• 取客户端IP的那些事


      1 外界流传的JAVA/PHP服务器端获取客户端IP都是这么取的:
      2 伪代码:
      3 1)ip = request.getHeader("X-FORWARDED-FOR")
      4     可伪造,参考附录A
      5 2)如果该值为空或数组长度为0或等于"unknown",那么:
      6 ip = request.getHeader("Proxy-Client-IP")
      7 3)如果该值为空或数组长度为0或等于"unknown",那么:
      8 ip = request.getHeader("WL-Proxy-Client-IP")
      9 4)如果该值为空或数组长度为0或等于"unknown",那么:
     10 ip = request.getHeader("HTTP_CLIENT_IP")
     11     可伪造
     12 5)如果该值为空或数组长度为0或等于"unknown",那么:
     13 ip = request.getRemoteAddr()
     14     可对于匿名代理服务器,可隐匿原始ip,参考附录B
     15  
     16 之所以搞这么麻烦,是因为存在很多种网络结构,如 Nginx+Resin、Apache+WebLogic、Squid+Nginx。下面挨个儿讲一下。
     17 郑昀 :△
     18 首先,明确一下,Nginx 配置一般如下所示:
     19               location / {
     20                        proxy_pass       http://yourdomain.com;
     21                        proxy_set_header   Host             $host;
     22                        proxy_set_header   X-Real-IP        $remote_addr;
     23                        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
     24               }
     25 注意看红色字体,这些配置与下面的闯关拿IP有关。
     26  
     27 ———————————————————————————————
     28 ——第一关|X-Forwarded-For :背景——
     29 这是一个 Squid 开发的字段,并非 RFC 标准。
     30 简称 XFF 头,只有在通过了 HTTP 代理或者负载均衡服务器时才会添加该项。在 Squid 开发文档中可以找到该项的详细介绍。
     31 XFF 格式如下:
     32 X-Forwarded-For: client1, proxy1, proxy2
     33 可以看出,XFF 头信息可以有多个,中间用逗号分隔,第一项为真实的客户端ip,剩下的就是曾经经过的代理或负载均衡服务器的ip地址。
     34  
     35 ——第一关|X-Forwarded-For :场景=客户端--CDN--Nginx——
     36 当用户请求经过 CDN 后到达 Nginx 负载均衡服务器时,其 XFF 头信息应该为 “客户端IP,CDN的IP”。
     37 一般情况下CDN服务商出于自身安全考虑会将屏蔽CDN的ip,只保留客户端ip。
     38 那么请求头到达 Nginx 时:
     39 
     40     * 在默认情况下,Nginx 并不会对 XFF 头做任何处理
     41     * 
     42         * 此时 Nginx 后面的 Resin/Apache/Tomcat 通过 request.getHeader("X-FORWARDED-FOR") 获得的ip仍然是原始ip。
     43 
     44     * 当 Nginx 设置 X-Forwarded-For 等于 $proxy_add_x_forwarded_for 时:
     45     * 
     46         * 如果从CDN过来的请求没有设置 XFF 头(通常这种事情不会发生),XFF 头为 CDN 的ip
     47         * 
     48             * 此时相对于 Nginx 来说,客户端就是 CDN 
     49 
     50         * 如果 CDN 设置了 XFF 头,我们这里又设置了一次,且值为$proxy_add_x_forwarded_for 的话:
     51         * 
     52             * XFF 头为“客户端IP,Nginx负载均衡服务器IP”,这样取第一个值即可
     53             * 这也就是大家所常见的场景!
     54 
     55 
     56 
     57 综上所述,XFF 头在上图的场景,Resin 通过 request.getHeader("X-FORWARDED-FOR") 获得的ip字符串,做一个split,第一个元素就是原始ip。
     58 那么,XFF 头可以伪造吗?
     59  
     60 ——第一关|X-Forwarded-For :伪造——
     61 可以伪造。
     62 XFF 头仅仅是 HTTP Headers 中的一分子,自然是可以随意增删改的。如附录A所示。
     63 很多投票系统都有此漏洞,它们简单地取 XFF 头中定义的ip地址设置为来源地址,因此第三方可以伪造任何ip投票。
     64  
     65 ———————————————————————————————
     66 ——第二和第三关|Proxy-Client-IP/WL-Proxy-Client-IP :背景——
     67 Proxy-Client-IP 字段和 WL-Proxy-Client-IP 字段只在 Apache(Weblogic Plug-In Enable)+WebLogic 搭配下出现,其中“WL” 就是 WebLogic 的缩写。
     68 即访问路径是:
     69 Client -> Apache WebServer + Weblogic http plugin -> Weblogic Instances
     70 所以这两关对于我们来说仅仅是兼容而已,怕你突然把 Nginx+Resin 换成 Apache+WebLogic 。
     71 也可以直接忽略这两个字段。
     72  
     73 ———————————————————————————————
     74 ——第四关|HTTP-Client-IP :背景——
     75 HTTP_CLIENT_IP 是代理服务器发送的HTTP头。
     76 很多时候 Nginx 配置中也并没有下面这项:
     77 proxy_set_header HTTP_CLIENT_IP $remote_addr;
     78 所以本关也可以忽略。
     79 郑昀 :△
     80 ———————————————————————————————
     81 ——第五关| request.getRemoteAddr() :背景——
     82 从 request.getRemoteAddr() 函数的定义看:
     83     Returns the Internet Protocol (IP) address of the client or last proxy that sent the request. 
     84 实际上,REMOTE_ADDR 是客户端跟服务器“握手”时的IP,但如果使用了“匿名代理”,REMOTE_ADDR 将显示代理服务器的ip,或者最后一个代理服务器的ip。请参考附录B。 
     85  
     86 综上,
     87 java/php 里拿到的ip地址可能是伪造的或代理服务器的ip。
     88  
     89 郑昀 :△
     90 +++附录A XFF 与 Nginx 配置的测试用例+++
     91 测试环境: nginx+resin
     92 内网IP:172.16.100.10
     93 客户端IP:123.123.123.123
     94 
     95 测试页面: test.jsp
     96 <%
     97 out.println("x-forwarded-for: " + request.getHeader("x-forwarded-for"));
     98 out.println("remote hosts: " + request.getRemoteAddr());
     99 %>
    100 
    101 nginx 配置一
    102 proxy_set_header X-Real-IP $remote_addr;
    103 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    104  
    105 wget测试
    106 wget -O aa --header="X-Forwarded-For:192.168.0.1" "http://test.com/test.jsp"
    107 页面返回结果:
    108 x-forwarded-for: 192.168.0.1, 123.123.123.123
    109 remote hosts: 172.16.100.10
    110  
    111 curl测试
    112 curl -H "X-Forwarded-For:192.168.0.1" "http://test.com/test.jsp"
    113 x-forwarded-for: 192.168.0.1, 123.123.123.123
    114 remote hosts: 172.16.100.10
    115 
    116 nginx 配置二
    117 proxy_set_header X-Real-IP $remote_addr;
    118 proxy_set_header X-Forwarded-For $remote_addr;
    119 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    120 
    121 wget测试:
    122 wget -O aa --header="X-Forwarded-For:192.168.0.1" "http://test.com/test.jsp"
    123 页面返回结果:
    124 x-forwarded-for: 123.123.123.123
    125 remote hosts: 172.16.100.10
    126 
    127 curl测试
    128 curl -H "X-Forwarded-For:192.168.0.1" "http://test.com/test.jsp"
    129 x-forwarded-for: 123.123.123.123
    130 remote hosts: 172.16.100.10
    131 
    132 测试结果:
    133 1、配置  
    134 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    135 增加了一个真实ip X-Forwarded-For,并且顺序是增加到了“后面”。
    136 
    137 2、配置  
    138 proxy_set_header X-Forwarded-For $remote_addr;
    139 清空了客户端伪造传入的X-Forwarded-For,
    140 保证了使用 request.getHeader("x-forwarded-for") 获取的ip为真实ip,
    141 或者用“,”分隔,截取 X-Forwarded-For 最后的值。
    142  
    143 +++附录B 搜狗浏览器高速模式的测试用例+++
    144 访问路径:
    145 搜狗浏览器“高速”模式(即使用代理)-->LVS-->Apache
    146 获得的值为:
    147 x-forwarded-for:180.70.92.43   (即真实ip)
    148 Proxy-Client-IP:null
    149 WL-Proxy-Client-IP:null 
    150 getRemoteAddr:123.126.50.185  (即搜狗代理ip)
    151  
    152  
    153 ×××参考资源:×××
    154 1,http://bbs.linuxtone.org/thread-9050-1-1.html
    155 2,http://hi.baidu.com/thinkinginlamp/item/e2cf05263eb4d18e6e2cc3e6
    156 3,http://bbs.chinaunix.net/thread-3659453-1-1.html
    157 
    158 
    159 
    160 
    161 
    162 转自:http://www.cnblogs.com/zhengyun_ustc/archive/2012/09/19/getremoteaddr.html
  • 相关阅读:
    SQL UNION 和 UNION ALL 操作符
    JavaScript--验证码随机生成
    C#基础 out和ref
    远程连接身份验证错误,又找不到加密Oracle修正
    ASP.Net WebAPI -- 简单实现增删改查
    SpringBoot发送邮箱验证码
    VMware虚拟机安装Linux系统详细教程
    SpringBoot实现登陆拦截
    JavaScript 实例、构造函数、原型对象关系图
    JavaScript创建对象的几种方式总结
  • 原文地址:https://www.cnblogs.com/live365wang/p/2940005.html
Copyright © 2020-2023  润新知