Nginx中如何获取客户端真实IP?

 3个月前     2  

文章目录

在nginx中,可以通过 $remote_addr 变量来获取客户端的IP,获取了客户端IP之后,才可以做限速、限流相关的配置等。但是如果用户A通过反向代理B访问到上游服务C ,假设上游服务是我们的nginx服务,那么上游服务 $remote_addr 获取到的是反向代理B的IP,因为直接访问C的是反向代理B而不是客户端A。

此时我们去获取用户A的IP,就要从header请求头的X-Forwarded-For和X-Real-IP来获取。
Nginx中如何获取客户端真实IP?

remote_addr 默认拿到的是上一级的ip地址, 来自于TCP连接,表示与服务端建立TCP连接的设备IP,因此,Remote Address无法伪造。

X-Forwarded-For

X-Forwarded-For(XFF) 是一个 HTTP 扩展头部。HTTP/1.1(RFC 2616)协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP。

XFF如今它已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中。

在消息流从客户端流向服务器的过程中被拦截的情况下,服务器端的访问日志只能记录代理服务器或者负载均衡服务器的IP地址。如果想要获得最初发起请求的客户端的IP地址的话,那么 X-Forwarded-For 就派上了用场。通常它的格式类似这样:

X-Forwarded-For: IP0(client), IP1(proxy1), IP2(proxy2)

X-Forwarded-For 会记录用户ip与每次转发用的代理服务器ip, 也就是说,经过多层代理的话,X-Forwarded-For会叠加经过的ip,每经过一层ip,代理服务器会叠加上一级访问者的ip,但是不会叠加自己的ip。

X-Real-IP

X-Real-IP无论经过多少层代理,X-Real-IP记录的都是原始客户端A的ip。

X-Real-IP是Nginx独有的,不是RFC规范,所以与client间如果还有其他非Nginx软件实现的代理,将取不到X-Real-IP头部

所以在上游服务器获取起始客户端IP一般是使用 X-Forwarded-For 而不是 X-Real-IP。

realip模块

Nginx中如何获取客户端真实IP?
用途:使用了代理的情况下可以获取到用户的真实IP地址
使用realip 功能需要 Nginx 添加 ngx_http_realip_module 模块,默认情况下是不被编译,如果需要添加,请在编译时添加 --with-http_realip_module 选项开启它。
PS:编译安装Nginx到指定路径的步骤:

1、 ./configure --prefix=/home/ap/nginx2 --with-http_realip_module
2、 make  && make install #编译和安装

realip 指令解释

 

  • • set_real_ip_from:设置上一级反向代理服务器,即可信任服务器IP(取客户端IP时候会从X-Forwarded-For排除掉可信地址ip)
  • • real_ip_header :X-Forwarded-For/X-Real-IP/proxy_protocol:告知Nginx真实客户端IP从哪个请求头获取。默认是X-Real-IP。但我们一般设置为X-Forwarded-For。
  • • real_ip_recursive:是否递归解析
    • • off:默认是off, 会将real_ip_header指定的HTTP头中的最后一个IP作为真实IP,一般都会开启
    • • on:会将real_ip_header指定的HTTP头中的从右边开始数第一个不是信任服务器的IP当成真实IP

在 X-Forward-For 的最左边才是真实用户的地址,右边都是代理地址,当我们把 real_ip_header 设置为 X-Forward-For 时,如果没有启用 环回地址 real_ip_recursive,我们取到的 $remote_addr 是 X-Forward-For 中最右边的 ip,无论是否设置了 set_real_ip_from;如果启用了环回地址 real_ip_recursive on,那么就获取 而是从右边开始数,第一个非可信地址的IP ,也就是排除设置了 set_real_ip_from(可信地址外的)

realip 变量

$realip_remote_addr   # 上一级代理的ip
$realip_remote_port   # 上一级代理的端口 
$remote_addr       # 如果不使用realip模块,$remote_addr是上一级代理的ip,使用了realip模块,是real_ip_header指令指定的起始客户端ip 

使用示例

  • • 客户端(A)在本地Windows机器上 :192.168.2.1
  • • 两层反向代理和上游服务都在192.168.2.129
  • • 代理(P1): 192.168.2.129:8089
  • • 代理(P2): 192.168.2.129:8080 # 也就是P1的上游服务
  • • 终端上游服务(C): 192.168.2.129:8088/remote_addr # 也就是P2的上游服务

访问路径如下:

A->P1->P2->具体服务C

# 定义终端上游服务
upstream rd {
    server 192.168.2.129:8088;
}
# 定义代理P1的上游服务(代理P2)
upstream rd2 {
    server 192.168.2.129:8080;
}
# 代理P1
server {
    listen 8089;
    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;    # 必须要定义,否则realip无法通过X-Forwarded-For请求头获取起始客户端ip
        proxy_pass http://rd2;
    }
}

# 代理P2
server {
    listen 8080;
    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  # 必须要定义,否则realip无法通过X-Forwarded-For请求头获取起始客户端ip
        proxy_pass http://rd/remote_addr;   #访问终端上游服务的remote_addr页面
    }
}

# 终端上游服务
server {
    listen 8088;
    set_real_ip_from 192.168.2.129;    #指定了两个可信任的IP,第二个是一个ip段
    set_real_ip_from 223.73.208.0/24;

    #real_ip_header X-Real-IP;
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;

    location /remote_addr {
        # 返回状态码200 以及一些信息。
        return 200 "Your remote_addr is $remote_addr\nYour realip_remote_addr is $realip_remote_addr\nYour realip_remote_port is $realip_remote_port\nYour X-Forwarded-For $http_x_forwarded_for";
    }
}

proxy_set_header 可以在代理服务发送请求时添加相应的header头,上面通过proxy_set_header添加了X-Forwarded-For/X-Real-Ip/Host这三个header头。

在我本地 192.168.2.1 主机对代理B1发postman请求,P1会请求P2再请求到C。得到的信息为 Your remote_addr is 192.168.2.1 # 起始客户端IP Your realip_remote_addr is 192.168.2.129 #直接请求终端的代理IP,即P2的ip Your realip_remote_port is 48348 Your X-Forwarded-For 192.168.2.1, 192.168.2.129 # X-Forwarded-For请求头的值,这里是起始客户端IP和代理B1的IP

Nginx中如何获取客户端真实IP?

 

暂无评论

暂无评论...