Modsecurity和Apache:如何通过标头限制访问速率?

时间:2018-12-04 20:00:06

标签: apache security mod-security

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

我知道我可以读取以下标头文件:

SecRule REQUEST_HEADERS:User-Agent "@pmFromFile ratelimit-bots.txt"

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

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

1 个答案:

答案 0 :(得分:2)

经过2天的研究和了解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. 第一个规则将请求标头用户代理与“ facebookexternalhit”进行匹配。如果匹配成功,它将在 global 集合中创建 ratelimit_facebookexternalhit 属性,其初始值为 1 (它将在每个匹配用户代理)。然后,它将此var的到期时间设置为3秒。如果我们收到与“ facebookexternalhit”匹配的新匹配,则其总和为ratelimit_facebookexternalhit。如果3秒钟后我们没有收到匹配“ facebookexternalhit”的匹配,ratelimit_facebookexternalhit将消失,此过程将重新启动。
  2. 如果global.ratelimit_clients> 1(我们在3秒钟内收到2个或更多匹配)并且用户代理匹配“ facebookexternalhit”(此AND条件很重要,因为否则如果生成匹配项,所有请求将被拒绝),我们设置了RATELIMITED = 1,使用429 http错误停止操作,然后在Apache错误日志中记录一条自定义消息:“ RATELIMITED BOT”。
  3. 设置
  4. RATELIMITED = 1只是为了添加自定义标头“ Retry-After:3”。在这种情况下,此变量由Facebook的抓取工具(facebookexternalhit)解释,并将在指定的时间重试操作。
  5. 我们为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)。我们使用用户代理setuid:%{tx.ua_hash} tx.ua_hash /usr/share/modsecurity-crs/modsecurity_crs_10_setup.conf中的全局范围内)初始化USER集合。而且,我们只是使用 user 作为集合,而不是 global 。仅此而已!