外界流传的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

X-FORWARDED-FOR的更多相关文章

  1. SQL Server中一个隐性的IO性能杀手-Forwarded record

    简介     最近在一个客户那里注意到一个计数器很高(Forwarded Records/Sec),伴随着间歇性的磁盘等待队列的波动.本篇文章分享什么是forwarded record,并从原理上谈一 ...

  2. [20140722] forwarded和forwarding记录

    背景: 今天被人文集forwarded和forwarding记录的事情. 简单介绍: 当堆表跟新某一个列的时候发现,不够放了,那么就在那行记录上标记forwarding,并把数据放到另外一个page, ...

  3. SQL Server 存储引擎-剖析Forwarded Records

    我们都知道数据在存储引擎中是以页的形式组织的,但数据页在不同的组织形式中其中对应的数据行存储是不尽相同的,这里通过实例为大家介绍下堆表的中特有的一种情形Forwared Records及处理方式. 概 ...

  4. Mac OS 使用 Vagrant 管理虚拟机(VirtualBox)

    Vagrant(官网.github)是一款构建虚拟开发环境的工具,支持 Window,Linux,Mac OS,Vagrant 中的 Boxes 概念类似于 Docker(实质是不同的),你可以把它看 ...

  5. npm 使用小结

    本文内容基于 npm 4.0.5 概述 npm (node package manager),即 node 包管理器.这里的 node 包就是指各种 javascript 库. npm 是随同 Nod ...

  6. Express 教程 01 - 入门教程之经典的Hello World

    目录: 前言 一.Express?纳尼?! 二.开始前的准备工作 三.测试安装之经典的Hello World 四.使用express(1)来生成一个应用程序 五.说明 前言: 本篇文章是建立在Node ...

  7. Fedora 24中的日志管理

    Introduction Log files are files that contain messages about the system, including the kernel, servi ...

  8. 使用packer制作vagrant centos box

    使用packer制作vagrant box:centos 制作vagrant box,网上有教程,可以自己step by step的操作.不过直接使用虚拟在VirtualBox中制作vagrant b ...

  9. Linux文本查看及处理.md

    cat cat命令的用途是连接文件或标准输入并打印.这个命令常用来显示文件内容,或者将几个文件连接起来显示,或者从标准输入读取内容并显示,它常与重定向符号配合使用. 主要功能 一次显示整个文件:cat ...

  10. sqlmap --dns-domain模拟实践

    因为看到乌云的这一篇文章 http://drop.xbclub.org/static/drops/tips-5283.html 里面的提到的用sqlmap 的--dns-domain 进行dns 注入 ...

随机推荐

  1. MySQL分支Percona,折腾中,先科普一下

    官方网站:http://www.percona.com/ Percona 为 MySQL 数据库服务器进行了改进,在功能和性能上较 MySQL 有着很显著的提升.该版本提升了在高负载情况下的 Inno ...

  2. Activity的学习

    安卓的四大组件分别是 Activity ,Service服务, BroadcastReceiver广播接收器,ContentProvide内容提供器 . Activity: Activity是应用程序 ...

  3. 洛谷 P1515 旅行

    P1515 旅行 题目描述 你要进行一个行程为7000KM的旅行,现在沿途有些汽车旅馆,为了安全起见,每天晚上都不开车,住在汽车旅馆,你手里现在已经有一个旅馆列表,用离起点的距离来标识,如下: 0, ...

  4. jquery mobile 复选框和单选框

    checkbox 和radio <!DOCTYPE html> <html> <head> <meta charset="utf-8"&g ...

  5. app.config动态修改及读取

    1.添加应用程序配置文件 右键点击项目,选择“添加”→“添加新建项”→“添加应用程序配置文件”将其添加到项目中. 2.设置配置文件 <?xmlversion="1.0"enc ...

  6. Axure自动幻灯片制作

    1.打开axure7,开始. 2.拖一个占位符组件到布局上(当然也可以是矩形.图片之类的),大小270*170,作为幻灯片的第一张片子,双击写上“第一张片子”. 3.拖一个矩形,设置形状为椭圆,调整大 ...

  7. PHP自定义弹出消息类,用于弹出提示信息并返回

    一个用PHP自写的弹出消息类,用于在程序出错时弹出提示,,弹出警告框,或在程序运行到某阶段的快捷提示,需用时只需传入参数即可,函数并不复杂,但觉得挺实用.具体代码: function Alert($a ...

  8. Python3 如何优雅地使用正则表达式(详解三)

    模块级别的函数 使用正则表达式也并非一定要创建模式对象,然后调用它的匹配方法.因为,re 模块同时还提供了一些全局函数,例如 match(),search(),findall(),sub() 等等.这 ...

  9. MMDrawerController 使用遇到的问题及定制

    MMDrawerController 1,集成UIViewController * leftDrawer = [[UIViewController alloc] init]; UIViewContro ...

  10. Swift—静态方法-备

    静态方法与静态属性类似,Swift中定义了静态方法,也称为类型方法.静态方法的定义与静态属性类似,枚举和结构体的静态方法使用的关键字是static:类静态方法使用的关键字是class或static,如 ...