外界流传的JAVA/PHP服务器端获取客户端IP都是这么取的:
伪代码:
1)ip = request.getHeader(”X-FORWARDED-FOR”)
可伪造,参考附录A
2)如果该值为空或数组长度为0或等于“unknown”,那么:
ip = request.getHeader(”Proxy-Client-IP”)
3)如果该值为空或数组长度为0或等于“unknown”,那么:
ip = request.getHeader(”WL-Proxy-Client-IP”)
4)如果该值
为空
或数组长度为0
或等于
“
unknown
”
,那么:
ip = request.getHeader(”HTTP_CLIENT_IP”)
可伪造
5)如果该值为空
或数组长度为0
或等于”unknown
“
,那么:
ip = request.getRemoteAddr()
可对于匿名代理服务器,可隐匿原始ip,参考附录B
之所以搞这么麻烦,是因为存在很多种网络结构,如 Nginx+Resin、Apache+WebLogic、Squid+Nginx。下面挨个儿讲一下。
郑昀:△
首先,明确一下,Nginx 配置一般如下所示:
location / {
proxy_pass http://yourdomain.com;
proxy_set_header Host \(host;<br><span style="color: #ff0000;"> proxy_set_header X-Real-IP \)remote_addr;
proxy_set_header X-Forwarded-For \(proxy_add_x_forwarded_for;</span><br> }</span></span></span></span></span></div> <div><span><span><span><span><span style="font-family: 'Microsoft Yahei';">注意看红色字体,这些配置与下面的闯关拿IP有关。</span></span></span></span></span></div> <div><span><span><span><span><span style="font-family: 'Microsoft Yahei';"> </span></span></span></span></span></div> <div><span><span><span><span><span style="font-family: 'Microsoft Yahei';">———————————————————————————————</span></span></span></span></span></div> <div> <div><strong>——第一关|X-Forwarded-For :背景——</strong></div> <div>这是一个 Squid 开发的字段,并非 RFC 标准。</div> <div>简称<strong>XFF 头</strong>,只有在通过了 HTTP 代理或者负载均衡服务器时才会添加该项。在 Squid 开发文档中可以找到该项的详细介绍。</div> <div>XFF 格式如下:</div> <div><span style="color: #0000ff;">X-Forwarded-For: client1, proxy1, proxy2</span></div> <div>可以看出,XFF 头信息可以有多个,中间用逗号分隔,第一项为真实的客户端ip,剩下的就是曾经经过的代理或负载均衡服务器的ip地址。</div> <div> </div> <div><strong>——第一关|X-Forwarded-For :场景=客户端--CDN--Nginx——</strong></div> <div> <div>当用户请求经过 CDN 后到达 Nginx 负载均衡服务器时,其 XFF 头信息应该为 “客户端IP,CDN的IP”。</div> <div>一般情况下CDN服务商出于自身安全考虑会将屏蔽CDN的ip,只保留客户端ip。</div> <div>那么请求头到达 Nginx 时:</div> <div> <ul> <li><span style="display: inline-block; background-color: yellow;">在默认情况下,Nginx 并不会对 XFF 头做任何处理</span></li> <ul> <li>此时 Nginx 后面的 Resin/Apache/Tomcat 通过 <span style="color: #000080;">request.getHeader("</span><span style="color: #ff0000;">X-FORWARDED-FOR</span><span style="color: #000080;">")</span> 获得的ip<strong>仍然是原始ip</strong>。</li> </ul> <li> <span style="display: inline-block; background-color: yellow;">当 Nginx 设置 X-Forwarded-For 等于 \)proxy_add_x_forwarded_for 时
:
proxy_pass http://yourdomain.com;
proxy_set_header Host \(host;<br><span style="color: #ff0000;"> proxy_set_header X-Real-IP \)remote_addr;
proxy_set_header X-Forwarded-For \(proxy_add_x_forwarded_for;</span><br> }</span></span></span></span></span></div> <div><span><span><span><span><span style="font-family: 'Microsoft Yahei';">注意看红色字体,这些配置与下面的闯关拿IP有关。</span></span></span></span></span></div> <div><span><span><span><span><span style="font-family: 'Microsoft Yahei';"> </span></span></span></span></span></div> <div><span><span><span><span><span style="font-family: 'Microsoft Yahei';">———————————————————————————————</span></span></span></span></span></div> <div> <div><strong>——第一关|X-Forwarded-For :背景——</strong></div> <div>这是一个 Squid 开发的字段,并非 RFC 标准。</div> <div>简称<strong>XFF 头</strong>,只有在通过了 HTTP 代理或者负载均衡服务器时才会添加该项。在 Squid 开发文档中可以找到该项的详细介绍。</div> <div>XFF 格式如下:</div> <div><span style="color: #0000ff;">X-Forwarded-For: client1, proxy1, proxy2</span></div> <div>可以看出,XFF 头信息可以有多个,中间用逗号分隔,第一项为真实的客户端ip,剩下的就是曾经经过的代理或负载均衡服务器的ip地址。</div> <div> </div> <div><strong>——第一关|X-Forwarded-For :场景=客户端--CDN--Nginx——</strong></div> <div> <div>当用户请求经过 CDN 后到达 Nginx 负载均衡服务器时,其 XFF 头信息应该为 “客户端IP,CDN的IP”。</div> <div>一般情况下CDN服务商出于自身安全考虑会将屏蔽CDN的ip,只保留客户端ip。</div> <div>那么请求头到达 Nginx 时:</div> <div> <ul> <li><span style="display: inline-block; background-color: yellow;">在默认情况下,Nginx 并不会对 XFF 头做任何处理</span></li> <ul> <li>此时 Nginx 后面的 Resin/Apache/Tomcat 通过 <span style="color: #000080;">request.getHeader("</span><span style="color: #ff0000;">X-FORWARDED-FOR</span><span style="color: #000080;">")</span> 获得的ip<strong>仍然是原始ip</strong>。</li> </ul> <li> <span style="display: inline-block; background-color: yellow;">当 Nginx 设置 X-Forwarded-For 等于 \)proxy_add_x_forwarded_for 时
:
- 如果从CDN过来的请求没有设置 XFF 头(通常这种事情不会发生),XFF 头为 CDN 的ip
- 此时相对于 Nginx 来说,客户端就是 CDN
- 如果 CDN 设置了 XFF 头,我们这里又设置了一次,且值为\(proxy_add_x_forwarded_for 的话:</li> <ul> <li> <strong>XFF 头为“客户端IP,Nginx负载均衡服务器IP”</strong>,这样取第一个值即可</li> <li><span style="color: #ff0000;"><strong>这也就是大家所常见的场景!</strong></span></li> </ul> </ul> </ul> </div> </div> </div> <blockquote> <div> <div><img alt="http://images.cnblogs.com/cnblogs_com/zhengyun_ustc//o_client-cdn-nginx-resin.png" class="decoded" src="http://images.cnblogs.com/cnblogs_com/zhengyun_ustc//o_client-cdn-nginx-resin.png"></div> </div> </blockquote> <div> <div>综上所述,XFF 头在上图的场景,Resin 通过 <span style="color: #000080;">request.getHeader("</span><span style="color: #ff0000;">X-FORWARDED-FOR</span><span style="color: #000080;">")</span> 获得的ip字符串,做一个split,第一个元素就是原始ip。</div> <div>那么,XFF 头可以伪造吗?</div> <div> </div> <div> <div><strong>——第一关|X-Forwarded-For :伪造——</strong></div> <div> <div><strong><span style="color: #ff0000;">可以伪造。</span></strong></div> <div>XFF 头仅仅是 HTTP Headers 中的一分子,自然是可以随意增删改的。如附录A所示。</div> </div> </div> <div>很多投票系统都有此漏洞,它们简单地取 XFF 头中定义的ip地址设置为来源地址,因此第三方可以伪造任何ip投票。</div> <div> </div> <div>———————————————————————————————</div> <div> <strong>——第二和第三关|Proxy-Client-IP/WL-</strong><strong>Proxy-Client-IP</strong><strong> :背景——</strong> </div> <div>Proxy-Client-IP 字段和 WL-Proxy-Client-IP 字段只在 Apache(Weblogic Plug-In Enable)+WebLogic 搭配下出现,其中“WL” 就是 WebLogic 的缩写。</div> <div>即访问路径是:</div> </div> <blockquote> <div> <div>Client -> Apache WebServer + Weblogic http plugin -> Weblogic Instances</div> </div> </blockquote> <div> <div>所以这两关对于我们来说仅仅是兼容而已,怕你突然把 Nginx+Resin 换成 Apache+WebLogic 。</div> <div>也可以直接忽略这两个字段。</div> <div> </div> <div> <div>———————————————————————————————</div> <div> <strong>——第四关|HTTP-Client-IP</strong><strong> :背景——</strong> </div> <div>HTTP_CLIENT_IP 是代理服务器发送的HTTP头。</div> <div>很多时候 Nginx 配置中也并没有下面这项:</div> </div> </div> <blockquote> <div> <div> <div>proxy_set_header HTTP_CLIENT_IP \)remote_addr;
所以本关也可以忽略。
郑昀:△
———————————————————————————————
——第五关| request.getRemoteAddr() :背景——
从 request.getRemoteAddr() 函数的定义看:
Returns the Internet Protocol (IP) address of the client or last proxy that sent the request.
实际上,REMOTE_ADDR 是客户端跟服务器“握手”时的IP,但如果使用了“匿名代理”,REMOTE_ADDR 将显示代理服务器的ip,或者最后一个代理服务器的ip。请参考附录B。
综上,
java/php 里拿到的ip地址可能是伪造的或代理服务器的ip。
郑昀:△
+++附录A XFF 与 Nginx 配置的测试用例+++
测试环境: nginx+resin
内网IP:172.16.100.10
客户端IP:123.123.123.123
测试页面: test.jsp
<%
out.println(“x-forwarded-for: ” + request.getHeader(“x-forwarded-for”));
out.println(“remote hosts: ” + request.getRemoteAddr());
%>
内网IP:172.16.100.10
客户端IP:123.123.123.123
测试页面: test.jsp
<%
out.println(“x-forwarded-for: ” + request.getHeader(“x-forwarded-for”));
out.println(“remote hosts: ” + request.getRemoteAddr());
%>
nginx 配置一proxy_set_header X-Real-IP \(remote_addr;</div> </div> <div> <div>proxy_set_header X-Forwarded-For \)proxy_add_x_forwarded_for;wget测试wget -O aa –header=“X-Forwarded-For:192.168.0.1” “ http://test.com/test.jsp”页面返回结果:x-forwarded-for: 192.168.0.1, 123.123.123.123remote hosts: 172.16.100.10curl测试curl -H “X-Forwarded-For:192.168.0.1” “ http://test.com/test.jsp”x-forwarded-for: 192.168.0.1, 123.123.123.123remote hosts: 172.16.100.10
nginx 配置二
proxy_set_header X-Real-IP \(remote_addr;<br>proxy_set_header X-Forwarded-For \)remote_addr;
proxy_set_header X-Forwarded-For \(proxy_add_x_forwarded_for;<br><br>wget测试:<br>wget -O aa --header="X-Forwarded-For:192.168.0.1" "http://test.com/test.jsp"<br>页面返回结果:<br>x-forwarded-for: 123.123.123.123<br>remote hosts: 172.16.100.10<br><br>curl测试<br>curl -H "X-Forwarded-For:192.168.0.1" "http://test.com/test.jsp"<br>x-forwarded-for: 123.123.123.123<br>remote hosts: 172.16.100.10<br><br>测试结果:<br>1、配置 </div> <div>proxy_set_header X-Forwarded-For \)proxy_add_x_forwarded_for;
增加了一个真实ip X-Forwarded-For,并且顺序是增加到了“后面”。
2、配置
proxy_set_header X-Forwarded-For $remote_addr;
清空了客户端伪造传入的X-Forwarded-For,
保证了使用 request.getHeader(“x-forwarded-for”) 获取的ip为真实ip,
或者用“,”分隔,截取 X-Forwarded-For 最后的值。
清空了客户端伪造传入的X-Forwarded-For,
保证了使用 request.getHeader(“x-forwarded-for”) 获取的ip为真实ip,
或者用“,”分隔,截取 X-Forwarded-For 最后的值。
+++附录B 搜狗浏览器高速模式的测试用例+++
访问路径:
搜狗浏览器“高速”模式(即使用代理)–>LVS–>Apache
获得的值为:
x-forwarded-for:180.70.92.43 (即真实ip)
Proxy-Client-IP:null
WL-Proxy-Client-IP:null
getRemoteAddr:123.126.50.185 (即搜狗代理ip)
×××参考资源:×××
1,http://bbs.linuxtone.org/thread-9050-1-1.html
2,http://hi.baidu.com/thinkinginlamp/item/e2cf05263eb4d18e6e2cc3e6
3,http://bbs.chinaunix.net/thread-3659453-1-1.html
转自:http://zhengyun-ustc.iteye.com/blog/

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/163799.html