Блокируем спам-ботов

Однажды на одном из сайтов обнаружилась вредоносная активность ботов. Группа организованых китайских виртуальных товарищей слала огромное количество POST /forum/index.php/trackback запросов, приводя сервер в крайнее замешательство и нежелание работать. Что было в теле запроса остаётся загадкой, но, думаю, это и не важно, т.к. активность ботов была похожа на простой ddos. Т.к. блокировать каждый новый ip — а в КНР их много — не предоставлялось возможным, подсетей также было много, а весь китайский сегмент забанить рука не подымалась, было придумано простенькое решение по автоматической блокировке при получении запроса на определённые URL. Ниже описано, как я это делал.

Итак, есть Debian 8 с Apache 2.4, задача состоит в автоматическом бане через iptables всех ip, ломящихся на /forum/index.php/trackback . Это возможно сделать, написав свой CGI-скрипт и прицепив его на нужый path, используя mod_cgi и mod_actions. Ещё потребуется сконфигурировать sudo, чтобы дать доступ к iptables пользователю, из которого запущен apache httpd. К слову, на сервере используется ISPManager, что привносит свою специфику в пути к файлам, но это решительным образом ни на что не влияет.

1. Настраиваем sudo

Создаём файл /etc/sudoers.d/iptables с таким содержимым:

Cmnd_Alias IPTABLES = /usr/bin/iptables *
www-data ALL=(ALL) NOPASSWD: IPTABLES

Здесь www-data — пользователь, из-под которого запущен демон apache (у меня он другой, кстати). И ещё, в дебиане iptables расположен в /sbin/iptables, в арче – /usr/bin/iptables, так что стоит проверить месторасположение через whereis iptables.
Выставляем права доступа readonly на файл:

chmod 0440 /etc/sudoers.d/iptables

2. Скрипт для блокировки IP

У меня он расположен по адресу /var/www/user/data/scripts/sectools-cgi/ban-ip.sh (из-за использования ISPManager)

#!/bin/sh

LOG_FILE=/var/www/user/data/logs/ban-ip.log

echo [$(date +'%d/%b/%Y:%H:%M:%S %z')] $REMOTE_ADDR $REQUEST_METHOD $PATH_TRANSLATED $QUERY_STRING >> $LOG_FILE 
echo "Content-type: text/plain"
echo ""
echo "Oops. You shouldn't enter $PATH_INFO. You ip is banned for security reasons."

if [ -n "$REMOTE_ADDR" ]; then
	sudo iptables -A INPUT -s $REMOTE_ADDR -j DROP
fi

Скрипт должен быть исполняемым,

chmod +x /var/www/user/data/scripts/sectools-cgi/ban-ip.sh

3. Настройка apache

Конфиг /etc/apache2/conf-available/ban-ip.conf

# ban IPs which make request to invalid paths
ScriptAlias "/sectools-cgi/" "/var/www/user/data/scripts/sectools-cgi/"
<Directory "/var/www/user/data/scripts/sectools-cgi">
    Options +ExecCGI
    SetHandler cgi-script
</Directory>

<LocationMatch "^/forum/index.php/trackback"> 
    SetHandler ban-ip
    Action ban-ip "/sectools-cgi/ban-ip.sh" virtual
</LocationMatch>

Включаем модули cgi и actions

a2enmod actions
a2enmod cgi

И включаем наш конфиг

a2enconf ban-ip

И перезагружаем апач.

Важное замечание: даже и не думайте проверять с локальной машины, работает ли оно :) Прокси/vpn/анонимайзер/удалённый сервер подойдут.