apache - Modsecurity & Apache : How to limit access rate by header?

标签 apache security mod-security

我让 Apache 和 Modsecurity 一起工作。我试图通过请求的 header (如“facebookexternalhit”)来限制命中率。然后返回友好的“429 Too Many Requests”和“Retry-After: 3”。

我知道我可以读取一个标题文件,例如:

SecRule REQUEST_HEADERS:用户代理“@pmFromFileratelimit-bots.txt”

但是我在构建规则时遇到了麻烦。

任何帮助将不胜感激。谢谢。

最佳答案

经过两天的研究和理解 Modsecurity 的工作原理,我终于做到了。仅供引用,我正在使用 Apache 2.4.37 和 Modsecurity 2.9.2 这就是我所做的:

在我的自定义文件规则:/etc/modsecurity/modsecurity_custom.conf中,我添加了以下规则:

# Limit client hits by user agent
SecRule REQUEST_HEADERS:User-Agent "@pm facebookexternalhit" \
    "id:400009,phase:2,nolog,pass,setvar:global.ratelimit_facebookexternalhit=+1,expirevar:global.ratelimit_facebookexternalhit=3"
SecRule GLOBAL:RATELIMIT_FACEBOOKEXTERNALHIT "@gt 1" \
    "chain,id:4000010,phase:2,pause:300,deny,status:429,setenv:RATELIMITED,log,msg:'RATELIMITED BOT'"
    SecRule REQUEST_HEADERS:User-Agent "@pm facebookexternalhit"
Header always set Retry-After "3" env=RATELIMITED
ErrorDocument 429 "Too Many Requests"

说明:

注意:我希望每 3 秒限制 1 个请求。

  1. 第一条规则将请求 header 用户代理与“facebookexternalhit”进行匹配。如果匹配成功,它会在 global 集合中创建 ratelimit_facebookexternalhit 属性,初始值为 1(每次匹配都会增加该值)点击匹配用户代理)。然后,它设置这个var的过期时间为3秒。如果我们收到与“facebookexternalhit”匹配的新点击,则ratelimit_facebookexternalhit 的总和将为1。如果 3 秒后我们没有收到与“facebookexternalhit”匹配的点击,ratelimit_facebookexternalhit 将消失,并且此过程将重新启动。
  2. 如果 global.ratelimit_clients > 1(我们在 3 秒内收到 2 次或更多点击)并且用户代理匹配“facebookexternalhit”(此 AND 条件很重要,因为否则如果产生匹配,所有请求都将被拒绝),我们设置 RATELIMITED =1,通过 429 http 错误停止操作,并在 Apache 错误日志中记录一条自定义消息:“RATELIMITED BOT”。
  3. 设置 RATELIMITED=1 只是为了添加自定义 header “Retry-After: 3”。在这种情况下,该变量由 Facebook 的爬虫 (facebookexternalhit) 解释,并将在指定时间重试操作。
  4. 我们为 429 错误映射自定义返回消息(如果需要)。

您可以通过添加 @pmf 和 .data 文件来改进此规则,然后初始化全局集合,例如 initcol:global=%{MATCHED_VAR},这样您就不会仅限于单个匹配规则。我没有测试最后一步(这是我现在需要的)。如果有的话,我会更新我的答案。

更新:

我已经调整了规则,以便能够拥有一个包含我想要限制速率的所有用户代理的文件,因此单个规则可以在多个机器人/爬虫之间使用:

# Limit client hits by user agent
SecRule REQUEST_HEADERS:User-Agent "@pmf data/ratelimit-clients.data" \
    "id:100008,phase:2,nolog,pass,setuid:%{tx.ua_hash},setvar:user.ratelimit_client=+1,expirevar:user.ratelimit_client=3"

SecRule USER:RATELIMIT_CLIENT "@gt 1" \
    "chain,id:1000009,phase:2,deny,status:429,setenv:RATELIMITED,log,msg:'RATELIMITED BOT'"                                                                                     
    SecRule REQUEST_HEADERS:User-Agent "@pmf data/ratelimit-clients.data"

Header always set Retry-After "3" env=RATELIMITED

ErrorDocument 429 "Too Many Requests"

因此,带有用户代理的文件(每行一个)位于此规则同一目录下的子目录中:/etc/modsecurity/data/ratelimit-clients.data。然后我们使用 @pmf 读取并解析文件( https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)#pmfromfile )。我们使用用户代理初始化 USER 集合:setuid:%{tx.ua_hash}(tx.ua_hash 位于 /usr/share/中的全局范围内) modsecurity-crs/modsecurity_crs_10_setup.conf)。我们只是使用user作为集合,而不是global。仅此而已!

关于apache - Modsecurity & Apache : How to limit access rate by header?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53620557/

相关文章:

https - HSTS 与仅使用安全 cookie 的 https

安全远程服务器上的 php LDAP 绑定(bind) Windows 失败

asp.net - 如何防止 SignalR 引起的 Modsecurity 误报?

php - gzip、md5-call-cachefiles-in-server、无限缓存控制后,加载我的网站仍然很慢,需要缓存方面的帮助

php - 知道 HTTP 状态代码是来自 apache 还是 PHP 的任何方法

php - 在第 3 方托管的 MySQL 服务器中存储加密 secret 数据的最佳做法是什么?

apache - mod_安全 : A rule to allow POST requests without a request body

linux - 当外部客户端尝试在我的服务器上运行 PHP 脚本时,我该怎么办?

PHP正在上传没有读取权限的文件

php - Yii2 自定义 url 管理。出现 400 错误