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

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

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

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, [email protected], [email protected], 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 是唯一向所有人开放的端口。所有其他端口均通过 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..@[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

这些请求都记录在 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

我这里还有 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

答案1

您的 iptables 规则看起来不错。但是,如果不记录接受,就无法确定它们传递了什么。Tcpdump 不会告诉您这一点,因为它在 iptables 运行之前对传入进行操作。由于您需要负载平衡器,端口 80 的 iptables-accept 日志可能会产生非常大的文件,您需要小心管理这些文件(用于磁盘使用),并且您需要脚本或其他工具来分析它们。但是,这就是您需要做的,以找出传递的内容。

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

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

还有一点需要考虑:您发布了 IPv4 规则。如果您在端口 80 上接受 IPv6 连接,则需要确保也遵守这些规则。

答案2

听起来 fail2ban 实际上并没有像您认为的那样制定新规则。当您看到“已禁止”消息时,您是否执行了“iptables -L”并看到了所需的规则?“已禁止”消息表示您的检测正在运行,但防火墙没有运行。如果您看到了规则,但它没有运行,则意味着规则的某些方面不起作用,您需要重新考虑规则。

您的 failregex 和 ignoreip 告诉我您只想阻止所有不属于您的 IP 地址的用户。这听起来比使用 fail2ban 简单得多。

实际上,您的管理控制台是否真的需要负载均衡器?99% 的流量肯定是恶意入侵。如果您知道允许哪些地址,并且您的 failregex 和 ignoreip 表明您知道,那么您可以直接让管理控制台可访问,但仅限于允许的 IP。

哦,嘿,这不是通过 SSL 吗?如果是,iptables 就无法读取 X-Forwarded-For 标头。

我真的很喜欢 HBruijn 关于使用 cloudflares API 的想法。他们应该进行阻止,而不是你。

最后,如果你决定在 apache 级别进行过滤,mod_rewrite 有重写地图这非常适合这种情况。dbd 和 prg 功能使您无需重新启动 apache 即可更改映射。

希望这些能有所帮助

-迪伦

相关内容