为什么 iptables 不阻止 IP 地址?(LB/代理版本)

dcm*_*own 5 iptables fail2ban apache-2.2 amazon-elb

警告:长。这里有很多信息。

3年前有人问为什么iptables不屏蔽IP地址?事实证明,原因是因为服务器位于 CloudFlare 后面,这使得无法按照他们想要的方式直接阻止 IP 地址,除非您以不同的方式使用它。任何反向代理或负载均衡器都会导致同样的事情。

同样,我们设置了fail2ban,其规则是禁止任何试图强行进入管理登录或垃圾邮件xmlrpc的机器人。该站点位于负载均衡器后面,因此显然我们不能直接禁止 IP 地址,但 iptables 应该接受连接和匹配数据包数据的模式以禁止特定流量。

这是fail2ban jam.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
Run Code Online (Sandbox Code Playgroud)

这是 wp-login 请求的简单模式匹配:

[Definition]
failregex = ^<HOST> .* "POST /wp-login.php
ignoreip = # our ip address
Run Code Online (Sandbox Code Playgroud)

这是我们的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    
Run Code Online (Sandbox Code Playgroud)

正如我所提到的,该站点位于弹性负载均衡器后面的一对服务器上,并且似乎在测试中正常工作。我们可以添加任何我们自己的 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
Run Code Online (Sandbox Code Playgroud)

80端口是唯一对所有人开放的端口。所有其他内容均通过 AWS 安全组进行 ACL。IPtables 似乎正在按正确的顺序进行处理,因此应该根据其 X-Forwarded-For 标头来阻止这些 IP。有一个 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
Run Code Online (Sandbox Code Playgroud)

这些请求都记录在transfer_log 中。当我们做同样的事情并伪造 X-Forwarded-For 时,我们在到达 Apache 之前就被 iptables 捕获了。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
Run Code Online (Sandbox Code Playgroud)

我这里还有 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)" - -
Run Code Online (Sandbox Code Playgroud)

因此,IP 地址(至少根据 ELB)似乎在 X-Forwarded-For 级别上没有被强制。为什么来自它的流量没有被阻止?IP 地址也经常显示在fail2ban 日志中,通常为:

fail2ban.actions[11535]: INFO [wp-auth] 91.200.12.33 already banned
Run Code Online (Sandbox Code Playgroud)

Dio*_*ght 2

你的 iptables 规则看起来不错。然而,如果没有记录接受,人们就无法确定他们正在传递什么。Tcpdump 不会告诉您这一点,因为它在 iptables 运行之前在传入上运行。由于您需要负载均衡器,端口 80 的 iptables-accept 日志可能会生成非常大的文件,您需要仔细管理这些文件(用于磁盘使用),并且需要脚本或其他工具来分析它们。然而,这就是您需要做的事情,以了解发生了什么。

不过,从上面我可以告诉您的是,使用网络数据包字符串匹配进行应用程序级过滤存在固有的泄漏问题。数据包边界不尊重应用程序边界,因此在高攻击环境中,其中一些请求会泄漏。这是统计效应。如果有足够多的请求发送到您的系统,其中一些请求被分成多个数据包的可能性就会增加。仅此一点就可以解释泄漏的原因。黑客可以通过插入增加数据包大小的标头来增加对自己有利的可能性。但光有数量就足够了。

为了彻底过滤,您需要在应用程序级别进行过滤。Apache 为此提供了多种机制。您可以使用 X-Forwarded-For 的 .htaccess 规则阻止由 failed2ban 标识的用户。您还可以在 Location 指令中进行过滤。我没有看到在fail2ban 中执行此操作的选项,也没有看到执行此操作的独立实用程序,但将fail2ban sail-ees 与apache 过滤器同步的自定义脚本将是实现应用程序级过滤器的一种方法。

另一项考虑因素:您发布了 IPv4 规则。如果您在端口 80 上接受 IPv6 连接,您需要确保这些规则也得到维护。