原文:http://zhangxugg-163-com.iteye.com/blog/1663687

构造 HTTP请求 Header 实现“伪造来源 IP ”

在阅读本文前,大家要有一个概念,在实现正常的TCP/IP 双方通信情况下,是无法伪造来源 IP 的,也就是说,在 TCP/IP 协议中,可以伪造数据包来源 IP ,但这会让发送出去的数据包有去无回,无法实现正常的通信。这就像我们给对方写信时,如果写出错误的发信人地址,而收信人按信封上的发信人地址回信时,原发信人是无法收到回信的。

一些DDoS 攻击,如 SYN flood,  就是利用了 TCP/ip 的此缺陷而实现攻击的。《计算机网络》教材一书上,对这种行为定义为“发射出去就不管”。

因此,本文标题中的伪造来源IP 是带引号的。并非是所有 HTTP 应用程序中存在此漏洞。

那么在HTTP 中, " 伪造来源 IP",  又是如何造成的?如何防御之?

在理解这个原理之前,读者有必要对HTTP 协议有所了解。 HTTP 是一个应用层协议,基于请求 / 响应模型。客户端(往往是浏览器)请求与服务器端响应一一对应。

请求信息由请求头和请求正文构成(在GET 请求时,可视请求正文为空)。请求头类似我们写信时信封上的基本信息,对于描述本次请求的一些双方约定。而请求正文就类似于信件的正文。服务器的响应格式,也是类似的,由响应头信息和响应正文构成。

为了解这个原理,可使用Firefox Firebug,  或 IE 浏览器插件 HTTPwatch 来跟踪 HTTP 请求 / 响应数据。

本文中,以HTTPwatch 为例说明之。安装 httpwatch 并重启 IE 浏览器后, IE 的工具栏上出现其图标,点击并运行 Httpwatch,  就会在浏览器下方显示出 HTTPWatch 的主界面。

点击左下角红色的“Record ”按钮,并在地址栏输入 www.baidu.com,  等页面打开后,选中一个请求,并在下方的 tab 按钮中选择“ Stream ”,如图:

左边即是请求数据,右边即是服务器响应数据。左边的请求头均以回车换行结束,即“\r\n ” ,  最后是一个空行(内容为 \r\n ) , 表示请求 header 结束。而请求 header 中除第一行外,其它行均由 header 名称, header 值组成,如  Accept-Encoding: gzip, deflate , header 名称与值之间有冒号相隔,之间的空格是可有可无的。

那么,在HTTP 应用程序中,如何取得指定的请求 header 信息呢?这里使用 PHP 语言为例说明。对所有客户端请求 header, PHP 程序中取得其值的方式如下: 
$_SERVER['HTTP_ HEADER_NAME ']

HEADER_NAME应该以换成对应的 header 名称,此项的规律是:全大写,连接线变成下划线。比如要取得客户端的User-Agent 请求头,则使用 $_SERVER['HTTP_USER_AGENT'],  掌握这个规律,即可达到举一反三的效果。如要取得 COOKIE 信息,则使用 $_SERVER['HTTP_COOKIE'] 即可。也就是说, $_SERVER 数组中,以 HTTP开头的项均属于客户端发出的信息。

回归到HTTP 应用程序层,来源 IP 的重要性不言而语,例如表单提交限制,频率等等均需要客户端 IP 信息。使用流行的 Discuz X2.5  的文件 source/class/discuz/discuz_application.php 中的代码片断:

private function _get_client_ip() {

$ip = $_SERVER['REMOTE_ADDR'];

if (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {

$ip = $_SERVER['HTTP_CLIENT_IP'];

如以下的JSP代码片段:
public String getIpAddr(HttpServletRequest request) {
       String ip = request.getHeader("x-forwarded-for");
       if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
          ip = request.getHeader("Proxy-Client-IP");
       }
       if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
          ip = request.getHeader("WL-Proxy-Client-IP");
       }
       if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
          ip = request.getRemoteAddr();
       }
       return ip;
}

以上代码片段即是获取客户端IP ,这段程序会尝试检查 HTTP_CLIENT_IP, HTTP_X_FORWARDED_FOR,  根据之前的原理说明,以 HTTP_ 开头的 header,  均属于客户端发送的内容。那么,如果客户端伪造 Client-Ip, X-Forward-For ,不就可以欺骗此程序,达到“伪造 IP ”之目的?

那么如何伪造这项值?如果你会写程序,并了解HTTP 协议,直接伪造请求 header 即可。或者使用 Firefox 的Moify Headers 插件即可。

按图示顺序号输入或点击相应按钮。Start 按钮这里变为红色 Stop ,说明设置成功。

这时,如果我们使用Firefox 访问其它网站,网站服务器就针接收到我们伪造的 X-Forward-For,  值为 1.1.1.1 。

严格意义上讲,这并不是程序中的漏洞。Discuz 为了保持较好的环境兼容性 ( 包含有反向代理的 web 服务器环境,如 nginx 作为 php fastcgi 的前端代理 ) ,如此处理是可以理解的。那么如何处理,才能杜绝这个问题呢?

服务器重新配置X-Forward-For 为正确的值。

如对典型的nginx + php fastcgi 环境( nginx 与 php fastcgi 是否位于同一机器,并不妨碍此问题的产生) , nginx和 php fastcig 进程直接通信:

切记,$_SERVER['REMOTE_ADDR']  是由 nginx 传递给 php 的参数,就代表了与当前 nginx 直接通信的客户端的 IP (是不能伪造的)。

再比如,存在中间层代理服务器的环境:

这种情况下,后端的HTTP 文件服务器上获取取的 REMOTE_ADDR 永远是前端的 squid/varnish cache 服务器的通信 IP 。

服务器集群之间的通信,是可以信任的。我们要做的就是在离用户最近的前端代理上,强制设定X-Forward-For 的值,后端所有机器不作任何设置,直接信任并使用前端机器传递过来的 X-Forward-For 值即可。

即在最前端的Nginx 上设置:

location  ~  ^/static {

proxy_pass  ....;

proxy_set_header X-Forward-For $remote_addr ;

}

如果最前端(与用户直接通信)代理服务器是与php fastcgi 直接通信,则需要在其上设定:

location ~ "\.+\.php$" {

fastcgi_pass localhost:9000;

fastcgi_param  HTTP_X_FORWARD_FOR  $remote_addr;

}

记住,$remote_addr 是 nginx 的内置变量,代表了客户端真实(网络传输层) IP 。通过此项措施,强行将 X-Forward-For 设置为客户端 ip,  使客户端无法通过本文所述方式“伪造 IP ”。

LVS转发环境下,是否存在此问题?

LVS工作在网络层,不改变来源及目标 IP ,更不可能更改应用层信息,故不存在此问题。如果有任何疑惑或需要帮助,请联系笔者信箱 zhangxugg@163.com。

存在此问题的程序:

所有版本的discuz, phpcms, phpwind, dedeCMS 。以及其它可能未知的程序。

例如使用Modify Headers 进行 IP 伪装之后再登录 bbs.phpchina.com ,我们查看自己的个人资料中的“上次访问IP ”就发现就是我们伪装的数据。

可以说,互联网上存在此漏洞的网站实在是太多了。试试便知。那么对于存在此漏洞,并且使用IP 作限制的网站,一定要小心。

构造HTTP请求Header实现“伪造来源IP”(转)的更多相关文章

  1. 构造HTTP请求Header实现"伪造来源IP"

    构造 HTTP请求 Header 实现“伪造来源 IP ” 在阅读本文前,大家要有一个概念,在实现正常的TCP/IP 双方通信情况下,是无法伪造来源 IP 的,也就是说,在 TCP/IP 协议中,可以 ...

  2. 【转】构造HTTP请求Header实现“伪造来源IP”

    构造 HTTP请求 Header 实现“伪造来源 IP ” 在阅读本文前,大家要有一个概念,在实现正常的TCP/IP 双方通信情况下,是无法伪造来源 IP 的,也就是说,在 TCP/IP 协议中,可以 ...

  3. 构造HTTP请求Header实现“伪造来源IP”

    在阅读本文前,大家要有一个概念,在实现正常的TCP/IP 双方通信情况下,是无法伪造来源 IP 的,也就是说,在 TCP/IP 协议中,可以伪造数据包来源 IP ,但这会让发送出去的数据包有去无回,无 ...

  4. 转:造HTTP请求Header实现“伪造来源IP”

    构造 HTTP请求 Header 实现“伪造来源 IP ” 在阅读本文前,大家要有一个概念,在实现正常的TCP/IP 双方通信情况下,是无法伪造来源 IP 的,也就是说,在 TCP/IP 协议中,可以 ...

  5. php curl伪造来源ip和refer实例代码

    php curl伪造来源ip和来路refer实例代码1: //随机IP function Rand_IP(){ $ip2id= round(rand(600000, 2550000) / 10000) ...

  6. PHP用curl抓取网站数据,仿造IP、伪造来源等,防屏蔽解决方案教程

    1.伪造客户端IP地址,伪造访问referer:(一般情况下这就可以访问到数据了) curl_setopt($curl, CURLOPT_HTTPHEADER, ['X-FORWARDED-FOR:1 ...

  7. java nginx等代理或网关转发请求后获取客户端的ip地址,原理

    在没有网关或者反向代理软件情况下,java里获取客户端ip地址的方法是request.getRemoteAddr() 先解释下http协议和TCP协议: 网页默认是进行http连接了,http协议即超 ...

  8. 用Python构造ARP请求、扫描、欺骗

    目录 0. ARP介绍 1. Scapy简述 2. Scapy简单演示 2.1 安装 2.2 构造包演示 2.2.1 进入kamene交互界面 2.2.2 查看以太网头部 2.2.3 查看 ICMP ...

  9. 利用X-Forwarded-For伪造客户端IP漏洞成因及防范

    内容转载自叉叉哥https://blog.csdn.net/xiao__gui/article/details/83054462 问题背景 在Web应用开发中,经常会需要获取客户端IP地址.一个典型的 ...

随机推荐

  1. otunnel : 一个和lcx差不多的端口转发的工具

    项目地址 ooclab/otunnel 下载地址(内涵各大平台) http://dl.ooclab.com/otunnel/ otunnel 用法 前提: 1. 假设 server 的地址为 exam ...

  2. [ATL/WTL]_[中级]_[保存CBitmap到文件-保存屏幕内容到文件]

    场景: 1. 在做图片处理时,比方放大后或加特效后须要保存CBitmap(HBITMAP)到文件. 2.截取屏幕内容到文件时. 3.不须要增加第3方库时. 说明: 这段代码部分来自网上.第一次学atl ...

  3. Linux使用expect实现自动登录的脚本

    前提条件服务器已经安装过tcl和expect, 若未安装:可以先执行 yum  install tcl  expect  进行安装 第一步.编写以下自动登录脚本login.sh ########### ...

  4. 帝国cms目录结构

    / 系统根目录├d/         附件和数据存放目录 (data) │├file/    附件存放目录 │├js/       JS调用生成目录 │└txt/        内容存文本存放目录 ├ ...

  5. android开发源代码分析--多个activity调用多个jni库的方法

    android开发源代码分析--多个activity调用多个jni库的方法 有时候,我们在开发android项目时会遇到须要调用多个native c/jni库文件,下面是本人以前实现过的方法,假设有知 ...

  6. JavaScript------自定义string.replaceAll()方法

    代码:: 注意:原始的replace()方法只能替换第一个字符串check String.prototype.replaceAll = function (s1, s2) { return this. ...

  7. POJ 2392 Space Elevator(多重背包变形)

    Q: 额外添加了最大高度限制, 需要根据 alt 对数据进行预处理么? A: 是的, 需要根据 alt 对数组排序 Description The cows are going to space! T ...

  8. 处理unsigned相减错误(BIGINT UNSIGNED value is out of range)

    mysql 当两个字段想减时,如果其中一个或两个字段的类型的unsigned无签名类型,如果想减的值小于0则会报错(BIGINT UNSIGNED value is out of range) 测试: ...

  9. UE4修改自Rama的UDP通信蓝图插件

    UE4.15没有提供蓝图UDP的组件,可以在网上找到一个ID叫Rama写的源代码,我把它封装成插件了(MyUdpPlugin),方便在各个UE4版本工程中使用UDP通信. 使用方式: 1.在自己的工程 ...

  10. 解决wamp、vertrigo等集成环境安装后apache不能启动的问题

    如果不是端口的问题,通常就是由于缺少vc库文件的支持,把vc2005.vc2008.vc2010抖安装一遍就呢过解决问题