更多优质内容
请关注公众号

Nginx HTTP模块篇 realip模块 (十)-张柏沛IT博客

正文内容

Nginx HTTP模块篇 realip模块 (十)

栏目:其他内容 系列:Nginx入门系列 发布时间:2020-02-14 18:50 浏览量:3469

在nginx中,我们可以通过 $remote_addr 变量来获取客户端的IP。获取了客户端IP之后,我们可以做很多事情如限速限流等。

但是如果 客户端A 通过 反向代理B 访问到 上游服务C ,假设上游服务是我们的nginx服务,那么上游服务 $remote_addr 获取到的是反向代理的IP,因为直接访问C的是反向代理B而不是客户端A。

此时我们如何去获取客户端A的IP。

在这里,我们要介绍header请求头的X-Forwarded-For和X-Real-IP


 X-Forwarded-For

如果 A 直接访问 C,那么A的请求头中是没有 X-Forwarded-For 这个项的。
如果 A 通过代理B 再去访问 C ,此时B发向C的请求头中才会有 X-Forwarded-For 这个项,其内容是A的ip。
如果 A 通过代理B 访问代理B2 再访问C,此时到达C的请求头中的 X-Forwarded-For 的内容是 “A的ip,B的ip”;也就是说,经过多层代理的话,X-Forwarded-For会叠加经过的ip,每经过一层ip,代理服务器会叠加上一级访问者的ip,但是不会叠加自己的ip。

所以假如 A 的ip为1.1.1.1,B的ip为2.2.2.2,C的ip为192.168.5.100
那么 A通过代理B访问到C ,最终到达C的X-Forwarded-For 内容为: 1.1.1.1 (不含2.2.2.2,因为B不会在X-Forwarded-For中添加自己的ip),C就可以在X-Forwarded-For中获取到真实客户端A的IP,当然C也可以通过 $remote_addr 获取到代理B的ip。

如果 A通过代理B访问代理B2访问C,则:
A的请求头中X-Forwarded-For:无
B的请求头中X-Forwarded-For:1.1.1.1
B2的请求头中X-Forwarded-For:1.1.1.1,2.2.2.2
C接受到的请求中的请求头:X-Forwarded-For:1.1.1.1,2.2.2.2

当然,代理可以决定加不加 X-Forwarded-For 。有些正向代理为了隐藏真实客户端IP会不设置X-Forwarded-For这个请求头。
但是一般反向代理会按照上面的规则设置 X-Forwarded-For 以方便知道请求经过了哪些IP。


X-Real-IP

X-Real-IP 就简单多了,无论经过多少层代理,X-Real-IP记录的都是原始客户端A的ip。
但是在使用代理的时候,代理服务器会遵守规则去添加 X-Forwarded-For ,可是X-Real-IP则不会作为标准要求代理去添加。

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



正向代理和反向代理

正向代理是,假如我要访问谷歌,但是国外网站国内访问不了,此时我们会主动使用VPN这样的代理服务去访问谷歌。这个代理是我们客户端主动找的中间节点,这个就是正向代理。

反向代理是,假如我要访问百度,百度有很多的服务器,百度为了方便我们访问会设置代理服务器,然后我们访问的是百度的代理,代理服务根据一定算法把我们的请求分配到百度其中一台主机上,这样做是为了负载均衡以及根据地区选择最近的节点加速访问。这个代理是上游服务端百度为了方便我们访问而设,所以这个就是反向代理。

正向代理和反向代理的原理都一样,关键是由客户端设置的还是服务端设置的。客户端设置的就是正向代理,服务端设置的是反向代理。


realip模块

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

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,根据我们上面讲的,这里真实客户端IP应该是1.1.1.1才对。所以我们一般设置为on。如果只有一层代理,on和off都无所谓。


变量

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

这些指令和变量都是在终端服务写的,不要写在了代理服务中。


下面我们做一个试验,做一个两层反向代理请求:
客户端(A)在本地 : 223.73.208.20
两层反向代理和上游服务都在203.195.165.55
代理(B1): 203.195.165.55:8089
代理(B2): 203.195.165.55:8080     # 也就是B1的上游服务
终端上游服务(C): 203.195.165.55:8088/remote_addr  # 也就是B2的上游服务

Nginx配置如下:

# 定义终端上游服务
upstream rd {
    server 203.195.165.55:8088;
}

# 定义代理B1的上游服务(代理B2)
upstream rd2 {
    server 203.195.165.55:8080;
}

# 代理B2
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页面
    }
}
 
# 代理B1
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;
    }
} 
 
# 终端上游服务
server {
    listen 8088;
    set_real_ip_from 203.195.165.55;    # 指定了两个可靠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头。

如果不添加这几个header头,终端服务就不能通过 X-Forwarded-For 或者 X-Real-IP 获取起始客户端的IP了。

# 重新加载配置
nginx -s reload

在我本地 223.73.208.20 主机的cmd中发送一条对代理B1的请求,B1会请求B2再请求到C。得到的信息为
Your remote_addr is 223.73.208.20               # 起始客户端IP
Your realip_remote_addr is 203.195.165.55       # 直接请求终端的代理IP,即B2的ip
Your realip_remote_port is 38004
Your X-Forwarded-For 223.73.208.20, 203.195.165.55  # X-Forwarded-For请求头的值,这里是起始客户端IP和代理B1的IP




更多内容请关注微信公众号
zbpblog微信公众号

如果您需要转载,可以点击下方按钮可以进行复制粘贴;本站博客文章为原创,请转载时注明以下信息

张柏沛IT技术博客 > Nginx HTTP模块篇 realip模块 (十)

热门推荐
推荐新闻