构造 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 作限制的网站,一定要小心。
相关推荐
curl虽然功能强大,但是只能伪造$_SERVER[“HTTP_X_FORWARDED_FOR”],对于大多数IP地址检测程序来说,$_SERVER[“REMOTE_ADDR”]很难被伪造: 首先是client.php的代码 复制代码 代码如下: $headers[‘CLIENT-IP’] ...
2.2、针对NSURLSessionConfiguration设置代理IP和端口,让一些特殊的请求走自定义的隧道IP和端口 2.3、对网络请求的数据进行报文级别的加密:使用NSURLProtocol来自动监听HTTP请求并加密解密。 通过[NSURLProtocol ...
对于 WKWebView 中发出的网络请求也无能为力`,如果真的要拦截来自 WKWebView 中的请求,还是需要实现 WKWebView 对应的 WKNavigationDelegate,并在代理方法中获取请求。 应用场景: 1、 自定义请求头的...
VC++ 写的构造HTTP请求头的类 用法: CHttpHeader* phttpHeader=new CHttpHeader(); phttpHeader->SetURI("www.baidu.com/news.asp?user=yubing&pass=good"); //phttpHeader->SetMethod("get"); //phttpHeader-...
httpclient的用法,发送get请求和post请求,设置header
某天,在需要抓取某个网页信息的时候,需要在header中增加一些信息,于是搜索了一下,如何在golang发起的http请求中设置header。 package main import ( "fmt" "io/ioutil" "net/http" "os" "encoding/json" )...
最近在工作中,由于合作商只提供uRL,我这边需要通过HTTP请求Get或Post方式请求Json数据,然后解析JSON格式,解析json我使用的第三方库rapidjson。开发环境是64位win7,VS2015。
curl发出请求的文件fake_ip.php: 代码 复制代码 代码如下: <?php $ch = curl_init(); $url = “http://localhost/target_ip.php”; $header = array( ‘CLIENT-IP:58.68.44.61’, ‘X-FORWARDED-FOR:58.68.44.61...
Header Editor是一款管理浏览器请求的Chrome扩展,包括修改请求头、修改响应头、重定向请求、取消请求。 您可以从Redirector导入规则 规则说明: 1、匹配类型 规则会应用到满足相应匹配条件的URL上 全部:...
JSP获取HTTP header信息(request)例子JSP获取HTTP header信息(request)例子
tcp/ip-HTTP-Header-消息报头 本文来自: E点废墟(www.xok.la) 详细出处参考:http://xok.la/2009/07/tcp-ip-http-header.html
下面小编就为大家带来一篇java获取http请求的Header和Body的简单方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
Unity3d www Http 请求 Headers 验证 文档地址:https://blog.csdn.net/nicepainkiller/article/details/75008516
Http协议header说明,包括: Content-Length Content-Language Content-Disposition Content-Type Cache-Control .............. 等属性使用
伪造IP来源对于php来说是很简单的一件事情,我们只要利用了php的curl即可实现伪造IP来源的功能,IP地址你可以随便写. index.php实例代码如下: 复制代码 代码如下:$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, ...
本文实例讲述了go语言在请求http时加入自定义http header的方法。分享给大家供大家参考。具体实现方法如下: 代码如下: client := &http.Client{] req, err := http.NewRequest(“POST”, “http://example.com”, ...
http header 详细介绍,详细的定义,类型等等等,希望对大家有帮助
用Nginx向http request请求的http header中添加字段