反向代理与真实客户端 IP:Nginx 转发后怎么拿到用户来源
一、先说结论
这一篇主要回答:
- Nginx 反向代理后,客户端真实 IP 怎么拿?
- 为什么不能无脑相信
X-Forwarded-For?
如果先把答案压缩成几句话,可以这样记:
- 反向代理后,后端服务直接看到的通常是 Nginx 的 IP
- 真实客户端 IP 一般要靠代理转发的请求头传递,比如
X-Forwarded-For和X-Real-IP - 只有在请求确实经过受信任代理时,才能把这些头当作真实来源来信任
二、为什么后端默认拿不到真实客户端 IP
当 Nginx 做反向代理时,请求链路会变成:
客户端 -> Nginx -> 后端服务对于后端服务来说,真正和它建立 TCP 连接的并不是客户端,而是:
Nginx
所以如果后端直接读取:
- socket 对端地址
remoteAddr
通常看到的就是:
Nginx 的 IP
而不是真实客户端 IP。
三、真实 IP 一般通过什么头传递
最常见的有两个头。
1. X-Forwarded-For
这是最常见的真实 IP 头。
例如:
X-Forwarded-For: 1.2.3.4如果经过多层代理,它可能变成:
X-Forwarded-For: 客户端IP, 代理1IP, 代理2IP也就是说,它常常是一个逗号分隔的链路列表。
2. X-Real-IP
很多场景也会由 Nginx 额外设置:
X-Real-IP: 1.2.3.4它更像是:
Nginx 当前认定的那个原始客户端 IP
四、Nginx 为什么能把真实 IP 传给后端
因为虽然 TCP 层面后端只能看到代理地址,但代理可以在应用层转发请求时,把来源信息重新写进 Header。
常见配置思路是:
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;这里:
$remote_addr是 Nginx 当前看到的对端 IP$proxy_add_x_forwarded_for表示在已有链路基础上继续追加当前来源
所以本质上:
真实 IP 不是 TCP 直接告诉后端的,而是代理通过 HTTP 请求头传下去的。
五、后端服务一般怎么取真实 IP
后端常见做法不是直接只看 remoteAddr,而是优先按顺序取:
X-Forwarded-ForX-Real-IP- 如果都没有,再退回到
remoteAddr
X-Forwarded-For 要注意什么
因为它可能有多个值,所以通常会:
- 取第一个非空、非
unknown的值 - 再根据是否经过受信任代理决定是否信任它
六、为什么不能无脑信任 X-Forwarded-For
这是面试里很加分的一点。
因为:
请求头本身是可以被伪造的。
如果你的后端服务直接暴露在公网,攻击者完全可以自己构造:
X-Forwarded-For: 8.8.8.8所以只有在下面这种前提下,才应该把它当真:
- 请求一定会先经过你信任的代理
- 只有代理有权限改写这些头
- 后端只接受来自受信任代理的流量
也就是说:
你信任的不是这个头本身,而是“是谁写了这个头”。
七、面试里怎么回答会比较顺
如果面试官问这题,可以这样答:
Nginx 反向代理后,后端服务默认拿到的通常是 Nginx 的 IP,因为真正和后端建立 TCP 连接的是代理服务器,而不是客户端本身。要获取真实客户端 IP,通常需要由 Nginx 在转发时通过请求头传递,比如
X-Forwarded-For和X-Real-IP。后端服务一般优先从这些头里取值,如果没有再退回到remoteAddr。不过需要注意,这类头本身可以被伪造,所以只有在请求确实经过受信任代理时,才能把它当作真实 IP 使用。
八、一句话总结
可以把这题压缩成一句话:
反向代理后,TCP 层看到的是代理 IP,真实客户端 IP 通常要靠代理通过 Header 帮你传下来。
