nginx反向代理之获取客户端IP(二)

前言

之前我们分享了nginx反向代理的X-Real-IPX-Forwarded-For的作用和实现原理,现在我们就根据之前的实验结果,继续分享nginx反向代理如何获取客户端的真实IP

Realip模块

该模块的作用是帮助我们在使用了代理的情况下获取客户真实ip。
该模块默认不编译进nginx二进制文件中,需要在编译时指定 --with-http_realip_module 参数才会安装该模块(yum安装的nginx默认编译该模块)

参数说明

  • set_real_ip_from

    指定可信地址,这里的可信地址是上一级代理,也就是直接访问上游服务的代理的ip;可以指定多行该指令;如果不使用该指令,就无法获取到起始客户端IP

  • real_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.101nginx1.22.1
反向代理A192.168.124.170nginx1.22.1
反向代理B192.168.124.171nginx1.22.1
反向代理C192.168.124.172nginx1.22.1
后端web服务器192.168.124.173nginx1.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(一)》实验结果对比,可知:

  1. 不使用realip模块,$remote_addr是上一级代理的ip。使用了realip模块,$remote_addr是real_ip_header指令指定的起始客户端ip.
  2. 当real_ip_recursive为off时,nginx会把real_ip_header指定的HTTP头中的最后一个IP当成真实IP
  3. 当real_ip_recursive为on时,nginx会把real_ip_header指定的HTTP头中的最后一个不是信任服务器的IP当成真实IP

IP地址伪装

从之前的实验结果, 我们一共得到得到了2种获取客户端真实IP的方式:

  1. 从首层代理(或者是互联网中的CDN)自定义header头

    即设置proxy_set_header X-Real-IP $remote_addr;,然后在应用端解析$http_x_real_ip
  2. 获取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

总结

  1. 小型架构(单一代理)

    直接使用 X-Real-IP,简单高效,日志中获取到的 IP 就是客户端的真实 IP。或者使用remote_addr,因为remote_addr无法伪造
  2. 多层代理架构(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。

本文由mdnice多平台发布

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

运维之牛马

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值