客户端真实IP需由可信上游代理(如Nginx)通过X-Real-IP头传递,后端仅在请求来自可信代理网段时采信该头;不可直接信任未经校验的X-Forwarded-For。

直接说结论:客户端真实 IP 不是“获取”出来的,而是靠上游代理(如 Nginx、CDN、负载均衡)在转发请求时,主动用 X-Forwarded-For 或 X-Real-IP 这类 HTTP 头塞进来的;后端代码只是读取它——但必须校验来源是否可信,否则极易被伪造。
为什么 X-Forwarded-For 不能直接信
这个头本质是链式追加的字符串,比如:X-Forwarded-For: 203.0.113.1, 192.168.1.10。最左边是原始客户端 IP,后面是各级代理的出口 IP。但任何前端请求都能手动加上这个头,比如 curl -H "X-Forwarded-For: 1.2.3.4",后端若无条件信任,就等于把伪造 IP 当真了。
- 只信任你**自己控制的入口代理**(比如 Nginx)添加的
X-Forwarded-For,其它中间层(如第三方 CDN)若未明确配置透传且可信,就别碰 - 如果后端直连公网(没代理),
X-Forwarded-For完全不可用,此时request.remote_addr(Python Flask)或req.connection.remoteAddress(Node.js)才是真实 IP - 某些代理(如 AWS ALB)默认不设
X-Forwarded-For,得在监听器规则里显式启用
Nginx 怎么安全地传真实 IP 给后端
关键不是“传”,而是“只从可信来源传”。Nginx 必须运行在你完全可控的边界上(比如最外层反向代理),且明确知道哪些 IP 是上游可信代理(如另一台 Nginx 或内部 LB)。
- 用
set_real_ip_from显式声明可信代理网段,例如:set_real_ip_from 10.0.0.0/8; - 配合
real_ip_header X-Forwarded-For;和real_ip_recursive on;,让 Nginx 自动解析并覆盖$remote_addr - 确保后端服务(如 Python、Go)读的是
X-Real-IP(Nginx 设置的)或remote_addr(已被重写),而不是原始X-Forwarded-For字符串 - 别漏掉
proxy_set_header X-Real-IP $remote_addr;—— 这才是你该传给后端的干净 IP
后端语言里怎么读才靠谱(以 Python Flask 为例)
Flask 的 request.remote_addr 默认是直接 TCP 连接方 IP,即上一级代理的 IP,不是用户真实 IP。必须依赖 Nginx 设置的 X-Real-IP 头,且仅当该请求确实来自你信任的 Nginx 时才可用。
- 检查请求头来源:如果
request.headers.get("X-Real-IP")存在,且request.remote_addr属于你配置的可信代理网段(比如10.0.0.0/8),才采信 - 不要用
request.headers.get("X-Forwarded-For").split(",")[0]直接取——没校验来源,等于开门揖盗 - 框架如 Django 有
SECURE_PROXY_SSL_HEADER和USE_X_FORWARDED_HOST,但它们不自动校验 IP 可信性,仍需配合 Nginx 的set_real_ip_from - 云环境注意:阿里云 SLB、腾讯云 CLB 默认用
X-Forwarded-For,但头部值由它们生成,可视为可信——前提是没被业务层其他代理二次篡改
真正麻烦的从来不是“怎么读”,而是“谁写的这个头、从哪来的、中间有没有被插过手”。一个没配 set_real_ip_from 的 Nginx,和一个开着 X-Forwarded-For 透传却没做白名单的 CDN,会让所有后端逻辑拿到的都是假 IP。










