简体   繁体   English

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

[英]NGINX rate limiting doesn't work when using Cloudflare. I can bring down my site with a simple `ab` command

I implemented a pretty simple but super effective rate limiting based on this blog post: https://www.nginx.com/blog/rate-limiting-nginx/我根据这篇博文实现了一个非常简单但超级有效的速率限制: https://www.nginx.com/blog/rate-limiting-nginx/

Basically:基本上:

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

limit_req zone=ip burst=20 nodelay;

It works great.它工作得很好。 However, recently I tried Cloudflare, and this doesn't protect me anymore.但是,最近我尝试了 Cloudflare,这不再保护我了。 I can bring down the site myself with a simple command of:我可以通过以下简单命令自行关闭网站:

ab -k -c 1000 -n 10000 site.com/

What's happening?发生了什么?

ab -k -c 1000 -n 10000 site.com/ is running 1000 requests in parallel, until a total of 10 000 requests total have been done. ab -k -c 1000 -n 10000 site.com/正在并行运行 1000 个请求,直到总共完成 10 000 个请求。

That's too brutal.这太残忍了。 It's likely that neither the client nor the server are tuned to handle thousands of connections over a few seconds.很可能客户端和服务器都没有经过调整以在几秒钟内处理数千个连接。

Adjust the nginx configuration and do a gentle test ab -k -c 5 -n 500 site.com/调整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;

429 Too Many Requests 429 请求过多

This configures nginx to return the standard status code 429 Too Many Requests when requests are rejected due to rate limiting.这将 nginx 配置为在请求因速率限制而被拒绝时返回标准状态代码429 Too Many Requests

nginx returns a 503 error by default (a bad default) meaning the application is failing, but it is not failing it is rate limited. nginx 默认返回503错误(一个错误的默认值),这意味着应用程序失败了,但它没有失败,它受速率限制。 It's important to configure status code appropriately to distinguish between server errors and rate limiting.适当配置状态代码以区分服务器错误和速率限制非常重要。

Cloudflare and client IP Cloudflare 和客户端 IP

When behind cloudflare, nginx will not see the IP of the client but the IP of the cloudflare server.在 cloudflare 后面时,nginx 不会看到客户端的 IP,而是看到 cloudflare 服务器的 IP。 One might think that it breaks rate limiting by IP but it does not, well, just a bit.有人可能认为它打破了 IP 的速率限制,但它并没有,嗯,只是一点点。

When testing locally with ab , your test computer is only resolving a handful of cloudflare servers, and ab probably only uses the first IP.使用 ab 进行本地测试时,您的测试计算机仅解析少数 cloudflare 服务器,而ab可能仅使用第一个 IP。 So no there aren't numerous clients IP, the rate limiting should work just fine.所以没有很多客户IP,速率限制应该工作得很好。

When in production , there will be different clients accessing through different cloudflare servers.在生产中,会有不同的客户端通过不同的 cloudflare 服务器进行访问。 Still, there aren't that many cloudflare servers and clients in a geographic area will most likely resolve to the same cloudflare servers.尽管如此,在一个地理区域内并没有那么多 cloudflare 服务器和客户端最有可能解析到相同的 cloudflare 服务器。 So there will be a bunch of different IPs somewhat defeating the rate limiting, but probably not that many.所以会有一堆不同的 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

Cloudflare puts the original client IP in the CF-Connecting-IP header. Cloudflare 将原始客户端 IP 放在CF-Connecting-IP header 中。 It can also be in the X-Forwarded-For header or X-Real-Ip or True-Client-IP depending on settings and requests.它也可以在X-Forwarded-For header 或X-Real-IpTrue-Client-IP中,具体取决于设置和请求。 See https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-请参阅https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-

Hence the above configuration does rate limiting by client IP using the CF-Connecting-IP header.因此,上述配置通过使用CF-Connecting-IP header 的客户端 IP 进行速率限制。 The nginx variable $binary_remote_addr would be the cloudflare server IP. nginx 变量$binary_remote_addr将是 cloudflare 服务器 IP。

Do not use X-Forwarded-For to rate limit不要使用X-Forwarded-For来限制速率

The X-Forwarded-For header can be controlled by the client. X-Forwarded-For header 可由客户端控制。 It shouldn't be used for rate limiting because it is trivial to circumvent.它不应该用于速率限制,因为它很容易规避。

Example with a client having the IP 100.11.22.33 :具有 IP 100.11.22.33的客户端的示例:

  • On a request without a X-Forwarded-For header => Cloudflare sets X-Forwarded-For: 100.11.22.33 and CF-Connecting-IP: 100.11.22.33 on the request.在没有X-Forwarded-For header => Cloudflare 的请求上设置X-Forwarded-For: 100.11.22.33CF-Connecting-IP: 100.11.22.33请求。
  • On a request with a X-Forwarded-For: dummyvalue header already set => CloudFlare sets X-Forwarded-For: dummyvalue,100.11.22.33 and CF-Connecting-IP: 100.11.22.33 on the request.在带有X-Forwarded-For: dummyvalue header already set => CloudFlare 设置X-Forwarded-For: dummyvalue,100.11.22.33CF-Connecting-IP: 100.11.22.33的请求上。

As you can see, it's trivial for the client to put a random value per request and totally circumvent any rate limiting based on the X-Forwaded-For header.如您所见,客户端为每个请求设置一个随机值并完全绕过基于X-Forwaded-For header 的任何速率限制是微不足道的。

I would suggest trying the following:我建议尝试以下方法:

(not sure if your backend is PHP but you can readjust) (不确定您的后端是否为 PHP 但您可以重新调整)

# Conection Limit, taking the best from:
# http://serverfault.com/questions/177461/how-to-rate-limit-in-nginx-but-including-excluding-certain-ip-addresses
# http://gadelkareem.com/2015/01/18/limiting-connections-requests-wordpress-nginx/

geo $whitelist {
   default 0;
   # CIDR in the list below are not limited ( 1 )
   127.0.0.1/32 1;

}

map $whitelist $limit {
    0     $binary_remote_addr;
    1     "";
}

# The directives below limit concurrent connections from a 
# non-whitelisted IP address to five

limit_conn_zone      $limit    zone=conlimit:30m;
limit_conn_zone      $limit    zone=conlimit_php:30m;

limit_conn           conlimit 40;
limit_conn_log_level warn;   # logging level when threshold exceeded
limit_conn_status    503;    # the error code to return

# Limit Req Non - PHP 
limit_req_zone       $limit   zone=reqlimit:30m  rate=5r/s; 
limit_req            zone=reqlimit burst=10;

# Limit Req PHP
limit_req_zone       $limit   zone=reqlimit_php:30m  rate=1r/s; 

limit_req_log_level  warn;
limit_req_status     503;

# Location VirtualHost

limit_req            zone=reqlimit_php burst=4;
limit_conn           conlimit_php 10;

And for CF-Connecting-IP , you can whitelist the Cloudflare IPs via:对于CF-Connecting-IP ,您可以通过以下方式将 Cloudflare IP 列入白名单:

#!/bin/bash
cloudflare_real_ip_conf='/usr/local/nginx/conf/cloudflare_ip.conf'

echo "#Cloudflare" > ${cloudflare_real_ip_conf};
for i in `curl -sk https://www.cloudflare.com/ips-v4`; do
        echo "set_real_ip_from $i;" >> ${cloudflare_real_ip_conf};
done
for i in `curl -sk https://www.cloudflare.com/ips-v6`; do
        echo "set_real_ip_from $i;" >> ${cloudflare_real_ip_conf};
done

echo "" >> ${cloudflare_real_ip_conf};
echo "# use any of the following two" >> ${cloudflare_real_ip_conf};
echo "real_ip_header CF-Connecting-IP;" >> ${cloudflare_real_ip_conf};
echo "#real_ip_header X-Forwarded-For;" >> ${cloudflare_real_ip_conf};

which will produce the CF whitelist (currently):这将产生 CF 白名单(当前):

#Cloudflare
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/12;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;

# use any of the following two
real_ip_header CF-Connecting-IP;
#real_ip_header X-Forwarded-For;

You can add below to you nginx config您可以在下面添加 nginx 配置

real_ip_header CF-Connecting-IP;

See the below article for more details有关更多详细信息,请参阅下面的文章

https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers- https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM