调试工具 / 环境
1 2
| docker run -d --restart=unless-stopped --name http-headers-printer -p 6130:6130 fangqk1991/http-headers-printer
|
入口 Nginx 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| server { listen 443 ssl; ssl_certificate ……; ssl_certificate_key ……; server_name *.fangcha.net;
location / { proxy_read_timeout 300; proxy_pass http://127.0.0.1:8000; proxy_http_version 1.1; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port 443; proxy_set_header Host $host; } }
|
Kong Route preserve_host = true
相当于 Nginx proxy_set_header Host $host;
,该值会影响后端应用接收的 HTTP Request Headers Host 值
1 2 3 4 5 6 7 8 9 10 11
| ## preserve_host = false { "host": "10.0.4.2:6130", …… }
## preserve_host = true { "host": "headers-printer.staging.fangcha.net", …… }
|
如何获得正确的客户端 IP ?
通常情况下,Nginx 转发配置如下
1 2
| proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
- 典型示意图: Client -> Nginx 1 -> Nginx 2 …… -> Nginx N -> App
- App 得到的
X-Real-IP
总是 Nginx N 的前一个节点 IP 信息
- App 得到的
X-Forwarded-For
理论上为 Client IP, Client 1 IP, ……, Nginx N IP
- 若仅有一层 Nginx 反向代理,App 通过
X-Real-IP
或 X-Forwarded-For
首项均可获得客户端 IP 地址
- 若有超过一层 Nginx 转发,App 通过
X-Real-IP
不能得到原始的 Client IP,理论上通过 X-Forwarded-For
首项可以获得
- 因此应用往往将
X-Forwarded-For
首项视为客户端 IP,进行数据记录或风控行为
1 2 3 4 5
| { "x-forwarded-for": "1.117.xx.xxx, 127.0.0.1", "x-real-ip": "1.117.xx.xxx", …… }
|
伪造 X-Forwarded-For
客户端发起请求时,可以伪造 X-Forwarded-For
进而达到攻击目的
1
| curl -H "X-Forwarded-For: 10.0.0.1, 10.0.0.2" https:
|
1 2 3 4 5
| { "x-forwarded-for": "10.0.0.1, 10.0.0.2, 1.117.xx.xxx, 127.0.0.1", "x-real-ip": "1.117.xx.xxx", …… }
|
解决方案 1
- 最靠近客户端的 Nginx 1
X-Forwarded-For
设置为 $remote_addr
而非 $proxy_add_x_forwarded_for
,可以避免来自客户端的 X-Forwarded-For
伪造
- 在应用多区域部署的网络架构下,代理区 Nginx 1 ~ Nginx N 往往互相连通的网状结构而非单向链式结构,所有代理节点均可能成为「最靠近客户端」的入口节点
- 因此上述方案实施的必要条件之一是「网关需要具备辨别来自客户端或其他网关节点转发的请求」,攻击者只要知晓用于辨别的特征,大多数情况下仍然可以对请求进行伪造
- 一般而言直接与服务器建立连接的 IP 地址
$remote_addr
是不易伪造的,可维护一份「网关 IP 名单」,用于辨别客户端直接流量或网关转发流量
解决方案 2
- 应用的 IP 判定策略调整,不再从左到右将
X-Forwarded-For
首项视为客户端 IP
- 而是从右到左剔除「网关 IP」直至得到第一个 IP,将其视为客户端 IP