Nginx 获取真实客户端 IP 的正确姿势
|
admin
2025年9月10日 21:22
本文热度 147
|
在云原生架构下,Nginx 或应用服务前面挂了 WAF、负载均衡(SLB) 等安全和流量治理组件,Nginx 日志里 $remote_addr
往往不再是用户的真实公网 IP,而是代理设备的出口 IP。
本文带你从原理到实践,搞清楚如何优雅、安全地拿回真实客户端 IP。
📌 背景与问题
为什么 `$remote_addr` 是代理 IP?因为 TCP 连接实际是和 WAF/SLB 建立的。
对 Nginx 来说,连接对端就是 SLB/WAF 的出口地址,而不是用户。
📌 用户真实 IP 的去向
WAF/SLB 会把真实用户 IP 写入 HTTP 头X-Forwarded-For: <client-ip>, <proxy-ip>, ...
X-Real-IP: <client-ip>
(某些设备使用)
因此,只能在 HTTP 七层读取这些头部才能拿回真实客户端 IP。
📌 正确获取真实 IP 的 Nginx 配置
直接打印 `$http_x_forwarded_for` 有安全风险
正确做法:使用 ngx_http_realip_module
,并只信任来自自家代理设备的 IP。
# 1) 信任的代理网段
set_real_ip_from 10.0.0.0/16;
set_real_ip_from 192.168.0.0/24;
# 2) 指定头部
real_ip_header X-Forwarded-For;
# 3) 启用递归解析,获取最左侧的客户端 IP
real_ip_recursive on;
# 4) 日志配置
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'status=$status bytes=$body_bytes_sent '
'xff="$http_x_forwarded_for" ua="$http_user_agent"';
access_log /var/log/nginx/access.log main;
📌 非 HTTP/HTTPS 场景怎么办?
有些业务跑在 WebSocket、HTTPS 直透、纯 TCP 服务 上,这时不能依赖 HTTP 头。
- PROXY protocol(推荐)
上游设备在 TCP 握手时写入真实 IP
Nginx 开启支持:
server {
listen 443 proxy_protocol;
real_ip_header proxy_protocol;
set_real_ip_from 10.0.0.0/16;
}
适用于 HTTPS、TCP 等多场景
- 透明代理/TPROXY
在网络层保留源地址,运维复杂,依赖内核和路由配置
公有云环境下一般不推荐
📌 避坑指南
set_real_ip_from
指定可信代理网段
real_ip_header X-Forwarded-For
并开启 real_ip_recursive on
日志同时打印 $remote_addr
与 $http_x_forwarded_for
向后端透传真实 IP:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
✅ 总结
为什么看不到真实 IP? 👉 TCP 对端是 WAF/SLB。
如何拿回? 👉 HTTP 场景依赖 X-Forwarded-For
,必须配合 realip
模块。
非 HTTP 场景? 👉 使用 PROXY protocol。
最佳实践? 👉 配置可信网段、递归解析、双日志记录、后端透传。
这样配置后,无论日志分析、风控策略还是安全审计,都能基于准确的用户源 IP 进行判断。
阅读原文:原文链接
该文章在 2025/9/11 10:01:11 编辑过