AVISO: Longo. Muita informação aqui.
Há 3 anos alguém perguntou Por que o iptables não está bloqueando um endereço IP? ? e descobriu-se que o motivo era porque os servidores estavam por trás do CloudFlare, o que tornava impossível bloquear os endereços IP diretamente do jeito que eles queriam, a menos que você o usasse de maneira diferente. Qualquer proxy reverso ou balanceador de carga causaria a mesma coisa.
Da mesma forma, configuramos o fail2ban com uma regra para proibir qualquer bots que tente forçar sua entrada no login administrativo ou no spam xmlrpc. O site está sentado atrás de um balanceador de carga, então obviamente não podemos proibir diretamente o endereço IP, mas o iptables deve estar aceitando a conexão e o padrão que combinam os dados do pacote para banir o tráfego específico.
Esta é a configuração fail2ban jail.conf:
[wp-auth]
enabled = true
filter = wp-auth
action = iptables-proxy[name = lb, port = http, protocol = tcp]
sendmail-whois[name=LoginDetect, [email protected], [email protected], sendername="Fail2Ban"]
logpath = /obfuscated/path/to/site/transfer_log
bantime = 604800
maxretry = 4
findtime = 120
Esta é simplesmente a correspondência de padrões para solicitações wp-login:
[Definition]
failregex = ^<HOST> .* "POST /wp-login.php
ignoreip = # our ip address
Esta é a nossa ação fail2ban iptables que deveria ser capaz de bloquear esses bots, mas a maior parte não parece. É da seção Dicas do site CentOS para fail2ban atrás de um proxy . Por razões de brevidade, deixei apenas os comentários do cabeçalho da seção no lugar.
# 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
Então, como mencionei, o site está em um par de servidores por trás de um balanceador de carga elástico e parece funcionar no teste. Podemos adicionar qualquer um dos nossos endereços IP e não podemos acessar o site. Apesar disso, os bots parecem conseguir passar.
[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
A porta 80 é a única porta aberta a todos. Todos os outros são ACL com os grupos de segurança da AWS. IPtables parece estar processando na ordem correta e, portanto, deve estar bloqueando esses IPs com base em seu cabeçalho X-Forwarded-For. Existe um plug-in do Firefox que permite enviar esses cabeçalhos com solicitações iniciais e, como resultado, também é bloqueado com qualquer um desses IPs de bots.
O endereço IP de origem não parece estar forjando o cabeçalho X-Forwarded-For com o qual estamos jogando, já que o ELB os reescreve de qualquer maneira. O tcpdump não mostra nenhuma informação extra no pacote no nível do servidor.
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..@[email protected]
...
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
Essas solicitações estão sendo registradas no transfer_log.
Quando fazemos a mesma coisa e forjamos o X-Forwarded-For, somos pegos pelo iptables antes mesmo de chegar ao Apache. O tcpdump também mostra nossos IPs extras.
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
Eu também tenho o log de acesso do ELB aqui que espero ver uma entrada, mas não os logs de transferência do 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)" - -
Portanto, o endereço IP (pelo menos de acordo com o ELB) não parece ser forçado no nível X-Forwarded-For. Por que o tráfego não está bloqueado? O endereço IP também aparece constantemente no log do fail2ban com o usual:
fail2ban.actions[11535]: INFO [wp-auth] 91.200.12.33 already banned