最近收到一条安全漏洞报告,通过利用代码漏洞,并结合HTTP扩展请求头 X-Forwarded-For 可以对客户端IP进行伪造,以达到非法目的。下面我将对这个漏洞进行介绍。
X-Forwarded-For 介绍
X-Forwarded-For 是一个 HTTP 扩展头部,用来表示HTTP请求端真实 IP,HTTP/1.1 协议并没有对它的定义,但现如今X-Forwarded-For已被各大 HTTP 代理、负载均衡等转发服务广泛使用。
X-Forwarded-For 请求头格式:
X-Forwarded-For: client, proxy1, proxy2
X-Forwarded-For 请求头的内容由英文逗号和空格隔开,每经过一级代理服务器,X-Forwarded-For 后面就会继续添加该代理设备的IP地址。
因此,一般来说,我们要获得客户端地址,直接从 X-Forwarded-For 拿到第一个 IP 地址即可。一般代码如下:
String ips = request.getHeader("X-Forwarded-For");
// 从ips中切割出client Ip 略
nginx配置
为了能够从请求头中获得 X-Forwarded-For,一般都会在 nginx 中进行如下配置:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for
因此,如果只配置一个 nginx,那么通过上面的代码我们所能得到的 ips 为 clientIp, nginx所在服务器Ip。
X-Forwarded-For 客户端Ip伪造
X-Forwarded-For 作为 HTTP 请求的扩展头,在请求的过程中可以被直接的进行修改。正常情况下,我们所获得的 ips 第一部分应该是客户端 IP,但是如果客户端对 X-Forwarded-For 进行了修改,我们仍旧采用以上方法获得客户端 IP,那么客户端 IP 将会是被伪造过的。
我们使用Postman模拟伪造一个X-Forwarded-For:
可以看到,如果只是简单进行获取,可能造成许多安全问题,尤其对于对 IP 具有较高要求的场景,例如投票系统等。
X-Forwarded-For 客户端IP伪造的防范
我们知道 X-Forwarded-For可以被伪造,但是客户端请求来源IP其实是不能被伪造的,因为在客户端和服务端进行通信的时候,我们需要进行三次握手,如果这个来源IP是假的,那么我们的握手是不会成功的,就好像我们给对方写信,如果发件人的地址写错了,那么我们就收不到对方的回信。
在 nginx 中,还有一个配置
proxy_set_header X-Real-IP $remote_addr
$remote_addr
是 nginx 的内置变量,代表客户端的真实IP。
既然我们能够直接获得真实的客户端 IP,那么我们为什么还要获得 X-Forwarded-For 呢?原因在于如果配置了多层的代理,那么这个 X-Real-IP 将会是上一层代理的真实 IP。
我们直接获得 X-Forwarded-For 将会有 IP 被伪造的风险,而使用 X-Real-IP 将会无法获得真实的 IP 地址。我们将两者的优势进行结合,便可防止客户端 IP 伪造。
对于最外层的代理服务器,我们可以进行如下配置:
proxy_set_header X-Forwarded-For $remote_addr
而内部的代理服务器则保留原有的 X-Forwarded-For 配置,这样,我们就可以获得真实的客户端IP了。