使用 Cloudflare 时,NGINX 速率限制不起作用。我可以用一个简单的 `ab` 命令关闭我的网站

goo*_*ing 3 linux nginx cloudflare

我根据这篇博文实现了一个非常简单但超级有效的速率限制:https : //www.nginx.com/blog/rate-limiting-nginx/

基本上:

limit_req_zone $binary_remote_addr zone=ip:10m rate=10r/s;

limit_req zone=ip burst=20 nodelay;
Run Code Online (Sandbox Code Playgroud)

它工作得很好。但是,最近我尝试了 Cloudflare,但这不再保护我了。我可以用一个简单的命令自己关闭网站:

ab -k -c 1000 -n 10000 site.com/
Run Code Online (Sandbox Code Playgroud)

发生了什么?

use*_*461 10

ab -k -c 1000 -n 10000 site.com/ 并行运行 1000 个请求,直到总共完成 10000 个请求。

这太残忍了。很可能客户端和服务器都没有被调整为在几秒钟内处理数千个连接。

调整nginx配置,做一个温和的测试 ab -k -c 5 -n 500 site.com/

limit_req_zone $http_cf_connecting_ip zone=ip:10m rate=3r/s;
limit_req zone=ip;

limit_conn_status 429;
limit_req_status 429;
Run Code Online (Sandbox Code Playgroud)

429 请求过多

这将 nginx 配置为在由于速率限制而拒绝请求时返回标准状态代码429 Too Many Requests

nginx503默认返回一个错误(一个错误的默认值),这意味着应用程序失败了,但它并没有失败,它是有速率限制的。正确配置状态代码以区分服务器错误和速率限制非常重要。

Cloudflare 和客户端 IP

当在 cloudflare 后面时,nginx 不会看到客户端的 IP,而是看到 cloudflare 服务器的 IP。有人可能认为它打破了 IP 的速率限制,但实际上并没有。

使用 ab 进行本地测试时,您的测试计算机仅解析少数 cloudflare 服务器,并且ab可能仅使用第一个 IP。所以没有很多客户端 IP,速率限制应该可以正常工作。

在生产中,会有不同的客户端通过不同的 cloudflare 服务器访问。尽管如此,一个地理区域中的 cloudflare 服务器和客户端并不多,很可能会解析到相同的 cloudflare 服务器。所以会有一堆不同的 IP 在某种程度上打败了速率限制,但可能不会那么多。

> nslookup mycloudflaresite.com

Name:    mycloudflaresite.com
Addresses:  104.28.14.125
            104.28.15.125
            2606:4700:3037::681c:e7d
            2606:4700:3036::681c:f7d
Run Code Online (Sandbox Code Playgroud)

Cloudflare 将原始客户端 IP 放在CF-Connecting-IP标头中。它也可以在X-Forwarded-For标题中,X-Real-Ip或者True-Client-IP取决于设置和请求。请参阅https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-

因此,上述配置使用CF-Connecting-IP标头通过客户端 IP 进行速率限制。nginx 变量$binary_remote_addr将是 cloudflare 服务器 IP。

不要X-Forwarded-For用于速率限制

X-Forwarded-For首标可以由客户端来控制。它不应该用于速率限制,因为规避是微不足道的。

具有 IP 的客户端的示例100.11.22.33

  • 在没有X-Forwarded-For标头的请求上=> Cloudflare 设置X-Forwarded-For: 100.11.22.33CF-Connecting-IP: 100.11.22.33请求。
  • X-Forwarded-For: dummyvalue已设置标头的请求上=> CloudFlare 设置X-Forwarded-For: dummyvalue,100.11.22.33CF-Connecting-IP: 100.11.22.33请求。

如您所见,客户端为每个请求设置一个随机值并完全绕过基于X-Forwaded-For标头的任何速率限制是微不足道的。

  • 有没有办法添加一个变量,表示“如果通过 cloudflare 重定向,则使用该 ip”。否则使用binary_remote_addr`? (2认同)