转发:https://www.cnblogs.com/diaosir/p/6890825.html

在使用nginx做反向代理时,我们为了记录整个的代理过程,我们往往会在配置文件中做如下配置:

location / {
       省略...
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://1xx.xxx.xxx.xxx;
    
    }

红色部分就是为了记录代理过程做的配置,在http header中添加代理的信息,我们可以把X-Forwarded-For当成http扩展头,其格式一般为:

X-Forwarded-For:192.168.247.1, 192.168.247.131, 192.168.247.132

注意,引用X-Forwarded-For时要这样$http_x_forwarded_for

做一下测试

1.我们测试一下请求经过三层代理的情况,测试设备分配:

  • win10 一台
  • 运行在win10上的虚拟机centos5.8,ip:192.168.247.131,一级代理
  • 运行在win10上的虚拟机centos6-1, ip:192.168.247.132 ,二级代理
  • 运行在win10上的虚拟机centos6-2, ip:192.168.247.133 ,三级代理
  • 云服务器,应用服务器

2.测试环境配置:

  • win10 在/etc/hosts文件中添加192.168.247.131 http://test.proxy.com
  • centos5.8,ip:192.168.247.131,安装nginx,把所有请求转发到192.168.247.132
  • centos6-1, ip:192.168.247.132,安装nginx,把所有请求转发到192.168.247.133
  • centos6-2, ip:192.168.247.133,安装nginx,把所有请求转发到云服务器
  • 在云服务器上的日志中打印http header中的X-Forwarded-For信息
  • 防火墙可以关闭掉,防止win10请求无法进入代理链

3.nginx配置文件

#centos5.8,ip:192.168.247.131 ,nginx.conf
location / {root   html;index  index.html index.htm index.php;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass http://192.168.247.132;}
#centos6-1,ip:192.168.247.132 ,nginx.conflocation / {root   html;index  index.html index.htm index.php;#proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass http://192.168.247.133;} #centos6-2,ip:192.168.247.133 ,nginx.conflocation / {root   html;index  index.html index.htm index.php;  #proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass http://123.206.96.111;}
#云服务器方便起见在日志中设置打印$http_x_forwarded_for,进行观察log_format  main  '$http_x_forwarded_for|$http_x_real_ip|$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';

4.基于上面的配置在win10浏览器输入:"http://test.proxy.com" 查看云服务器日志打印结果如下:

192.168.247.1, 192.168.247.131, 192.168.247.132|192.168.247.1|101.254.182.6 - - [22/May/2017:18:20:27 +0800] "GET /admin/login/?next=%2Fadmin%2F HTTP/1.0" 200 623 "http://test.proxy.com/admin/login/?next=%2Fadmin%2F" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1, 192.168.247.131, 192.168.247.132"
192.168.247.1, 192.168.247.131, 192.168.247.132 为$http_x_forwarded_for内容,显然记录了代理过程,其中192.168.247.1是客户端ip
192.168.247.1 为基于上述设置的真实IP(不一定准确)
101.254.182.6 公网IP
作为重度强迫症患者,测试到这里可不是我的风格.....

我们要仔细测试一下在不同代理服务器设置X-FORWARDED-FOR在应用服务器拿到的$http_x_forwarded_for有何不同1.只在proxy01设置X-FORWARDED-FOR, 在proxy02,proxy03配置文件中注释掉proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;192.168.247.1|192.168.247.1|101.254.182.6 - - [22/May/2017:18:52:49 +0800] "GET /admin/login/?next=%2Fadmin%2F HTTP/1.0" 200 623 "http://test.proxy.com/admin/login/?next=%2Fadmin%2F" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1"2.只在proxy02设置X-FORWARDED-FOR, 在proxy01,proxy03配置文件中注释掉proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;192.168.247.131|192.168.247.1|101.254.182.6 - - [22/May/2017:18:59:59 +0800] "GET /admin/login/?next=%2Fadmin%2F HTTP/1.0" 200 623 "http://test.proxy.com/admin/login/?next=%2Fadmin%2F" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.131"3.只在proxy03设置X-FORWARDED-FOR, 在proxy01,proxy02配置文件中注释掉proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;192.168.247.132|192.168.247.1|101.254.182.6 - - [22/May/2017:19:01:27 +0800] "GET /admin/login/?next=%2Fadmin%2F HTTP/1.0" 200 623 "http://test.proxy.com/admin/login/?next=%2Fadmin%2F" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.132"4.只在proxy01,proxy03设置X-FORWARDED-FOR, 在proxy02配置文件中注释掉proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;192.168.247.1, 192.168.247.132|192.168.247.1|101.254.182.6 - - [22/May/2017:19:05:49 +0800] "GET /admin/login/?next=%2Fadmin%2F HTTP/1.0" 200 623 "http://test.proxy.com/admin/login/?next=%2Fadmin%2F" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1, 192.168.247.132"5.只在proxy02,proxy03设置X-FORWARDED-FOR, 在proxy01配置文件中注释掉proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;192.168.247.131, 192.168.247.132|192.168.247.1|101.254.182.6 - - [22/May/2017:19:08:39 +0800] "GET /admin/login/?next=%2Fadmin%2F HTTP/1.0" 200 623 "http://test.proxy.com/admin/login/?next=%2Fadmin%2F" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.131, 192.168.247.132"6.只在proxy01,proxy02设置X-FORWARDED-FOR, 在proxy03配置文件中注释掉proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;192.168.247.1, 192.168.247.131|192.168.247.1|101.254.182.6 - - [22/May/2017:19:10:40 +0800] "GET /admin/login/?next=%2Fadmin%2F HTTP/1.0" 200 623 "http://test.proxy.com/admin/login/?next=%2Fadmin%2F" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1, 192.168.247.131"小结:

1.通过以上几种情况我们可以了解到设置X-Forwarded-For是一个可叠加的过程,后面的代理会把前面代理的IP加入X-Forwarded-For,类似于python的列表append的作用.

2.我们看到在三层代理情况下无论如何设置,应用服务器不可能从$http_x_forwarded_for拿到与它直连的这台服务器的ip(proxy03 ip),此时我们可以使用$remote_addr(远程ip,表示直连的那台代理).一句话,当前服务器无法通过$http_x_forwarded_for获得上级代理或者客户端的ip,应该使用$remote_addr.

3.在代理过程中至少有一个代理设置了proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;否则后面代理或者应用服务器无法获得相关信息.

4.注意,应用服务器可以通过$proxy_add_x_forwarded_for客户端IP(只要至少proxy01代理设置了proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;我们取第一IP就好了),但是我们要考虑客户端伪造头部的情况,如下示例:

假设我们在所有代理都加上了proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;然后我们在proxy01机器上本机curl代替win10模拟一个客户端请求,

在proxy01上执行: curl localhost/admin -H 'X-Forwarded-For: 1.1.1.1' -H 'X-Real-IP: 2.2.2.2'

1.1.1.1, 127.0.0.1, 192.168.247.131, 192.168.247.132|127.0.0.1|101.254.182.6 - - [23/May/2017:11:02:09 +0800] "GET /admin HTTP/1.0" 301 263 "-" "curl/7.15.5 (i386-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5" "1.1.1.1, 127.0.0.1, 192.168.247.131, 192.168.247.132"

可以看到,1.1.1.1放到了最前面,所以我们不能够想当然的去取第一个ip作为客户端的这是IP.这里127.0.0.1是真实IP.

5.虽然X-Forwarded-For可以伪造,但是对我们依然有用,比如我们就从proxy01代理往后截取就行了,这样就能做到直接忽视伪造得IP.

X-Real-IP


下面我们看一下有多级代理存在时如何获取客户端真实IP.

首先要明确在header里面的 X-Real-IP只是一个变量,后面的设置会覆盖前面的设置(跟X-Forwarded-For的追加特性区别明显),所以我们一般只在第一个代理设置proxy_set_header X-Real-IP $remote_addr;就好了,然后再应用端直接引用$http_x_real_ip就行.

1.假如我们只在proxy01设置了 X-Real-IP

192.168.247.1, 192.168.247.131, 192.168.247.132|192.168.247.1|101.254.182.6 - - [23/May/2017:11:23:00 +0800] "GET /test/ HTTP/1.0" 200 9 "http://test.proxy.com/test/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1, 192.168.247.131, 192.168.247.132"

2.假如我们只在proxy02设置了X-Real-IP

192.168.247.1, 192.168.247.131, 192.168.247.132|192.168.247.131|101.254.182.6 - - [23/May/2017:11:26:22 +0800] "GET /test/ HTTP/1.0" 200 9 "http://test.proxy.com/test/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1, 192.168.247.131, 192.168.247.132"

3.假如我们只在proxy03设置了X-Real-IP

192.168.247.1, 192.168.247.131, 192.168.247.132|192.168.247.132|101.254.182.6 - - [23/May/2017:11:27:21 +0800] "GET /test/ HTTP/1.0" 200 9 "http://test.proxy.com/test/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1, 192.168.247.131, 192.168.247.132"

4.所有代理都设置X-Real-IP

192.168.247.1, 192.168.247.131, 192.168.247.132|192.168.247.132|101.254.182.6 - - [23/May/2017:11:29:09 +0800] "GET /test/ HTTP/1.0" 200 9 "http://test.proxy.com/test/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1, 192.168.247.131, 192.168.247.132"

5.强迫症来了,再试一个只设置proxy01,proxy02的看看

192.168.247.1, 192.168.247.131, 192.168.247.132|192.168.247.131|101.254.182.6 - - [23/May/2017:11:30:36 +0800] "GET /test/ HTTP/1.0" 200 9 "http://test.proxy.com/test/" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36" "192.168.247.1, 192.168.247.131, 192.168.247.132"

假如有人假冒X-Real-IP呢?

6. 在proxy01上执行: curl localhost/admin -H 'X-Forwarded-For: 1.1.1.1' -H 'X-Real-IP: xx.xx.xx.xx'

1.1.1.1, 127.0.0.1, 192.168.247.131, 192.168.247.132|192.168.247.131|101.254.182.6 - - [23/May/2017:11:36:02 +0800] "GET /admin HTTP/1.0" 301 263 "-" "curl/7.15.5 (i386-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5" "1.1.1.1, 127.0.0.1, 192.168.247.131, 192.168.247.132"

并没有影响.

HTTP 请求头中的 X-Forwarded-For,X-Real-IP(nginx)相关推荐

  1. Http 请求头中的 Proxy-Connection

    平时用 Chrome 开发者工具抓包时,经常会见到 Proxy-Connection 这个请求头.之前一直没去了解什么情况下会产生它,也没去了解它有什么含义.最近看完<HTTP 权威指南> ...

  2. HTTP 请求头中的 Remote_Addr,X-Forwarded-For,X-Real-IP

    REMOTE_ADDR 表示发出请求的远程主机的 IP 地址,remote_addr代表客户端的IP,但它的值不是由客户端提供的,而是服务端根据客户端的ip指定的,当你的浏览器访问某个网站时,假设中间 ...

  3. ajax被token拦截,vue中封装ajax请求,并且拦截请求在请求头中添加token

    /** * 封装请求方法 * @param {Object} url 接口请求地址 * @param {Object} data 接口请求参数(无需请求方式参数,则此项可以为空,否则必须传) * @p ...

  4. axios获取header中的信息_Axios请求头中常见的Content-Type及其使用

    Vue2.0之后,官方不再继续维护vue-resource,尤雨溪大大推荐使用Axios用来替代Ajax. Axios请求头中的Content-Type常见的有3种: 1.Content-Type:a ...

  5. mysqls压力测试怎么用_用 Swagger 测试接口,怎么在请求头中携带 Token?

    松哥周末抽空给 Spring Security 系列也录制了一套视频,目录如下: 感兴趣的小伙伴戳这里-->Spring Boot+Vue+微人事视频教程 今天的话题来自一个小伙伴在微信上的提问 ...

  6. oauth2 java 获取token_OAuth2 Token 一定要放在请求头中吗?

    Token 一定要放在请求头中吗? 答案肯定是否定的,本文将从源码的角度来分享一下 spring security oauth2 的解析过程,及其扩展点的应用场景. Token 解析过程说明 当我们使 ...

  7. 爬虫-在请求头中添加cookie键值对 访问登陆后可见的页面

    关于cookie >笔记 >理解 cookie相当于病人手里的病历 cookie的格式 请求头中添加cookie键值对 练习-不使用cookie访问个人中心 访问人人网个人中心 结果是得到 ...

  8. http请求头中Referer的含义和作用

    http请求头中Referer的含义和作用 别人写好了,链接过去看看吧,出门左转. 记得房号不迷路 02房 01房 三人行必有我师焉,其实两人行也有我师焉--

  9. 前后端分离项目,请求头中包含Authorizaton:XX,但是后端getHeader(Authorizaton) 获取不到

    前端请求头 后台校验 结果是 request = null: 原因是因为,在发起跨域请求时,会发送事先发送一个OPTIONS请求,可以在浏览器的NETWORK中看到发起了两个名字一样的请求. 第一个请 ...

  10. token放在cookie中和放在请求头中的区别

    token放在cookie中 和 放在请求 头中的区别 cookie中: 防止xss攻击,但是导致所有请求都会携带token 请求头中: 会有xss风险,而且前端需要保存token并在每次请求的时候携 ...

最新文章

  1. PCL基础4:PCLVisualizer可视化窗口显示
  2. Docker环境配置指南!
  3. 【控制】《多智能体系统的协同群集运动控制》陈杰老师-第8章-高阶非线性多智能体分布式自适应鲁棒控制
  4. Redis入门(二)安装和基本操作
  5. group by 的实现原理
  6. 数组 最大差值_数组两元素的最大差:从暴力到多线程
  7. Android系统(133)---Google Play Store无法搜索应用或提示应用不兼容,此类问题该如何定位及分析
  8. CentOS 6.5 yum安装配置lnmp服务器(Nginx+PHP+MySQL)
  9. linux git编译安装目录,Linux(centos) 环境下如何源码编译安装git
  10. (一)跟我一起玩Linux网络服务:DNS服务——BIND(/etc/named.conf、/var/named)设置实现和解释...
  11. cadz轴归零命令_CAD图形Z轴坐标归零方法
  12. C# TeeChart使用心得,干货
  13. 评选最佳文本编辑器-UltraEdit From善用佳软
  14. 查看局域网内所有的主机名、MAC地址和IP地址
  15. 【统计学习方法】EM算法原理
  16. strpos使用不当引发漏洞
  17. php cgi sapi
  18. android-smart-image-view图片加载简单使用
  19. 前端开发精华网站(强烈推荐!)
  20. memset()函数怎么用?

热门文章

  1. 综合素质计算机的知识考点,综合素质常识考题
  2. 端口号,UDP,TCP
  3. 专注UI——实用技术:模糊搜索
  4. 关于jquery.mloading加载loading效果
  5. vh布局移动端软键盘弹起改变高度问题
  6. lat_mem_rd 内存延迟测试工具原理,lmbench编译时llseek链接不到问题解决
  7. getElementById 用法的一个技巧
  8. java人民币大小写转换_Java 实现人民币小写转大写[转载http://sunjun.blogchina.com/]
  9. 在SQL中删除重复记录(多种方法) [转]
  10. JAVA AJAX教程第一章-初始AJAX