nataraj: (Бритый небритый)
[personal profile] nataraj
У меня есть wiki на не самом плохом, с точки зрения SEOшников домене. И в какой-то момент туда полез спам. Крайне активно. При этом начало этого процесса я проворонил, и уж не знаю обмениваются ли спамеры между собой базами, или каждый нарывает свою, но попал я во многие базы, это точно.
С этим надо было что-то делать. И вот что я сделал

1. Знать что происходит. В LocalSettings.php добавляем настройку, которая будет оповещать Вас о любом изменении сделанном в вики:
$wgUsersNotifiedOnAllChanges = array( 'Nataraj' );

Nataraj -- в данном случае имя пользователя, на чей адрес приходят оповещения. More Info

2 Знать откуда происходит. Если ваша вики стоит за проксирующим фронтендом, не плохо бы сделать так, чтобы в веб-логи и в базу MediaWiki попадали реальные IP адреса запросов, а не адрес фронтенда. Для этого в конфиге nginx'а добавляем
        set_real_ip_from   111.222.33.44;
        real_ip_header  X-Forwarded-For;

где 111.222.33.44 -- адрес вашего фронтенда. Тогда в логи будут попадать IP адреса из заголовка X-Forwarded-For More Info

и в LocalSettings.php добавляем
$wgUsePrivateIPs = true;
$wgSquidServersNoPurge =  array( '111.222.33.44' );

И тогда сама MediaWiki для запросов пришедших с 111.222.33.44 будет запоминать не этот адрес, а адрес из X-Forwarded-For. More info

3. Капча на все случаи жизни. В любом случае на сайте следует поставить каптчу. Я предпочитаю FancyCaptcha, поскольку она адекватно работает в случае включенного JavaScript'а. Она входит в дистрибутив, ее надо только включить, и сгенерить ей картинки, так как это рекомендовано в руководстве.

3.1. Если у вас мало изменяемая вики, или вики которую с среднем правят узкая группа людей, то каптчу следует поставить на все изменения, которые происходят, добавив всех кого надо в список привелегированных пользователей.
$wgCaptchaTriggers['edit']          = true; 
$wgCaptchaTriggers['create']        = true;

3.2. Вы наверное могли заметить, что на в мануале FancyCaptcha относится к числу не рекомендованных. И правда, если сгенерировать каптчи ровно по инструкции, то получатся картинки "как у всех", которые спамеры хорошо научились распознавать... Поэтому рекомендую простыми методами сделать не как у всех. Используя либо ImageMagic, либо пакетную обработку фотошопа, докорёжте картинки так, чтобы сделать ее неподходящей для робота распознавателя, настроенного на картинки "как у всех". Как именно это сделать -- советовать не буду, каждый должен избрать свой путь. Иначе мы получим новую "как у всех"

4. Черный Список. Есть замечательный ресурс http://www.stopforumspam.com, собирающий данные о спамерской активности на форумах и сайтах. Они ежечасно обновляют список опасных IP адресов, и для этих адресов можно либо закрыть доступ, либо сделать для них специальную Read Only версию сайта, чтобы живые пользователи не страдали если что. На сайте MediaWiki предлагается вот такое-вот php-only решение Я его пробовал применить на практике, но при нынешних объемах черного списка и объеме идущего спама, оно безбожно ело процессор. Поэтому я решил перевести процесс блокировки на уровень веб сервера. Перевод делается в несколько шагов.

4.1. Изготовление read-only копии сайта. Следующий скрипт делает при помощи символических ссылок полную копию сайта, за исключением файла конфигурации LocalSettings.php, сам файл конфигурации копируется штатными средствами, и в него добавляются настройки выключающие возможность редактирования
#!/usr/bin/perl

use strict;
use File::Path qw(remove_tree);


my $orig_path = '/var/www/';
my $ro_path = $orig_path."-ro";

my $ro_hostname_prefix = "ro.";

remove_tree($ro_path);
mkdir ($ro_path);


opendir(my $dh, $orig_path);

my $file;
while ($file= readdir $dh)
{
  if (! ($file ~~ ['.','..','LocalSettings.php']))
  {
    print $file,"\n";
    `ln -s "$orig_path/$file" "$ro_path/$file"`;
  }
}
closedir($dh);

open F, "$orig_path/LocalSettings.php";
open F2, ">", "$ro_path/LocalSettings.php";

while (my $s = )
{
  $s=~s{(\$wgSitename\s*=\s*".*)(";)}     {$1 - Read only version for known SPAM bots$2};
  $s=~s{(\$wgServer\s*=\s*"http://)(?:www\.)?(.*";)}{$1$ro_hostname_prefix$2};
  print F2 $s;
}
print F2 "\n\$wgReadOnly = 'SPAM alert. Your IP is tainted';\n";

close F;
close F2;

В хостнейме для r/o копии www. заменяется на ro. или в случае если www. не было ro. просто добавляется. Это знание понадобится потом, когда будем писать новый nginx конфиг.

4.2. Создаем список запрещенных IP адресов в nginx. Для того чтобы в конфиге разнести отдачу для белого и для черного списка, мы воспользуемся модулем geo. И для этого нужно сконвертировать csv который дает нам stopforumspam в geo'вский список IP'шников.

Для этого я написал следующий скрипт:
#!/usr/bin/perl

use strict;

# http://www.mediawiki.org/wiki/Manual:Combating_spam#IP_address_blacklists

my $cache_dir = '/var/cache';
my $config_file =  '/etc/nginx/sites-enabled/bad_ip_list.conf';

my $log = "";

if ('daily' ~~ \@ARGV || ! -e "$cache_dir/bannedips.zip")
{
#  print "Ежедневный запуск\n";
  $log.=`rm -f $cache_dir/bannedips.zip`;
  $log.=`cd $cache_dir ; wget http://www.stopforumspam.com/downloads/bannedips.zip 2>&1`;
  my_die("bannedips.zip failed to download") unless -e "$cache_dir/bannedips.zip";
  $log.=`rm -f $cache_dir/bannedips.csv`;
  $log.=`cd $cache_dir ; unzip bannedips.zip`;
}

if (! ('daily' ~~ \@ARGV) || ! -e "$cache_dir/listed_ip_1.zip")
{
#  print "Ежечасный запуск\n";
  $log.=`rm -f $cache_dir/listed_ip_1.zip`;
  $log.=`cd $cache_dir ; wget http://www.stopforumspam.com/downloads/listed_ip_1.zip 2>&1`;
  my_die("listed_ip_1.zip failed to download") unless -e "$cache_dir/listed_ip_1.zip";
  $log.=`rm -f $cache_dir/listed_ip_1.txt`;
  $log.=`cd $cache_dir ; unzip listed_ip_1.zip`;
}


open F2 ,">", "$config_file.new" or die;

print F2 "geo \$bad_ip {\n";
print F2 "    default 0;\n";


my %known_addresses = ();
open F, "$cache_dir/listed_ip_1.txt" or die;
  while (my $ip =  )
  {
    $ip =~ s/\n\z// or die;
    my_die("$ip is not IP address") unless is_ip($ip);
    print F2 "    $ip 1;\n";
    $known_addresses{$ip} = 1;
  }


close F;
open F, "$cache_dir/bannedips.csv" or die "Error opening 'bannedips.csv': \$!";
{
  local $/ = ',';
  while (my $ip =  )
  {
    $ip =~ s/\,\z// or die;
    my_die("$ip is not IP address") unless is_ip($ip);
    print F2 "    $ip 1;\n" unless $known_addresses{$ip};
  }
}
close F;

print F2 "}\n";
close F2;

`mv  $config_file $config_file.old`;
`mv $config_file.new $config_file`;
`rm $config_file.old`;

sub is_ip
{
  my $ip = shift;
  $ip =~ /^(\d)+\.(\d+)\.(\d+)\.(\d+)\z/ or return 0;
  return 0 if $1<0 || $1>255;
  return 0 if $2<0 || $2>255;
  return 0 if $3<0 || $3>255;
  return 0 if $4<0 || $4>255;
  return 1;
}

sub my_die
{
  print $log;
  die @_;
}

И добавляем запуск этого скрипта в /etc/rc.local
/usr/local/bin/nginx-watchdog.pl &

4.5. Тестируем Проверяем, все запуская все скрипты руками, а так же руками вписываем свой текущий IP'шник в /etc/nginx/sites-enabled/bad_ip_list.conf перезапускаем сервер и убеждаемся что теперь нас не пускают редактировать собственное wiki. Bingo! Еще полезно вписать MAILTO=my-email@example.com в /etc/crontab и получать письма, если что-то в работе скриптов пошло не так.

5. Если вы дочитали до этого места и вам понравилось... 41001103370866 - яндекс деньги
5.1. Вопросы, комментарии и критика -- принимаются...

См. также часть 2.
This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

Profile

nataraj: (Default)
Swami Dhyan Nataraj

July 2024

S M T W T F S
 123456
789 10111213
14151617181920
21222324252627
28293031   

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Mar. 12th, 2026 06:14 am
Powered by Dreamwidth Studios