Nginx获取用户真实ip
为了网站的正常运行,所以我们要对网站的访问做一些限制,如果网站没有使用CDN,也就是用户直接与服务器相连,网站的访问方式为:用户浏览器->服务器。
如果网站使用了CDN,那么网站的访问方式就变成了:用户浏览器->CDN->服务器,这个时候方案一就会对CDN的IP做出限制,起到了相反的作用。
如果是第一种,此时 $remote_addr显示的正是用户的IP,如果使用CDN,那么remote_addr显示的是CDN的IP,remote_addr获取到的 IP 是 Web 服务器 TCP 连接的 IP(这个不能伪造,如果伪造了源 IP,无法建立 TCP 连接,更不会有后面的 HTTP 请求)
X-Forwarded-For 是一个扩展头,用来表示 HTTP 请求端真实 IP。
1 2
| #X-Forwarded-For请求头格式非常简单 X-Forwarded-For:client, proxy1, proxy2
|
最远的为客户端IP,但是注意这个客户端IP是可以伪造的。有些CDN是提供realip(可能要企业用户才能使用,cf提供了CF-Connecting-IP,True-Client-IP(仅Enterprise计划)),我们普通用户使用cf的话可以好好利用CF-Connecting-IP来获取用户真实IP。
获取真实IP
map需要放入nginx.conf或者site.conf中非server段
通过CloudFlare的CDN CF-Connecting-IP
获取真实IP(可信程度较高)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| map $HTTP_CF_CONNECTING_IP $real { "" $remote_addr; "~^([0-9a-fA-F:.]+)$" $HTTP_CF_CONNECTING_IP; }
map $HTTP_CF_CONNECTING_IP $real { "" $remote_addr; "~^(?<ipv6>[a-fA-F0-9:]+)$" $ipv6; "~^(?<ipv4>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$" $ipv4; default $HTTP_CF_CONNECTING_IP; }
map $HTTP_CF_CONNECTING_IP $real { "" $remote_addr; default $HTTP_CF_CONNECTING_IP; }
|
通过 http_x_forwarded_for
获取真实IP(可信程度较低)
1 2 3 4 5 6
| map $http_x_forwarded_for $clientRealIP{ "" $remote_addr; ~^(?P<firstAddr>[0-9a-fA-F:.]+),?.*$ $firstAddr; }
|
通过nginx的realip模块获取真实地址(可信程度较低)
通过X-Forwarded-For获取用户真实IP,然后赋值给$remote_addr,但不是很可靠。
没有尝试,这只是一种方法。
可以尝试从$HTTP_CF_CONNECTING_IP获取用户真实IP,然后赋值给remote_addr。
没有使用CDN(可信程度较高)
如果没有使用CDN,那么直接使用 $remote_addr
1
| proxy_set_header X-Real-IP $remote_addr;
|
则 HTTP_X_REAL_IP
的值为用户真实的ip。
总结:
我认为通过 CF-Connecting-IP
获取到的IP真实性高,强烈建议使用第一种,如果CDN提供商不是CloudFlare且没有提供客户端 IP 地址,那么只能使用第二种。
我们可以完全信任 HTTP_CF_CONNECTING_IP
,而不是 http_x_forwarded_for
获取到真实IP后就可以对这些IP的活动进行限制。
1 2 3 4 5 6 7 8 9 10 11 12
| map $HTTP_CF_CONNECTING_IP $real { "" $remote_addr; "~^(?<ipv6>[a-fA-F0-9:]+)$" $ipv6; "~^(?<ipv4>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$" $ipv4; default $HTTP_CF_CONNECTING_IP; }
|
使用
我们获取到了用户的真实ip,那么我们要怎么使用他们呢?
以前都写过就不在赘述了。
日志
nginx
有一些变量需要改一下,比如map中的 $real
, $clientRealIP
log_format main 中的 $real
, $clientRealIP
, $http_x_forwarded_for
log_format
和 map
要放在server{}以外
应用
搭建图床
限制速率
vim /etc/nginx/nginx.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| http{ ... map $HTTP_CF_CONNECTING_IP $real { "" $remote_addr; default $HTTP_CF_CONNECTING_IP; } limit_conn_zone $real zone=perserver:10m; limit_conn perserver 20; limit_conn_log_level notice; limit_req_zone $real zone=one:10m rate=15r/s; limit_req_log_level notice; limit_req_status 403; limit_req zone=one burst=10 nodelay; ... } server{ ... ... }
|
我们需要知道的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| 1. 几个概念 remote_addr:如果中间没有代理,这个就是客户端的真实IP,如果有代理,这就是上层代理的IP. X-Forwarded-For:一个HTTP扩展头,格式为 X-Forwarded-For: client, proxy1, proxy2 X-Real-IP:自定义的HTTP头,用于把客户端真实IP一层层传递下去。
2.几个变量 $remote_addr:上层IP(客户端或代理) $proxy_add_x_forwarded_for:包括客户端请求头的X-Forwarded-For和$remote_addr $http_x_forwarded_for:就是X-Forwarded-For的值
3. 获取客户端真实IP的方法 3.1 通过设置X-real-IP层层传递 首层代理:proxy_set_header X-Real-IP $remote_addr; 针对首层代理,拿到真实IP 非首层代理:proxy_set_header X-Real-IP $http_x_real_ip; # 针对非首层代理,一直传下去 3.2 通过设置X-Forwarded-For请求头 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 然后截取X-Forward-For请求头的第一段,即是客户端的真实IP
4. 经过CDN后,获取用户真实IP的方法 4.1 一般CDN都会传递X-Forwarded-For请求头,通过X-Forwarded-For请求头获取用户真实IP。 4.2 后端Nginx配置 http { map $http_x_forwarded_for $clientRealIp { "" $remote_addr; ~^(?P<firstAddr>[0-9\.]+),?.*$ $firstAddr; }
} 我们通过map自定义了一个变量$clientRealIp; 如果X-Forwarded-For头是空的,那么客户端真实IP就是remote_addr; 如果X-Forwarded-For头非空,我们就通过正则匹配,捕获到第一段,这就是用户的真实IP,当然有可能是用户伪造的; 必须注意的是,在每一层代理都要设置X-Forwarded-For头。
|
安装压力测试软件
1 2 3 4 5 6 7 8 9
| wget http://download.joedog.org/siege/siege-4.1.1.tar.gz tar -zxvf siege-4.1.1.tar.gz
cd siege-4.1.1 ./configure --with-ssl=/usr/bin/openssl make clean make && make install
siege -c 1000 -r 10000 -d 10 <url>
|
参考与引用:
nginx通过cloudflare cdn的请求头获取用户真实ip 兼容Ipv6
Cloudflare如何处理HTTP请求标头?
HTTP request headers
Restoring original visitor IPs
https://limbopro.com/archives/1852.html
https://www.imydl.tech/lnmp/231.html