c.clientip()在生产环境几乎必然返回错误ip,因其默认仅信任127.0.0.1/8等本地段,而真实请求必经nginx/cdn等未被信任的代理,导致fallback至remoteaddr(如10.0.1.5),须同步配置nginx透传头、gin可信代理段及ip合法性校验。

直接说结论:c.ClientIP() 在生产环境几乎必然返回错误 IP,除非你同时搞定 Nginx 透传 + Gin 可信代理配置 + IP 合法性校验三件事。单独调用它没意义。
为什么 c.ClientIP() 总是 127.0.0.1 或内网地址
Gin 的 c.ClientIP() 不是从 TCP 连接里“抓”真实 IP,而是按顺序查 X-Forwarded-For → X-Real-IP → c.Request.RemoteAddr。但默认情况下,它只信任 127.0.0.1/8 和 ::1/128 这些本地段——而你的 Nginx、SLB、CDN 都不在这个范围内,所以整条 X-Forwarded-For 链被无视,直接 fallback 到 RemoteAddr(即最后一跳代理的内网地址)。
常见现象包括:
- 本地开发时返回
127.0.0.1(因为 Nginx 和 Go 同机,但没加"127.0.0.1"到可信列表) - K8s NodePort 下返回
10.0.x.x(Service 没开externalTrafficPolicy: Local,流量被 kube-proxy 做了 SNAT) - 阿里云 SLB 后返回
100.x.x.x(SLB 的出口 IP 没加进SetTrustedProxies)
Nginx 必须配这三行,缺一不可
仅 Gin 端配置无法补救上游没传头的问题。Nginx 的 location 或 server 块里必须有:
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
注意点:
-
$proxy_add_x_forwarded_for是 Nginx 内置变量,不是字符串字面量;写成"$remote_addr"或漏掉$都会失效 - 如果用了 CDN 或 WAF,它们也会追加
X-Forwarded-For,此时 Nginx 要确保自己是“最后一级可信代理”,否则可能把 CDN 的 IP 当作客户端 IP - 不要在
upstream块里重复定义这些proxy_set_header,优先级错乱会导致头被覆盖
Gin 启动时必须显式设置可信代理段
在 gin.Default() 或 gin.New() 之后、r.Run() 之前,立即执行:
r.SetTrustedProxies([]string{"127.0.0.1", "192.168.1.10", "100.64.0.0/10"})
其中:
- 本地单机部署:至少加
"127.0.0.1" - 私有云或 K8s 集群:填 Nginx Pod 所在网段,如
"10.244.0.0/16"(CNI 网段) - 公有云 SLB:查文档确认其出口 IP 段,比如阿里云 SLB 是
"100.64.0.0/10",腾讯云是"100.125.0.0/16" - 别用
nil或空 slice 清空信任列表——Gin v1.9+ 会 fallback 到默认值,仍不信任你的代理
顺带启用链式解析:r.ForwardedByClientIP = true,并可选指定头顺序:r.RemoteIPHeaders = []string{"X-Forwarded-For", "X-Real-IP"}。
永远别直接用 c.ClientIP() 做安全判断
c.ClientIP() 返回的是字符串,不做合法性校验。攻击者只要发 X-Forwarded-For: 127.0.0.1, 1.2.3.4,你就可能拿到 "127.0.0.1" 并当成真实 IP 处理。
正确做法是手动解析并过滤:
- 用
net.ParseIP()解析字符串,再调ip.IsGlobalUnicast() - 跳过所有私有网段:
127.0.0.0/8、10.0.0.0/8、172.16.0.0/12、192.168.0.0/16、::1/128等 - IPv6 地址需先
strings.Trim(ipStr, "[]")去掉方括号 - 多层代理下,
X-Forwarded-For是逗号分隔字符串,取最左第一个全局单播地址即可,别取最后一个
最常被忽略的一点:即使你配全了所有项,X-Forwarded-For 本身仍是客户端可伪造的 HTTP 头。真要防绕过,得配合 X-Real-IP(由 Nginx 直接注入,不可伪造)+ 严格可信代理段双重保障。











