Как защитить сайт от спама с помощью iptables
Недавно я окончательно разобрался с настройкой iptables и даже написал краткую инструкцию по настройке iptables для новичков. И вот сегодня оказалось, что из-за одного маленького упущенного нюанса вся система защиты не работала, однако, статус показывал, что все работает как надо. Хочу уберечь вас от этого досадного недоразумения.
Поиск по данной проблеме показал, что люди часто с этим сталкиваются, но отвечающие не всегда понимают суть проблемы.
Итак, сначала небольшая преамбула. Недавно ко мне обратился один знакомый гражданин и пожаловался, что его сайт по продаже автозапчастей облюбовали спамеры и повадились каждый день обсирать с ног до головы спамными комментариями. Каптча не спасала (спасибо индусам, которые предлагают сервис по ручному разгадыванию каптч по доступной даже для российских пенсионеров цене — 1 цент за 100 картинок). Встроенные средства CMS тоже не позволяли эффективно банить, так как:
- журналы доступа заточены под выявление активных пользователей и популярных источников переходов (referers), а гаденыши иногда даже не попадали в журнал вовсе;
- движок сайта устроен так, что для того, чтобы проверить IP-адрес на вхождение в shit-list, необходимо провести полную загрузку всех подсистем и установить соединение с базой данных (в которой shit-list, собственно и хранится). Очень глупое решение, так как даже пресеченные попытки оставить спамный комментарий все равно вызывают нагрузку на сервер и когда желающих испражниться рекламой становится слишком много, сайт начинает тормозить и для целевых посетителей.
Для решения проблемы мной был написан простенький скрипт, регулярно просматривающий /var/log/apache2/access.log. Особое внимание уделялось следующим посетителям:
- юзеры, пришедшие "из ниоткуда" сразу на форму отправки комментария (80% спамеров сразу отсеивается);
- юзеры, старательно долбящие несуществующие страницы;
- юзеры, перебирающие несуществующие страницы специфического свойства (/wp-admin.php, /administrator.php, /admin.php и т.д.).
Выловленные IP просеиваются через uniq и добавляются к правилам iptables. Стартовые правила таковы:
iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P INPUT DROP
То есть: разрешены входящие только на порт 80 (web-сервер), всё остальное режется. Разрешены любые исходящие. Далее выявленные нарушители добавляются по мере обнаружения следующей командой:
iptables -A INPUT -s адрес-спамера -j REJECT
Ну что, видите уже ошибку? ;)
Я периодически проверял как пополняется база IP-адресов спамеров и вносятся ли соответствующие изменения в iptables:
iptables -L -n
База росла как на дрожжах и состояла на 60% из китайцев, на 30% из украинцев, остальные страны делили оставшиеся 10%. Китайцев было решено банить целыми А-подсетками, за ненадобностью. С лицами украинской национальности было сложнее: во-первых, братский народ и банить невиновных было бы неправильно; во-вторых, что важнее, из этой группы возможны покупатели. Хозяин сайта, узнав о 30% с Украины заметно расстроился.
Но не будем отвлекаться. Гражданин был в восторге от моего элегантного решения и не сдерживал ни радости, ни щедрости (хотя последнего все же было заметно меньше, а хотелось бы наоборот).
Казалось бы, все прекрасно и ничто не предвещает беду... И вот через пару дней раздался звонок. Встревоженным голосом гражданин сообщил, что сайт-таки свалился, не выдержав веса обрушившегося на голову дерьма от спамеров.
Что такое?! Надо проводить расследование. Осмотр показал, что система работала как надо и список увеличился еще сильнее (несколько тысяч IP). Я заглянул в логи Апача и ахнул — лог чуть менее, чем полностью состоял из записей о спамерах. Как же так? Почему «iptables -L -n | grep адрес-спамера» показывает присутствие IP-адреса в говносписке, а лог продолжает пополнятся записями о посещении с этого хоста? Кажется, что-то пошло не так. Я зашел на сайт через прокси, сразу на страницу отправки комментария. Адрес добавился в базу, но блокировка не сработала. Почему?
Как оказалось, я не учел мааааааленькую деталь. Когда пакет проходит правило, разрешающее подключение к 80 порту...
iptables -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
... то пакет проходит и просмотр цепочек правил завершается, хотя, казалось бы, интуиция подсказывает, что если мы что-то чуть позже запрещаем, то иметь силу должно самое свежее решение, а не «старое».
Но не будем спорить с разработчиками iptables — им виднее. Смотрим как правильно в руководстве, оказывается вот так:
iptables -I INPUT -p tcp -m tcp --dport 22 -j ACCEPT
То есть, опция -A (append) добавляет новое правило, а опция -I (insert) вставляет новое правило. Чувствуете разницу? Вот в ней все и дело. Из-за этого «нюанса» моя система защиты любезно пропускала любого желающего. То есть, сначала фильтруем нарушителей, а уже потом все остальное.
Что же теперь делать со старыми и неработающими правилами? Конечно, можно их обнулить и начать накопление заново, но я решил не делать спамерам такой подарок. Сохраняем состояние iptables:
service iptables-persistent save
А потом прогоняем /etc/iptables/rules.v4 через sed, заменяя -A на -I. Далее восстанавливаем состояние из файла:
service iptables-persistent reload
Все, теперь торговля автозапчастями в безопасности!
iptables — это просто
Комментарии
Чингачгук
14 февраля, 2014 - 07:36
Рубрика «я познаю мир».
Чингачгук
7 мая, 2015 - 03:37
Очень полезно, продолжайте!
Чингачгук
10 июня, 2016 - 20:00
Что-то не почувствовал разницу между Insert и Append.
В случае с Append это "ИЛИ", а Insert это "И"? Или как?
pomodor
10 июня, 2016 - 20:16
Append добавляет правило в конец цепочки. Если перед ним есть другое разрешающее правило, то новое правило попросту не сработает.
Комментировать