使用 Fail2ban 阻止恶意机器人

Fail2ban 是一个多功能的安全工具。 虽然它主要用于防止对 SSH 的暴力攻击,但它也可以用于保护其他服务。

有一些机器人会四处扫描互联网并向 Web 服务器发送数千个请求,以期找到漏洞。 这篇文章讨论了如何使用 Fail2ban 阻止此类机器人。

我们假设您正在使用 Apache 作为网络服务器。 但是,这些说明可以很容易地针对 nginx 或任何其他 Web 服务器进行调整。

但是,您应该记住,Fail2ban 不是 Web 应用程序防火墙 (WAF),并且无法抵御传入的恶意请求。 这是因为fail2ban 通过监控日志来采取行动; 因此,在 Fail2ban 采取行动之前,必须至少记录一次恶意尝试。

什么是坏机器人?

在这篇文章中,我们将专注于阻止执行以下操作之一的机器人:

  • 扫描网站以查找开放代理
  • 发送包含参数的 GET 请求 SQL注入 有效载荷
  • 发送包含参数的 GET 请求 贝壳冲击 有效载荷

当然,您也可以阻止其他类型的攻击。 但是,我们将在本文中仅限于上述三种情况。

安装 Fail2ban

Fail2ban 在大多数发行版的存储库中可用。

要在 Debian/Ubuntu 上安装它,请运行以下命令:

sudo apt-get update sudo apt-get install fail2ban

在 CentOS 上,您应该首先启用 EPEL 存储库; 然后,您应该启用并启动它。

sudo yum -y install epel-release sudo yum -y install fail2ban sudo systemctl enable fail2ban sudo systemctl start fail2ban

Fail2ban 基础知识

Fail2ban 工作机制的核心是一组监狱。 简而言之,jail 告诉Fail2ban 查看一组日志,并在每次日志更改时对其应用过滤器。 如果过滤器的匹配数等于jail 允许的最大匹配数,则执行jail 中指定的操作。

因此,您需要定义两件事:过滤器和监狱。 将监狱配置为查看 Apache的日志来检测恶意请求。

定义过滤器

过滤器只是与日志匹配的 Python 正则表达式的集合。 在这里,我们需要为我们上面描述的标准定义过滤器。

但首先,让我们看一下 Apache 日志:

66.249.79.189 - - [17/Jan/2017:14:10:41 +0000] "GET /robots.txt HTTP/1.1" 200 3494 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http: //www.google.com/bot.html)"

注意请求头 GET /robots.txt HTTP/1.1 用双引号括起来。 在自己设计此类规则时,您应该足够小心以确保只有请求标头匹配。 否则,您可能会阻止合法用户。

SQL 注入负载通常包含以下形式的字符串 union select(...) 或者 select concat (...). 因此,您可以尝试将此模式与以下正则表达式匹配:

(?i)^<HOST> -.*"[^"]+(?:union[^"]+select[^"]*|select[^"]+concat[^"]*)(?:%%2[8C]|[,(])

<HOST> 部分定义了 IP 地址在日志条目中的位置,以及 (?i) 声明正则表达式不区分大小写。

[^"] 在正则表达式中确保匹配的文本用双引号括起来。 这有助于确保正则表达式只匹配请求标头而不匹配其他任何东西。 这 (?:%%2[8C]|[,(]) 指定 union select 或者 select concat 匹配后跟一个逗号(,) 或括号 ((),直接或在他们的 百分比编码形式.

扫描开放代理的机器人通常会发送以下形式的请求:

101.33.59.9 - - [17/Jan/2017:14:10:41 +0000] "GET https://google.com/ HTTP/1.1" 400 3494 "-" "Mozilla" 101.33.59.9 - - [17/Jan/2017:14:10:44 +0000] "CONNECT yahoo.com:80" 400 3499 "-" "Mozilla"

像下面这样的正则表达式可以很容易地匹配这些:

(?i)^<HOST> -.*"(?:(?:GET|POST|HEAD) https?:|CONNECT [a-z0-9.-]+:[0-9]+)

正则表达式 (?:(?:GET|POST|HEAD) https?: 匹配第一种类型的请求,而正则表达式 CONNECT [a-z0-9.-]+:[0-9]+ 匹配第二种类型的请求。

扫描 Shellshock 的机器人通常会发出如下请求:

10.11.12.13 - - [17/Jan/2016:16:00:00 +0000] "GET /cgi-bin/printenv.cgi HTTP/1.0" 200 1 "-" "() { test;};echo "Content-type: text/plain"; echo; echo; /bin/rm -rf /var/www/"

像这样的正则表达式将匹配 Shellshock 的模式:

<HOST> -.*"()s*{[^;"]+[^}"]+}s*;

在这里,我们正在检查 () { <command>; } 模式,以及 s 考虑可能存在于恶意请求中的空格。

结合它们,我们现在可以编写我们的过滤器:

[Definition]  failregex = <HOST> -.*"()s*{[^;"]+[^}"]+}s*;             (?i)^<HOST> -.*"[^"]+(?:union[^"]+select[^"]*|select[^"]+concat[^"]*)(?:%%2[8C]|[,(])             (?i)^<HOST> -.*"(?:(?:GET|POST|HEAD) https?:|CONNECT [a-z0-9.-]+:[0-9]+)  ignoreregex =

ignoreregex 允许您将条目列入白名单。 您可以添加忽略的正则表达式,就像对 failregex 所做的那样。

Save 上面的过滤器变成 /etc/fail2ban/filter.d/badbot.local

定义监狱

定义了过滤器后,现在是定义监狱的时候了。 在这里,如果 IP 地址在六分钟内发送三个此类请求,我们将阻止该 IP 地址六分钟。

将此添加到您的 /etc/fail2ban/jail.local 文件:

[badbot]  enabled   = true port      = http,https filter    = badbot logpath   = /var/log/apache*/*access.log maxretry  = 3 banaction = iptables-multiport findtime  = 360 bantime   = 360

配置jail 后,您应该重新启动fail2ban 以使这些更改生效。 根据您的发行版,需要以下命令之一来重新启动它:

sudo systemctl restart fail2ban sudo service fail2ban restart

fail2ban 现在将阻止恶意机器人尝试攻击您的 Web 服务器的所有尝试。 您还可以将这些规则扩展到您的另一台 Web 服务器,或您可能会看到的其他类型的攻击。