服务器是通过 CentOS 5.9 上的 cpanel 配置的标准 LAMP 堆栈。
我们的一个域中有一个文件,称为 bad.php,服务提供商每秒错误地访问该文件约 10 次。该文件不再存在,我们希望以最有效的方式阻止这些请求。目前,我们返回的是基本的 410 响应,但这仍然涉及绑定 Apache 线程、发送标头等。
理想情况下,我希望只是放弃请求,而不发送任何响应。按 IP 阻止不是一个选项,因为我们需要允许这些 IP 合法访问其他文件。(不,我们不能只是要求他们停止。)我们也没有外部防火墙可以使用(租用服务器,自定义外部防火墙需要额外付费)。
我的想法是,最好的选择是这样的 iptables 规则:
iptables -I INPUT -p tcp --dport 80 --destination [ip address] -m string \
--algo kmp --string "bad\.php" -j DROP
两个问题:
首先,我尝试了该规则(用域的 IP 地址代替 ip 地址),但没有效果。这是 iptables -L 显示的第一条规则,因此不应被较早的规则覆盖:
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP tcp -- anywhere [ip address] tcp dpt:http STRING match "bad\.php" ALGO name kmp TO 65535
我是不是搞错了什么地方?我对 iptables 一窍不通。
第二个问题是,这有什么注意事项吗?让 iptables 字符串匹配每个请求会产生很大的开销吗(与我们现在使用的 R=410 的 apache RewriteRule 相比)?我最好就这样忍受吗?或者有更好的选择吗?(也许是 mod_security?)服务器还没有到不堪重负的地步,所以这不是必需的,只是一种优化。
编辑回应 Saurabh Barjatiya:
当我请求 bad.php 文件时,我从 tcpdump 看到的所有内容如下:
20:21:09.740217 IP [clientIP].62790 > [serverIP].http: S 3454863895:3454863895(0) win 8192 <mss 1460,nop,wscale 2,nop,nop,sackOK>
20:21:09.740243 IP [serverIP].http > [clientIP].62790: S 4112555138:4112555138(0) ack 3454863896 win 5840 <mss 1460,nop,nop,sackOK,nop,wscale 7>
20:21:09.838595 IP [clientIP].62790 > [serverIP].http: . ack 1 win 16425
20:21:09.838606 IP [clientIP].62790 > [serverIP].http: . 1:1461(1460) ack 1 win 16425
20:21:09.838622 IP [serverIP].http > [clientIP].62790: . ack 1461 win 69
20:21:09.838632 IP [clientIP].62790 > [serverIP].http: P 1461:1476(15) ack 1 win 16425
20:21:09.838638 IP [serverIP].http > [clientIP].62790: . ack 1476 win 69
显然实际的 url 字符串不在这里。我的理解是 iptables能但是过滤了 url 字符串,所以大概我检查错了。
答案1
猜测是 iptables 规则将使用比 apache 配置更多的 CPU。但尽管如此,使用 iptables 来阻止传入请求还是很有趣的。由于请求未经过 gzip 压缩,并且它们通常位于一个数据包中,因此我认为您的逻辑没有任何问题。
为了理解为什么当前规则不起作用,我有两条建议:
- 删除 -d 一段时间,看看规则是否有效。你可能在解释目标 IP 时犯了一个愚蠢的错误
- 使用 tcpdump 或 wireshark 捕获数据包并分析它们,以查看在 bad.php 请求中可以匹配的字符串。这也有助于验证所有 bad.php 请求是否真的如预期那样包含 bad.php。有时本地重写规则可能会导致请求转到 bad.php,而数据包中的原始请求是 good.php,从而使 iptables 规则失败。