构造HTTP请求Header实现“伪造来源IP”(重在原理)

转载自:


1. 伪造原理

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

 

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

 

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

 

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

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

 

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

 

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



左边即是请求数据,右边即是服务器响应数据。

特点:

请求 header 中除第一行外,其它行均由 header 名称, header 值组成,如  Accept-Encoding: gzip, deflate  header 名称与值之间有冒号相隔,之间的空格是可有可无的。

那么,在HTTP 应用程序中,如何取得指定的请求 header 信息呢?

以下是js获取ip地址:

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;
}
由上可知: 服务器通过request中的  x-forwarded-for 和 client-ip 来获取 客户端的ip.

那么,如果客户端伪造 Client-Ip, X-Forward-For ,可以欺骗此程序,达到“伪造 IP ”之目的.


2. 那么如何伪造这项值(X-Forward-For)?

方法一: 如果你会写程序,并了解HTTP 协议,直接伪造请求 header 即可

方法二: 使用 Firefox Moify Headers 插件即可(推荐)



3. 如何避免伪造ip

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

服务器集群之间的通信,是可以信任的。我们要做的就是在离用户最近的前端代理上,强制设定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 ”。






在 C 语言中,可以使用标准库中的 socket 和 HTTP 协议来实现 HTTP 请求和响应的处理。HTTP 头部(header)是 HTTP 请求和响应中的重要组成部分,包含了请求和响应的各种参数信息。下面是一个简单的 C 语言程序,可以解析 HTTP 请求头部中的参数信息: ```c #include <stdio.h> #include <string.h> int main() { char buffer[1024]; char *method, *path, *http_version; int content_length = -1; // 读取 HTTP 头部 fgets(buffer, sizeof(buffer), stdin); sscanf(buffer, "%s %s %s", method, path, http_version); while (fgets(buffer, sizeof(buffer), stdin)) { if (strcmp(buffer, "\n") == 0 || strcmp(buffer, "\r\n") == 0) { break; } if (strncmp(buffer, "Content-Length:", 15) == 0) { sscanf(buffer + 15, "%d", &content_length); } } printf("Method: %s\n", method); printf("Path: %s\n", path); printf("HTTP Version: %s\n", http_version); printf("Content-Length: %d\n", content_length); return 0; } ``` 在上面的代码中,首先声明了三个指针变量 `method`、`path` 和 `http_version`,用于存储 HTTP 请求的方法、路径和版本号。然后通过 `fgets()` 函数和 `sscanf()` 函数从标准输入流(stdin)中读取 HTTP 头部的各个参数。 接着,通过一个 while 循环遍历 HTTP 头部中的每一行,如果遇到空行,则表示 HTTP 头部已经读取完毕,可以退出循环。如果遇到 Content-Length 参数,则使用 sscanf() 函数解析其中的数值,并将其存储到 content_length 变量中。 最后,通过 printf() 函数输出读取到的 HTTP 头部参数信息。 需要注意的是,上面的代码只是一个简单的示例,实际的 HTTP 头部可能会更加复杂,需要根据不同的情况进行适当的调整。同时,还需要对 HTTP 请求和响应的其他部分进行处理,包括请求体、响应状态码、响应体等等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值