前言
之前我们分享了nginx反向代理的X-Real-IP和X-Forwarded-For的作用和实现原理,现在我们就根据之前的实验结果,继续分享nginx反向代理如何获取客户端的真实IP
Realip模块
该模块的作用是帮助我们在使用了代理的情况下获取客户真实ip。该模块默认不编译进nginx二进制文件中,需要在编译时指定 --with-http_realip_module 参数才会安装该模块(yum安装的nginx默认编译该模块)
参数说明
set_real_ip_from
指定可信地址,这里的可信地址是上一级代理,也就是直接访问上游服务的代理的ip;可以指定多行该指令;如果不使用该指令,就无法获取到起始客户端IPreal_ip_header
告知Nginx真实客户端IP从哪个请求头获取。默认是X-Real-IP。但我们一般设置为X-Forwarded-For。real_ip_recursive off
是否递归解析,off表示默认从最后一个地址开始解析。例如 X-Forwarded-For 是 1.1.1.1,2.2.2.2,3.3.3.3,那么off取的是3.3.3.3,我们一般设置为on。如果只有一层代理,on和off都无所谓。
以上参数,一般配置在后端服务中,中间代理层不做配置
实验解析
网络环境还是上篇文档中的相关配置,下面直接开始实验过程。
| 角色 | ip | 软件及版本 | 
|---|---|---|
| 客户端 | 192.168.124.101 | nginx1.22.1 | 
| 反向代理A | 192.168.124.170 | nginx1.22.1 | 
| 反向代理B | 192.168.124.171 | nginx1.22.1 | 
| 反向代理C | 192.168.124.172 | nginx1.22.1 | 
| 后端web服务器 | 192.168.124.173 | nginx1.22.1 | 
客户端配置域名解析文件C:\Windows\System32\drivers\etc\hosts
192.168.124.170   www.ywnm.com
real_ip_recursive
开启
在反向代理节点A/B/C中开启proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;,A节点开启proxy_set_header X-Real-IP $remote_addr;,
后端web服务器,配置Realip模块参数real_ip_recursive on;,set_real_ip_from添加3个代理地址为可信地址,具体配置如下
后端web服务
http{
...
    log_format  main  '$remote_addr + "$http_host" + "$http_x_forwarded_for" + "$http_x_real_ip"';
    access_log    logs/access.log main;
    server {
        listen       80;
        server_name  192.168.124.173;
        set_real_ip_from 192.168.124.170;
        set_real_ip_from 192.168.124.171;
        set_real_ip_from 192.168.124.172;
        real_ip_header   X-Forwarded-For;
        real_ip_recursive on;
        location / {
            root   html/;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html/;
        }
    }
}
访问www.ywnm.com,后端web服务日志:
192.168.124.101 + "www.ywnm.com" + "192.168.124.101, 192.168.124.170, 192.168.124.171" + "-"
关闭
后端web服务器,设置real_ip_recursive off;,访问www.ywnm.com,后端web服务日志:
192.168.124.171 + "www.ywnm.com" + "192.168.124.101, 192.168.124.170, 192.168.124.171" + "-"
注意
这里的remote_addr值变成了192.168.124.171。上一篇中的实验结果,该值都是192.168.124.172,即后端web服务的上层代理节点C的ip。
set_real_ip_from
设置不同可信地址set_real_ip_from时,后端web服务日志中remote_addr的变化
set_real_ip_from可信地址设置为192.168.124.170/171,去掉192.168.124.172,后端web服务日志 
192.168.124.172 + "www.ywnm.com" + "192.168.124.101, 192.168.124.170, 192.168.124.171" + "-"
set_real_ip_from可信地址设置为192.168.124.170/172,去掉192.168.124.171,后端web服务日志 
192.168.124.171 + "www.ywnm.com" + "192.168.124.101, 192.168.124.170, 192.168.124.171" + "-"
set_real_ip_from可信地址设置为192.168.124.171/172,去掉192.168.124.170,后端web服务日志 
192.168.124.170 + "www.ywnm.com" + "192.168.124.101, 192.168.124.170, 192.168.124.171" + "-"
通过启用Realip模块配置,与上篇《nginx反向代理之获取客户端IP(一)》实验结果对比,可知:
不使用realip模块, $remote_addr是上一级代理的ip。使用了realip模块,$remote_addr是real_ip_header指令指定的起始客户端ip.当real_ip_recursive为off时,nginx会把real_ip_header指定的HTTP头中的最后一个IP当成真实IP 当real_ip_recursive为on时,nginx会把real_ip_header指定的HTTP头中的最后一个不是信任服务器的IP当成真实IP 
IP地址伪装
从之前的实验结果, 我们一共得到得到了2种获取客户端真实IP的方式:
从首层代理(或者是互联网中的CDN)自定义header头 
即设置proxy_set_header X-Real-IP $remote_addr;,然后在应用端解析$http_x_real_ip获取forwarded-for信息,设置realip 
即每层代理都设置proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;,在后端web服务通知设置可信地址,并开启real_ip_recursive来获取真实客户端ip。
以上的2种方案都能获取到真实的客户端ip,但是当你的后端服务不是nginx作为web服务(不能设置可信地址,并且从右往左遍历ip串),或者是后端代码通过获取远程客户端ip,如以下代码:
public String getClientIp(HttpServletRequest request) {
    String xff = request.getHeader("X-Forwarded-For");
    if (xff == null) {
        return request.getRemoteAddr();
    } else {
        return xff.contains(",") ? xff.split(",")[0] : xff;
    }
}
这个时候,通过X-Forwarded-For来获取heade头作为客户端真实ip就会出现问题。我们通过apipost伪装X-Forwarded-For并发送请求来模拟
此时后端web中获取到的日志信息:
192.168.124.101 + "www.ywnm.com" + "2.2.2.2, 192.168.124.101, 192.168.124.170, 192.168.124.171" + "-"
此时X-Forwarded-For为2.2.2.2, 192.168.124.101, 192.168.124.170, 192.168.124.171,如果取字符串的最左侧ip,客户端为2.2.2.2
总结
小型架构(单一代理) 
直接使用 X-Real-IP,简单高效,日志中获取到的 IP 就是客户端的真实 IP。或者使用remote_addr,因为remote_addr无法伪造多层代理架构(Nginx + CDN / WAF / 反向代理链) 
建议使用 X-Forwarded-For,配合 real_ip_recursive 来递归解析最原始的 IP 地址。。并且首层代理配置proxy_set_header X-Forwarded-For $remote_addr;代替proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;,这样X-Forwarded-For将无法伪造客户端ip。

优网科技秉承"专业团队、品质服务" 的经营理念,诚信务实的服务了近万家客户,成为众多世界500强、集团和上市公司的长期合作伙伴!
优网科技成立于2001年,擅长网站建设、网站与各类业务系统深度整合,致力于提供完善的企业互联网解决方案。优网科技提供PC端网站建设(品牌展示型、官方门户型、营销商务型、电子商务型、信息门户型、微信小程序定制开发、移动端应用(手机站、APP开发)、微信定制开发(微信官网、微信商城、企业微信)等一系列互联网应用服务。
                    
                                    
                                    
        
        
                    
                    
                    
公安局备案号:
                                
