fix: trust Cloudflare CF-Connecting-IP for IP extraction

When behind Cloudflare CDN, RemoteAddr shows CF's IP, breaking rate
limiting and logging. Trust CF-Connecting-IP (set by CF, cannot be
spoofed by clients) and fall back to RemoteAddr for direct connections.
This commit is contained in:
root 2026-04-25 11:45:07 +08:00
parent 77d276da04
commit e035fb07a9
2 changed files with 14 additions and 6 deletions

View file

@ -12,11 +12,15 @@ import (
"github.com/gin-gonic/gin"
)
// getRemoteIp extracts the real IP address from the direct connection.
// Uses RemoteAddr to prevent IP spoofing via X-Real-IP/X-Forwarded-For headers.
// If the panel is behind a trusted reverse proxy, configure Gin's SetTrustedProxies
// to re-enable header-based IP detection.
// getRemoteIp extracts the real IP address from the request.
// Trusts Cloudflare's CF-Connecting-IP header (overwritten by CF, cannot be spoofed by clients).
// Falls back to RemoteAddr for direct connections without a trusted proxy.
func getRemoteIp(c *gin.Context) string {
// Cloudflare CDN sets CF-Connecting-IP to the real client IP and overwrites it,
// so it can be trusted even though it's a header.
if cfIP := c.GetHeader("CF-Connecting-IP"); cfIP != "" {
return cfIP
}
addr := c.Request.RemoteAddr
ip, _, _ := net.SplitHostPort(addr)
return ip

View file

@ -37,8 +37,12 @@ func RateLimitMiddleware(maxRequests int, window time.Duration) gin.HandlerFunc
}()
return func(c *gin.Context) {
// Use RemoteAddr directly to prevent IP spoofing via headers
ip := c.Request.RemoteAddr
// Trust Cloudflare's CF-Connecting-IP (overwritten by CF, not spoofable).
// Fall back to RemoteAddr for non-CDN deployments.
ip := c.GetHeader("CF-Connecting-IP")
if ip == "" {
ip = c.Request.RemoteAddr
}
mu.Lock()
now := time.Now()