我对此很感兴趣,因为它可以保护 Web 应用程序免受机器人攻击,但我猜它适用于机器人通过 IPv6 发起的所有类型的攻击。
在 Web 应用程序中,您需要保护某些页面免受机器人的攻击。
它可能是一个登录页面:您想避免数百万个尝试用户名/密码组合的请求。
这可能是一个注册页面。您不希望在您的网站上创建数千个机器人账户。
或者您可能不希望一次性下载数据库的全部内容。您认为匿名用户每天向您的数据库发出 100 或 200 个请求以获取一些信息是可以的,但您不能接受机器人以每分钟 1000 个请求的速度下载您提供的所有内容。
或者只是为了统计目的。您正在记录访客在网站上的活动,您不希望机器人完全歪曲您的数据,比如,人为地点击链接数千次,以便它链接到的文章成为您的新闻网站上的“最受欢迎的文章”。
我经常使用基于 IP 地址的限制/速率限制来处理这个问题,使用 Nginx 速率限制功能:
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/m;
server {
location /sensitiveUrl {
limit_req zone=mylimit;
proxy_pass http://my_upstream;
}
}
但对于 IPv6,我不确定这种方法有多有效。我的意思是,对于 IPv4,这种方法相对有效,因为攻击者创建和使用数千个 IP 地址的成本很高,但对于 IPv6,似乎任何人都可以创建数百万个 IP。如何处理这个问题?我应该对 IPv6 网络而不是地址应用限制吗?如果我这样做,在实践中效果如何?
答案1
IPv6 在寻址方面的灵活性非常好,但确实使这样的事情变得更加困难。我推荐一种算法:
- 首先阻止单独的 IPv6 地址 (a
/128
)。它可能是网络上的单个用户,该网络有多个用户,并且您要避免阻止无辜用户(由于 NAT,IPv4 中经常发生这种情况,我们不再赘述) x
如果同一个 中有超过块/64
,则假设整体/64
已被污染并阻止所有块。您现在可以/128
从黑名单中删除单个记录,因为它们现在已被 覆盖/64
。这可以防止黑名单系统溢出内存/存储。- 攻击者可能拥有不止一个
/64
。默认大小为/48
,但会出现/56
和 偶数/60
(对于 IPv6 来说太小了,但有些 ISP 永远不会知道)。我会按每 4 位进行扩展:如果/64
来自同一个 的多个/60
被阻止,则扩展以阻止整个/60
。对于/60
a 中的多个 等,情况相同/56
。 /64
我还建议对不同的前缀长度使用不同的黑名单超时时间。单个用户意外阻止某个用户比某人“意外”阻止整个用户更容易/48
。在我看来,较大的阻止时间应该在黑名单上保留更长时间。- 攻击者可能会滥用此算法,从一开始就将攻击扩展到整个系统
/48
,从而无法快速触发扩展算法。因此,您可能需要并行设置多个条件以快速扩展。
这种扩展机制的一个例子可能是:
+---------------+----------------------------------------+-----------+
| | Block when containing >= of these: | Blacklist |
| Prefix length | /128 | /64 | /60 | /56 | /52 | time |
+---------------+--------+-------+-------+-------+-------+-----------+
| /128 | N/A | N/A | N/A | N/A | N/A | 5 min |
| /64 | 5 | N/A | N/A | N/A | N/A | 15 min |
| /60 | 15 | 2 | N/A | N/A | N/A | 30 min |
| /56 | 50 | 4 | 2 | N/A | N/A | 60 min |
| /52 | 75 | 8 | 4 | 2 | N/A | 120 min |
| /48 | 100 | 16 | 8 | 4 | 2 | 240 min |
+---------------+--------+-------+-------+-------+-------+-----------+
答案2
你可以做一些非常原始的事情通过正则表达式进行 IP 子网划分。在这里,我传递 IPv4 地址,不做任何更改,但抓取 IPv6 地址的前半部分,这对应于地址的 /64 前缀。因此,nginx 将同时跟踪整个 /64 的速率限制。
map $binary_remote_addr $masked_ip_addr {
# Extract the first half (the /64 prefix) of an ipv6 address
"~^(?P<a>........)........$" "$a";
# Extract the entire ipv4 address
"~^(?P<a>....)$" "$a";
}
limit_req_zone $masked_ip_addr zone=myzone:10m rate=1r/s;
server {
limit_req zone=myzone;
}