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.

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. 11th, 2026 07:11 pm
Powered by Dreamwidth Studios