在 Web 开发中,服务器获取客户端真实 IP 地址是一个常见但容易出错的需求,由于网络架构的复杂性(如反向代理、负载均衡、NAT 等),直接获取 IP 并不总是直接的。
以下是几种主要的方式、原理、优缺点及最佳实践:
直接获取连接 IP(最基础方式)
这是最原始的方式,适用于没有反向代理或负载均衡的简单架构。
- 原理:服务器直接从 TCP 连接中获取对端(客户端)的 IP 地址。
- 代码示例:
- Java (Servlet):
request.getRemoteAddr() - Python (Flask):
request.remote_addr - Node.js (Express):
req.ip或req.connection.remoteAddress - Go:
req.RemoteAddr
- Java (Servlet):
- 优点:简单、直接、性能高。
- 缺点:
- 如果客户端位于 NAT(网络地址转换)后面(如家庭宽带、公司内网),获取到的是网关出口 IP,而非用户真实 IP。
- 如果前面有 Nginx、HAProxy、Cloudflare 等反向代理,获取到的是代理服务器的 IP,而非最终用户的 IP。
通过 HTTP 头信息获取(常见于代理场景)
当请求经过反向代理(如 Nginx、Apache、CDN、云厂商负载均衡)时,代理服务器通常会将原始客户端 IP 附加在 HTTP 请求头中。
常用 Header 字段:
| Header 名称 | 说明 | 安全性/可靠性 |
|---|---|---|
X-Forwarded-For (XFF) |
最常用,格式:client, proxy1, proxy2,第一个 IP 通常是原始客户端 IP。 |
⚠️ 不可信:客户端可伪造此头。 |
X-Real-IP |
Nginx 常用,通常只包含一个 IP 值。 | ⚠️ 不可信:客户端可伪造。 |
CF-Connecting-IP |
Cloudflare 专用。 | ✅ 可信:由 Cloudflare 设置,客户端无法伪造。 |
True-Client-IP |
Akamai 等 CDN 使用。 | ✅ 可信:由 CDN 设置。 |
X-Forwarded-Proto |
记录原始协议(http/https),非 IP,但常配合使用。 |
获取逻辑(伪代码):
def get_client_ip(request):
# 1. 优先检查可信 CDN 提供的专用头
if request.headers.get('CF-Connecting-IP'):
return request.headers['CF-Connecting-IP']
# 2. 检查 X-Forwarded-For
xff = request.headers.get('X-Forwarded-For')
if xff:
# XFF 格式: "client, proxy1, proxy2"
# 取第一个 IP
return xff.split(',')[0].strip()
# 3. 检查 X-Real-IP
if request.headers.get('X-Real-IP'):
return request.headers['X-Real-IP']
# 4. 降级到直接连接 IP
return request.remote_addr
⚠️ 重要安全警告:
X-Forwarded-For和X-Real-IP可以被客户端伪造!- 如果用户手动修改 HTTP 请求头,可以设置
X-Forwarded-For: 127.0.0.1来欺骗服务器。 - 解决方案:在反向代理(如 Nginx)中配置,只信任内部代理服务器传来的 XFF 头,丢弃来自外部客户端的伪造头。
- 如果用户手动修改 HTTP 请求头,可以设置
通过反向代理配置(Nginx 示例)
为了正确传递真实 IP,必须在反向代理层进行配置。
Nginx 配置示例:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend_server;
# 传递真实 IP 给后端
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; # 将客户端 IP 放入 X-Real-IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 追加 IP 到 XFF
}
}
后端信任代理配置(关键!):
后端应用需要知道哪些 IP 是“可信代理”,否则可能被伪造攻击。
- Nginx + Gunicorn: 使用
gunicorn的--forwarded-allow-ips参数。 - Node.js (Express): 设置
trust proxy。app.set('trust proxy', true); // 或指定具体 IP 列表 - Java (Spring Boot): 在
application.yml中配置。server: tomcat: remoteip: remote-ip-header: x-forwarded-for protocol-header: x-forwarded-proto
使用云厂商或 CDN 提供的专用 API/Header
如果使用 AWS ALB、Cloudflare、简米云 SLB 等云服务,它们通常会提供不可伪造的 IP 信息。
| 服务商 | 推荐 Header | 说明 |
|---|---|---|
| Cloudflare | CF-Connecting-IP |
最可靠,客户端无法伪造。 |
| AWS ALB | X-Forwarded-For |
AWS 保证不会由客户端伪造。 |
| 简米云 SLB | X-Forwarded-For |
简米云保证可信。 |
| Azure | X-Forwarded-For |
在 App Service 中需配置 X-Forwarded-For 支持。 |
✅ 最佳实践:优先使用云服务商提供的专用 Header(如
CF-Connecting-IP),其次才是通用的X-Forwarded-For。
总结与最佳实践建议
| 场景 | 推荐方式 | 注意事项 |
|---|---|---|
| 无代理直连 | request.getRemoteAddr() |
简单直接。 |
| 自建 Nginx 代理 | 读取 X-Real-IP 或 X-Forwarded-For |
必须在 Nginx 中配置 proxy_set_header,并在后端信任代理 IP。 |
| 使用 Cloudflare | 读取 CF-Connecting-IP |
最安全,无需担心伪造。 |
| 使用 AWS/Azure/简米云 | 读取 X-Forwarded-For |
云厂商保证该头可信。 |
| 高安全要求 | 结合 IP 白名单 + 日志审计 | 不要仅依赖 IP 做权限控制,应结合其他认证机制。 |
🛡️ 安全建议
- 永远不要完全信任
X-Forwarded-For:除非你确认请求来自可信的代理服务器。 - 配置信任代理列表:在后端框架中明确指定哪些 IP 是“可信代理”,这样框架会自动忽略来自非代理 IP 的伪造 XFF 头。
- 日志记录:记录原始连接 IP 和解析后的用户 IP,便于审计和故障排查。
- 防刷策略:如果用于频率限制(Rate Limiting),建议使用
X-Forwarded-For的第一个 IP,但需确保代理层已正确清理伪造头。
通过以上方式,你可以准确、安全地获取客户端真实 IP。
首发原创文章,作者:世雄 - 原生数据库架构专家,如若转载,请注明出处:https://idctop.com/article/487174.html



