PHP-客户端的IP地址伪造、CDN、反向代理、获取的那些事儿

外界流传的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;
                       proxy_set_header   X-Real-IP        $remote_addr;
                       proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
              }

注意看红色字体,这些配置与下面的闯关拿IP有关。

———————————————————————————————

——第一关|X-Forwarded-For :背景——

这是一个 Squid 开发的字段,并非 RFC 标准。

简称 XFF 头,只有在通过了 HTTP 代理或者负载均衡服务器时才会添加该项。在 Squid 开发文档中可以找到该项的详细介绍。

XFF 格式如下:

X-Forwarded-For: client1, proxy1, proxy2

可以看出,XFF 头信息可以有多个,中间用逗号分隔,第一项为真实的客户端ip,剩下的就是曾经经过的代理或负载均衡服务器的ip地址。

——第一关|X-Forwarded-For :场景=客户端--CDN--Nginx——

当用户请求经过 CDN 后到达 Nginx 负载均衡服务器时,其 XFF 头信息应该为 “客户端IP,CDN的IP”。

一般情况下CDN服务商出于自身安全考虑会将屏蔽CDN的ip,只保留客户端ip。

那么请求头到达 Nginx 时:

  • 在默认情况下,Nginx 并不会对 XFF 头做任何处理
    • 此时 Nginx 后面的 Resin/Apache/Tomcat 通过 request.getHeader("X-FORWARDED-FOR") 获得的ip仍然是原始ip
  • 当 Nginx 设置 X-Forwarded-For 等于 $proxy_add_x_forwarded_for 时:
    • 如果从CDN过来的请求没有设置 XFF 头(通常这种事情不会发生),XFF 头为 CDN 的ip
      • 此时相对于 Nginx 来说,客户端就是 CDN
    • 如果 CDN 设置了 XFF 头,我们这里又设置了一次,且值为$proxy_add_x_forwarded_for 的话:
      • XFF 头为“客户端IP,Nginx负载均衡服务器IP”,这样取第一个值即可
      • 这也就是大家所常见的场景!

综上所述,XFF 头在上图的场景,Resin 通过 request.getHeader("X-FORWARDED-FOR") 获得的ip字符串,做一个split,第一个元素就是原始ip。

那么,XFF 头可以伪造吗?

——第一关|X-Forwarded-For :伪造——

可以伪造。

XFF 头仅仅是 HTTP Headers 中的一分子,自然是可以随意增删改的。如附录A所示。

很多投票系统都有此漏洞,它们简单地取 XFF 头中定义的ip地址设置为来源地址,因此第三方可以伪造任何ip投票。

———————————————————————————————

——第二和第三关|Proxy-Client-IP/WL-Proxy-Client-IP :背景——

Proxy-Client-IP 字段和 WL-Proxy-Client-IP 字段只在 Apache(Weblogic Plug-In Enable)+WebLogic 搭配下出现,其中“WL” 就是 WebLogic 的缩写。

即访问路径是:

Client -> Apache WebServer + Weblogic http plugin -> Weblogic Instances

所以这两关对于我们来说仅仅是兼容而已,怕你突然把 Nginx+Resin 换成 Apache+WebLogic 。

也可以直接忽略这两个字段。

———————————————————————————————

——第四关|HTTP-Client-IP :背景——

HTTP_CLIENT_IP 是代理服务器发送的HTTP头。

很多时候 Nginx 配置中也并没有下面这项:

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());
%>

nginx 配置一

proxy_set_header X-Real-IP $remote_addr;

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.123

remote hosts: 172.16.100.10

curl测试

curl -H "X-Forwarded-For:192.168.0.1" "http://test.com/test.jsp"

x-forwarded-for: 192.168.0.1, 123.123.123.123

remote hosts: 172.16.100.10

nginx 配置二
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
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: 123.123.123.123
remote hosts: 172.16.100.10

curl测试
curl -H "X-Forwarded-For:192.168.0.1" "http://test.com/test.jsp"
x-forwarded-for: 123.123.123.123
remote hosts: 172.16.100.10

测试结果:
1、配置

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 最后的值。

+++附录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://www.cnblogs.com/zhengyun_ustc/archive/2012/09/19/getremoteaddr.html

时间: 2024-10-10 22:39:52

PHP-客户端的IP地址伪造、CDN、反向代理、获取的那些事儿的相关文章

HTTP中ip地址伪造的问题以及解决办法

在真实环境下,php获取客户端ip地址的方法通常有以下几种: (1):通过$_SERVER[ "HTTP_CLIENT_IP" ] (2):通过$_SERVER[ "HTTP_X_FORWARDED_FOR" ] (3):通过$_SERVER[ "REMOTE_ADDR" ] 这里需要注意的是:在php中的$_SERVER数组中以HTTP开头的值,都是由客户端(client)传递到服务端的,也就是说这一部分是可以进行伪造的.而$_SERVER[

获取客户端的ip地址与mac地址总结

最近刚完成的一个模块中,需要获取系统客户端的IP地址与物理地址(MAC地址). 1. 获取的本机IP与MAC是服务器的,而非客户端的→_→ 通过JAVA获取,本机的IP地址与MAC地址,使用如下代码即可完成: package com.howin.util; import java.net.*; public class Ipconfig { public static void main(String[] args) throws Exception { // TODO Auto-generat

获取客户端真实IP地址

1.需要引入log4j-1.2.14.jar package org.ydd.test; import java.util.Enumeration; import javax.servlet.http.HttpServletRequest; import org.apache.log4j.Logger; /** * @author coco * @version * 获取IP4 */ public class IP4 { private static final Logger log = Log

获取客户端的IP地址

/// <summary> /// 获取客户端的IP地址 /// </summary> /// <returns></returns> public static string ClientIP() { string result = String.Empty; result = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (result

服务器端获取客户端的IP地址(当客户端调用由Axis开发的WebService)

一.前言 由于项目中一个小的模块需要获取客户端的IP地址以保证安全调用webservice接口,项目中客户端使用C#编写,服务器端使用Java编写,服务器端与客户端采用Axis开发的WebService进行通信.服务器端维护IP白名单列表,只有IP地址在白名单中的客户端才可以成功调用到接口,获得服务. 二.代码清单 若要成功获取客户端IP地址,需要如下Jar包的支持. servlet-api.jar axis.jar axis2-kernel-1.6.2.jar 获取IP地址的具体代码如下: i

asp网络编程:ASP如何获取客户端真实IP地址

要想透过代理服务器取得客户端的真实IP地址,就要使用 Request.ServerVariables("HTTP_X_FORWARDED_FOR") 来读取.不过要注意的事,并不是每个代理服务器都能用 Request.ServerVariables("HTTP_X_FORWARDED_FOR") 来读取客户端的真实 IP,有些用此方法读取到的仍然是代理服务器的IP.还有一点需要注意的是:如果客户端没有通过代理服务器来访问,那么用 Request.ServerVari

使用SEP禁止客户端修改IP地址 - 飞舞的菜刀 - 51CTO技术博客

1.首先从注册表中搜寻 IP地址所在的位置,查到几项,此项即可: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces 2.打开[应用程序与设备控制]界面,单击[添加],新建一个策略,填写相应的"名称":如下图 2.点击[应用程序控制],[添加],输入规则集名字.在[将此规则应用于下列进程]右边单击[添加] 输入"*",在[请勿将此规则应用于下列程序],添加输

socket.io获取客户端的IP地址(修正官方1.0.4版本BUG)

之前我有看过别人写的文章,说到如何获取客户端IP地址,代码如下: var io = require("socket.io").listen(server); io.sockets.on("connection", function (socket) { var address = socket.handshake.address; console.log("New connection from " + address.address + &qu

java获取客户端请求ip地址

public static String getIpAddr(HttpServletRequest request) { if (null == request) { return null; } String proxs[] = { "X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWAR

ASP.NET - 获得客户端的 IP 地址

通常我们都通过下面的代码获得IP: REMOTE_ADDR 说明:访问客户端的 IP 地址. 此项信息用户不可以修改.如果真的给改了的话,你也和服务器连接不了了,服务器就是按照这个来与客户端建立连接并进行通讯的.实际我测试修改这个 ServerVariables , 一点效果都没有.仍然获得是实际的值. string ip =System.Web.HttpContext.Current.Request.UserHostAddress; string ip =System.Web.HttpCont