ВНИМАНИЕ: долго. Здесь много информации.
3 года назад кто-то спросил Почему iptables не блокирует IP-адрес? и оказалось, что причина в том, что серверы стояли за CloudFlare, что делало невозможным блокировать IP-адреса напрямую, как они хотели, если вы не используете его по-другому. Любой обратный прокси-сервер или балансировщик нагрузки вызовут то же самое.
Точно так же мы настроили fail2ban с правилом для запрета любых ботов, которые пытаются грубой силой проникнуть в административный логин или спамить xmlrpc. Сайт находится за балансировщиком нагрузки, поэтому, очевидно, мы не можем напрямую запретить IP-адрес, но предполагается, что iptables принимает соединение и шаблон, соответствующий пакетным данным, для запрета определенного трафика.
Это конфиг fail2ban jail.conf:
[wp-auth]
enabled = true
filter = wp-auth
action = iptables-proxy[name = lb, port = http, protocol = tcp]
sendmail-whois[name=LoginDetect, dest=ITemail@ourdomain.com, sender=acceptablebotbot@ourdomain.com, sendername="Fail2Ban"]
logpath = /obfuscated/path/to/site/transfer_log
bantime = 604800
maxretry = 4
findtime = 120
Это простое соответствие шаблону для запросов wp-login:
[Definition]
failregex = ^<HOST> .* "POST /wp-login.php
ignoreip = # our ip address
Это наше действие fail2ban iptables, которое должно блокировать этих ботов, но по большей части этого не делает. Это из раздела Советы сайта CentOS для fail2ban за прокси. Для краткости я оставил только комментарии в заголовке раздела.
# Fail2Ban configuration file
#
# Author: Centos.Tips
#
[INCLUDES]
before = iptables-blocktype.conf
[Definition]
# Option: actionstart
actionstart = iptables -N fail2ban-<name>
iptables -A fail2ban-<name> -j RETURN
iptables -I <chain> -p <protocol> --dport <port> -j fail2ban-<name>
# Option: actionstop
actionstop = iptables -D <chain> -p <protocol> --dport <port> -j fail2ban-<name>
iptables -F fail2ban-<name>
iptables -X fail2ban-<name>
# Option: actioncheck
actioncheck = iptables -n -L <chain> | grep -q 'fail2ban-<name>[ \t]'
# Option: actionban
actionban = iptables -I fail2ban-<name> 1 -p tcp --dport 80 -m string --algo bm --string 'X-Forwarded-For: <ip>' -j DROP
# Option: actionunban
actionunban = iptables -D fail2ban-<name> -p tcp --dport 80 -m string --algo bm --string 'X-Forwarded-For: <ip>' -j DROP
[Init]
# Default name of the chain
name = default
# Option: port
port = http
# Option: protocol
protocol = tcp
# Option: chain
chain = INPUT
Итак, как я уже упоминал, сайт находится на паре серверов за эластичным балансировщиком нагрузки и, похоже, работает при тестировании. Мы можем добавить любой из наших собственных IP-адресов, и мы не сможем получить доступ к сайту. Несмотря на это, боты, похоже, могут пройти.
[root:~/] iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N fail2ban-SSH
-N fail2ban-lb
-A INPUT -p tcp -m tcp --dport 80 -j fail2ban-lb
-A INPUT -p tcp -m tcp --dport 22 -j fail2ban-SSH
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 5666 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 24007:24020 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
-A fail2ban-SSH -j RETURN
-A fail2ban-lb -p tcp -m tcp --dport 80 -m string --string "X-Forwarded-For: 91.200.12.33" --algo bm --to 65535 -j DROP
-A fail2ban-lb -p tcp -m tcp --dport 80 -m string --string "X-Forwarded-For: 91.134.50.10" --algo bm --to 65535 -j DROP
-A fail2ban-lb -p tcp -m tcp --dport 80 -m string --string "X-Forwarded-For: 160.202.163.125" --algo bm --to 65535 -j DROP
-A fail2ban-lb -p tcp -m tcp --dport 80 -m string --string "X-Forwarded-For: 162.243.68.232" --algo bm --to 65535 -j DROP
-A fail2ban-lb -j RETURN
Порт 80 - единственный порт, открытый для всех. Все остальные находятся в ACL через группы безопасности AWS. Кажется, что IPtables обрабатываются в правильном порядке и поэтому должны блокировать эти IP-адреса на основе их заголовка X-Forwarded-For. Существует плагин Firefox, который позволяет вам отправлять эти заголовки с начальными запросами, и в результате мы также блокируемся с любым из этих IP-адресов ботов.
Похоже, что исходный IP-адрес не подделывает заголовок X-Forwarded-For, как мы играли, поскольку ELB все равно их перезаписывает. tcpdump не показывает никакой дополнительной информации о пакете на уровне сервера.
22:07:14.309998 IP ip-10-198-178-233.ec2.internal.11054 > ec2-10.4.8.71.http: Flags [P.], seq 2545:3054, ack 19506, win 166, options [nop,nop,TS val 592575835 ecr 2772410449], length 509
E..1..@.@..9
...
f.p+..P.Nz.
20............
#Q.[.?.QPOST /wp-login.php HTTP/1.1
host: www.thiswebsite.com
Accept: */*
Accept-Language: zh-cn
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded
Referer: http://www.thiswebsite.com/wp-login.php
User-Agent: Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; 125LA; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
X-Forwarded-For: 91.200.12.33
X-Forwarded-Port: 80
X-Forwarded-Proto: http
Content-Length: 21
Connection: keep-alive
Все эти запросы регистрируются в журнале transfer_log. Когда мы делаем то же самое и создаем X-Forwarded-For, iptables ловит нас еще до того, как достигнет Apache. tcpdump также показывает наши дополнительные IP-адреса.
20:10:25.378873 IP ip-10-198-178-233.ec2.internal.11054 > ec2-10.4.8.71.http: Flags [P.], seq 3157:3860, ack 124583, win 267, options [nop,nop,TS val 526293643 ecr 2507283790], length 703
E...Tf@.@.[.
...
f.p,O.P...GU........m.....
.^...r.QPOST /wp-login.php HTTP/1.1
host: www.thiswebsite.com
Accept: /
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.5
Cache-Control: no-cache
Cookie: __utma=190528439.16251225.1476378792.1478280188.1478289736.3; __utmz=190528439.1476378792.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _icl_current_language=en; __utmc=190528439; __utmb=190528439.2.10.1478289736; __utmt=1
Pragma: no-cache
Referer: http://www.thiswebsite.com/
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:49.0) Gecko/20100101 Firefox/49.0
X-Forwarded-For: 91.200.12.33, <our ip address>
X-Forwarded-Port: 80
X-Forwarded-Proto: http
Connection: keep-alive
У меня также есть журнал доступа ELB, для которого я ожидаю увидеть запись, а не журналы передачи Apache.
2016-11-07T22:07:14.309917Z mLB 91.200.12.33:60407 10.4.8.71:80 0.000079 1.99244 0.000091 200 200 21 3245 "POST http://www.thiswebsite.com:80/wp-login.php HTTP/1.1" "Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; 125LA; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)" - -
Таким образом, IP-адрес (по крайней мере, согласно ELB), похоже, не является принудительным на уровне X-Forwarded-For. Почему не блокируется трафик с него? IP-адрес также постоянно отображается в журнале fail2ban, как обычно:
fail2ban.actions[11535]: INFO [wp-auth] 91.200.12.33 already banned
Ваши правила iptables выглядят нормально. Однако нельзя точно сказать, что они проходят, без регистрации принятия. Tcpdump не сообщит вам об этом, потому что он запускается при входящем перед запуском iptables. Поскольку вам нужен балансировщик нагрузки, журналы iptables-accept для порта 80, скорее всего, будут создавать очень большие файлы, с которыми вам нужно будет аккуратно управлять (для использования на диске), и вам потребуются сценарии или другие инструменты для их анализа. Однако это то, что вам нужно сделать, чтобы узнать, что происходит.
Тем не менее, что я могу сказать вам из вышесказанного, так это то, что существует проблема с утечкой при использовании сопоставления строк сетевых пакетов для фильтрации на уровне приложений. Границы пакетов не соответствуют границам приложений, поэтому в среде с высокой степенью атак некоторые из этих запросов будут просачиваться. Это статистический эффект. Если в вашу систему направлено достаточно запросов, вероятность того, что некоторые из них будут разбиты на несколько пакетов, возрастает. Одно это может объяснить утечки. Хакеры могут изменить шансы в свою пользу, вставив заголовки, увеличивающие размер пакета. Но одного объема достаточно.
Для тщательной фильтрации нужно фильтровать на уровне приложения. Apache предоставляет для этого несколько механизмов. Вы можете заблокировать пользователей, идентифицированных с помощью fail2ban, с помощью правила .htaccess для X-Forwarded-For. Вы также можете фильтровать в своей директиве Location. Я не вижу возможности сделать это ни в fail2ban, ни в отдельной утилите, которая это делает, но пользовательский скрипт для синхронизации jail-e в fail2ban с фильтром apache был бы одним из способов реализации фильтра на уровне приложения.
Еще одно соображение: вы разместили правила для IPv4. Если вы принимаете соединения IPv6 через порт 80, вы должны убедиться, что эти правила также соблюдаются.
Похоже, что fail2ban на самом деле не устанавливает новые правила, как вы думаете. Когда вы видите сообщение «уже забанен», выполняете ли вы команду «iptables -L» и видите желаемое правило? Сообщение «уже заблокировано» означает, что ваше обнаружение работает, а ваш брандмауэр - нет. Если вы видите правило, но оно не работает, это означает, что что-то в правиле не работает, и вам нужно переосмыслить правило.
Ваш failregex и ignoreip говорят мне, что вы просто хотите заблокировать всех, кто не использует ваши IP-адреса. Это звучит намного проще, чем использование fail2ban.
На самом деле, нужен ли вашей консоли администратора балансировщик нагрузки? 99% трафика на этот сайт должны быть злоумышленниками, пытающимися взломать. Если вы знаете, какие адреса разрешить, а ваши failregex и ignoreip указывают, что вы это делаете, вы можете просто сделать консоль администратора доступной напрямую, но только для разрешенных IP-адресов.
Ой, это не через SSL, не так ли? Если это так, iptables не может прочитать заголовок X-Forwarded-For.
Мне очень нравится идея HBruijn об использовании API Cloudflares. Они должны блокировать, а не вы.
Наконец, если вы решите выполнить фильтрацию на уровне apache, mod_rewrite имеет переписывать карты которые отлично подходят для этого. Функции dbd и prg позволяют изменять сопоставление без перезапуска apache.
Надеюсь, что это поможет
-Дилан