问题:IP 限制能信吗
很多 Web 应用做 IP 白名单 / 黑名单(投票限 IP、登录失败限速、按地区限制内容等),依赖的就是 HTTP 请求里的"客户端 IP"。但这个 IP 实际上可以被伪造。

本文讲清楚:
- 为什么 HTTP 层的 IP 能伪造,TCP/IP 层却不能
- 怎么伪造
- 怎么防御
原理:网络层 vs 应用层
正常的 TCP/IP 通信里,要"伪造源 IP" 是困难的 —— 你的 TCP 数据包里写假 IP 发出去,服务器响应包会发到那个假 IP,你根本收不到响应,TCP 连接建立不起来。所以纯 IP 层欺骗对 TCP 不可行。
但是 HTTP 是应用层协议,它跑在 TCP 上。HTTP 请求里有一组 Header,常见的 X-Forwarded-For、X-Real-IP、X-Client-IP 等都是用来表示"原始客户端 IP"。这些 Header 是请求里的纯文本字符串,客户端可以随便写。
很多服务器应用读这些 Header 来识别"客户端 IP"(尤其是配置在反向代理或 CDN 后面时),这就给了伪造空间。
怎么伪造
最简单 —— curl 加 header:
curl -H "X-Forwarded-For: 1.2.3.4" https://target.com/some-api
Python:
import requests
requests.get('https://target.com/some-api', headers={
'X-Forwarded-For': '1.2.3.4'
})
如果目标服务器把 X-Forwarded-For 当作客户端 IP 信任,它会以为请求来自 1.2.3.4,绕过基于 IP 的限制。
常见的可伪造 Header
除了 X-Forwarded-For,还有不少 Header 在不同 Web 框架 / 反向代理里都被用作"客户端 IP",都可以试着伪造:
X-Originating-IP: 127.0.0.1 X-Remote-IP: 127.0.0.1 X-Client-IP: 127.0.0.1 X-Forwarded-For: 127.0.0.1 X-Forwared-Host: 127.0.0.1 X-Host: 127.0.0.1 X-Custom-IP-Authorization: 127.0.0.1
实际渗透测试 / Bug Bounty 里,7 个 header 全试一遍是标准操作。
Nginx 是怎么设置 X-Forwarded-For 的
正常情况下 Nginx 反向代理会这么写:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for
这条 proxy_add_x_forwarded_for 的逻辑:
- 如果请求没 X-Forwarded-For:加一个,值是
$remote_addr(真实客户端 IP) - 如果请求有 X-Forwarded-For:在末尾追加
$remote_addr
结果是一个逗号分隔的 IP 链:X-Forwarded-For: 1.2.3.4, 192.168.1.1, 10.0.0.1。第一个是客户端伪造的(不可信),后面的才是经过的各级代理 IP(可信)。
正确的服务端读法
很多人写代码犯的错:直接 request.headers['X-Forwarded-For'],拿到的就是用户伪造的那个 IP。
正确做法:
- 知道你前面有几级可信代理(比如 Cloudflare → Nginx → 应用,2 级)
- 取
X-Forwarded-For从右往左数第 2 个 IP 才是真实客户端 - 或者用反向代理的特殊 header(
CF-Connecting-IP是 Cloudflare 给的)
Node.js Express 示例:
// app.js
app.set('trust proxy', 2); // 信任前 2 层代理
app.get('/api', (req, res) => {
console.log(req.ip); // Express 会用 trust proxy 算出真实 IP
});
Python Flask:
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=2) # 信任 2 层代理
Nginx 配置层面,可以用 real_ip 模块强制覆盖 $remote_addr:
set_real_ip_from 10.0.0.0/8; # 信任内网代理
set_real_ip_from 172.20.0.0/16; # 信任 Docker 网络
real_ip_header X-Forwarded-For;
real_ip_recursive on;
防御:别信用户给的 Header
核心原则:HTTP header 是不可信输入。任何依赖 IP 做决策的逻辑都要:
- 明确数据来源 —— 是 TCP 层(
$remote_addr)还是 HTTP 层(X-Forwarded-For) - HTTP 层 IP 只在前面有可信代理时才可信
- 取最右边的真实代理 IP(链尾)
- 关键操作(登录失败限速)双层防御:IP + 设备指纹 + Captcha
实际案例:投票 / 抽奖系统
很多线上投票限制"每个 IP 只能投一次",但只看 X-Forwarded-For 的话,5 行 Python 就能刷:
import requests
import random
for i in range(100):
fake_ip = f"{random.randint(1,255)}.{random.randint(1,255)}.{random.randint(1,255)}.{random.randint(1,255)}"
requests.post('https://vote.example.com/vote',
headers={'X-Forwarded-For': fake_ip},
data={'option': 'A'})
print(f"投票 #{i+1} 用 IP {fake_ip}")
真正稳的方案:
- IP 限制 + Cookie / localStorage 限制 + 浏览器指纹
- 需要登录账号才能投
- 滑动验证码 / 人机验证 reCAPTCHA / Cloudflare Turnstile
- 统计异常流量(同源、同 UA、同时间窗口)
一句话:任何"仅看 IP"的限制都能被绕过,认真的反作弊一定是多维度的。
合法用途
本文讲的"伪造 IP"主要是技术原理,合法场景:
- 渗透测试 / 安全审计(经授权)
- 调试本地开发服务(模拟不同地区访问)
- 测试自家服务的 IP 防御逻辑
未经授权对他人服务做这种事是违法的(《刑法》285、286 条,《网络安全法》)。理解原理 + 用在正当地方 = 工程师的边界。
—— 别看了 · 2026