fix(security): X-Forwarded-For IP 伪造防护

- isTrustedProxy: 空可信代理列表时默认不信任(安全优先)
- realIP: 修正 XFF 遍历逻辑,从右到左跳过可信代理,返回第一个不可信的客户端 IP
- GetClientIP: 优先读取 IPFilterMiddleware 已验证的 client_ip,避免直接信任转发头
This commit is contained in:
2026-05-08 10:35:20 +08:00
parent d4ec8a13e4
commit 8665c97d0d
3 changed files with 18 additions and 41 deletions

View File

@@ -64,20 +64,17 @@ func (m *IPFilterMiddleware) realIP(c *gin.Context) string {
// X-Forwarded-For 可能包含代理链
xff := c.GetHeader("X-Forwarded-For")
if xff != "" {
// 从右到左遍历(最右边是最后一次代理添加的)
for _, part := range strings.Split(xff, ",") {
ip := strings.TrimSpace(part)
parts := strings.Split(xff, ",")
// 从右到左遍历(最右边是离服务器最近的代理)
for i := len(parts) - 1; i >= 0; i-- {
ip := strings.TrimSpace(parts[i])
if ip == "" {
continue
}
// 检查是否是可信代理
if !m.isTrustedProxy(ip) {
continue // 不是可信代理,跳过
}
// 是可信代理,检查是否为公网 IP
if !isPrivateIP(ip) {
return ip
if m.isTrustedProxy(ip) {
continue // 跳过可信代理
}
return ip // 第一个不可信代理就是真实客户端
}
}
@@ -97,7 +94,7 @@ func (m *IPFilterMiddleware) realIP(c *gin.Context) string {
// isTrustedProxy 检查 IP 是否在可信代理列表中
func (m *IPFilterMiddleware) isTrustedProxy(ip string) bool {
if len(m.config.TrustedProxies) == 0 {
return true // 如果没有配置可信代理列表,默认信任所有(兼容旧行为
return false // 配置可信代理列表 → 不信任任何代理(安全优先
}
for _, trusted := range m.config.TrustedProxies {
if ip == trusted {

View File

@@ -18,8 +18,12 @@ func init() {
// newTestEngine 用给定的 IPFilterMiddleware 构建一个最简 Gin 引擎,
// 注册一个 GET /ping 路由,返回 client_ip 值。
func newTestEngine(f *security.IPFilter) *gin.Engine {
return newTestEngineWithConfig(f, IPFilterConfig{})
}
func newTestEngineWithConfig(f *security.IPFilter, cfg IPFilterConfig) *gin.Engine {
engine := gin.New()
engine.Use(NewIPFilterMiddleware(f, IPFilterConfig{}).Filter())
engine.Use(NewIPFilterMiddleware(f, cfg).Filter())
engine.GET("/ping", func(c *gin.Context) {
ip, _ := c.Get("client_ip")
c.JSON(http.StatusOK, gin.H{"ip": ip})