nginx 真实ip获取

反向代理与 Real-IP 和 X-Forwarded-For

一、虚拟机准备环境

客户端:192.168.29.7

proxy1:192.168.32.230

proxy2:192.168.32.231

proxy3:192.168.32.232

real server:192.168.32.245

 

二、测试

1、直接使用最简单反向代理测试

proxy1-3配置相同

server {
        server_name     www.jcici.com;
        listen  80;

        access_log /home/nginx/logs/daili.access.log main;
        error_log /home/nginx/logs/daili.error.log;

        location / {
        proxy_pass http://192.168.32.231;  #每台nginx反向代理的ip不一样
        }
}

 

real server配置为

server {
        server_name     www.jcici.com;
        listen  80;

        access_log /home/nginx/logs/ceshi.access.log main;
        error_log /home/nginx/logs/ceshi.error.log;

        location /realip {
                default_type text/html;
                index index.html index.htm;
                echo "$remote_addr || $http_x_real_ip || $http_x_forwarded_for";
        }
}

客户端访问

http://www.jcici.com/realip

输出结果为

192.168.32.232 || ||

分析:

(1)$remote_addr在这里获取的是最后一层代理到real server的ip,并不是客户端真正的ip

(2)$http_x_real_ip获取不到是因为在代理端没有将$remote_addr 的值赋到X-Real-IP上,所以为空;

(3)因代理没有特殊配置X-Forwarded-for,值不会自动添加到头信息中去,所以为空;

 

2、通过添加X-Real-IP将真实ip赋值。

proxy1

server {
        server_name     www.jcici.com;
        listen  80;

        access_log /home/nginx/logs/daili.access.log main;
        error_log /home/nginx/logs/daili.error.log;

        location / {
        proxy_pass http://192.168.32.231;
        proxy_set_header X-Real-IP $remote_addr;  #将客户真实ip赋予值到X-Real-IP;
        }
}

proxy2-3以及real server保持配置不变

客户端访问

http://www.jcici.com/realip

输出结果为

192.168.32.232 || 192.168.29.7 ||

 

分析:

(1)$remote_addr在这里获取的是最后一层代理到real server的ip,并不是客户端真正的ip;

(2)$http_x_real_ip 其中这个X-real-ip是一个自定义的变量名,名字可以随意取,这样做完之后,用户的真实ip就被赋予在X-real-ip这个变量里了,注:在后端real server用$http_x_real_ip获取;

(3)因代理没有特殊配置X-Forwarded-for,值不会自动添加到头信息中去,所以为空;

 

3、通过添加X-Real-IP和X-Forwarded-For捕获客户端真实IP。

proxy1

server {
        server_name     www.jcici.com;
        listen  80;

        access_log /home/nginx/logs/daili.access.log main;
        error_log /home/nginx/logs/daili.error.log;

        location / {
        proxy_pass http://192.168.32.231;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

proxy2-3

server {
        server_name     www.jcici.com;
        listen  80;

        access_log /home/nginx/logs/ceshi.access.log main;
        error_log /home/nginx/logs/ceshi.error.log;

        location / {
        proxy_pass http://192.168.32.232;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

real server保持不变

客户端访问

http://www.jcici.com/realip

输出结果为

192.168.32.232 || 192.168.29.7 || 192.168.29.7, 192.168.32.230, 192.168.32.231

分析:

(1)$remote_addr在这里获取的是最后一层代理到real server的ip,并不是客户端真正的ip;

(2)$http_x_real_ip 其中这个X-real-ip是一个自定义的变量名,名字可以随意取,这样做完之后,用户的真实ip就被赋予在X-real-ip这个变量里了,注:在后端real server用$http_x_real_ip获取;

(3)X-Forwarded-For的值为client1,proxy1,proxy2。在这里X-Forwarded-For不会保存最后一级的代理ip

 1 1. proxy_set_header    X-real-ip $remote_addr;
 2 
 3 这句话之前已经解释过,有了这句就可以在web服务器端获得用户的真实ip
 4 
 5 但是,实际上要获得用户的真实ip,不是只有这一个方法,下面我们继续看。
 6 
 7 2.  proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
 8 
 9 我们先看看这里有个X-Forwarded-For变量,这是一个squid开发的,用于识别通过HTTP代理或负载平衡器原始IP一个连接到Web服务器的客户机地址的非rfc标准,如果有做X-Forwarded-For设置的话,每次经过proxy转发都会有记录,格式就是client1, proxy1, proxy2,以逗号隔开各个地址,由于他是非rfc标准,所以默认是没有的,需要强制添加,在默认情况下经过proxy转发的请求,在后端看来远程地址都是proxy端的ip 。也就是说在默认情况下我们使用request.getAttribute("X-Forwarded-For")获取不到用户的ip,如果我们想要通过这个变量获得用户的ip,我们需要自己在nginx添加如下配置:
10 
11 proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
12 
13 意思是增加一个$proxy_add_x_forwarded_for到X-Forwarded-For里去,注意是增加,而不是覆盖,当然由于默认的X-Forwarded-For值是空的,所以我们总感觉X-Forwarded-For的值就等于$proxy_add_x_forwarded_for的值,实际上当你搭建两台nginx在不同的ip上,并且都使用了这段配置,那你会发现在web服务器端通过request.getAttribute("X-Forwarded-For")获得的将会是客户端ip和第一台nginx的ip。
14 
15 那么$proxy_add_x_forwarded_for又是什么?
16 
17 $proxy_add_x_forwarded_for变量包含客户端请求头中的"X-Forwarded-For",与$remote_addr两部分,他们之间用逗号分开。
18 
19 举个例子,有一个web应用,在它之前通过了两个nginx转发,www.linuxidc.com 即用户访问该web通过两台nginx。
20 
21 在第一台nginx中,使用
22 
23 proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
24 
25 现在的$proxy_add_x_forwarded_for变量的"X-Forwarded-For"部分是空的,所以只有$remote_addr,而$remote_addr的值是用户的ip,于是赋值以后,X-Forwarded-For变量的值就是用户的真实的ip地址了。
26 
27 到了第二台nginx,使用
28 
29 proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
30 
31 现在的$proxy_add_x_forwarded_for变量,X-Forwarded-For部分包含的是用户的真实ip,$remote_addr部分的值是上一台nginx的ip地址,于是通过这个赋值以后现在的X-Forwarded-For的值就变成了“用户的真实ip,第一台nginx的ip”,这样就清楚了吧。
32 
33 最后我们看到还有一个$http_x_forwarded_for变量,这个变量就是X-Forwarded-For,由于之前我们说了,默认的这个X-Forwarded-For是为空的,所以当我们直接使用proxy_set_header            X-Forwarded-For $http_x_forwarded_for时会发现,web服务器端使用request.getAttribute("X-Forwarded-For")获得的值是null。如果想要通过request.getAttribute("X-Forwarded-For")获得用户ip,就必须先使用proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;这样就可以获得用户真实ip。
X-Forwarded-For解释

4、real server获取真实ip

了更方便的获取真实客户端IP,可以使用nginx http_realip_module模块解决,在安装nginx时通过–with-http_realip_module安装该模块。代理配置与刚刚一样。

后端real server配置为:

server {
        server_name     www.jcici.com;
        listen  80;

        access_log /home/nginx/logs/ceshi.access.log main;
        error_log /home/nginx/logs/ceshi.error.log;


        location /realip {
                default_type text/html;
                index index.html index.htm;
                echo "$remote_addr || $http_x_real_ip || $http_x_forwarded_for";
                set_real_ip_from 192.168.32.0/24;
                real_ip_header X-Forwarded-For;
                real_ip_recursive on;
        }
}

客户端访问

http://www.jcici.com/realip

输出结果为

192.168.29.7 || 192.168.29.7 || 192.168.29.7, 192.168.32.230, 192.168.32.231

(1)set_real_ip_from 是指接受从哪个信任前代理处获得真实用户ip。

(2)real_ip_header 是指从接收到报文的哪个http首部去获取前代理传送的用户ip。

(3)在real_ip_recursive 为on时:

  nginx会从右至左处理ip,在此例中set_real_ip_from 后面的192.168.32.0/24,表示在192.168.32.230以及192.168.32.231为我们机器的代理ip,是可以信任的,用户的真是ip是X-Forwarded-For中的第一个ip,即192.168.29.7

(4)在real_ip_recursive 为off时: 

  会获取第一个值为信任ip,即192.168.32.231。

(5)如果最后段的real server不单单只是想要获取$remote_addr 还想要获取X-Forwarded-For中的ip呢,那就需要在每级代理中加上proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for了。

 

 

 

posted @ 2018-04-27 16:21  jcici  阅读(874)  评论(0编辑  收藏  举报