
Gin 怎么配置 SetTrustedProxies 與 TrustedPlatform 讓 ClientIP 返回真實客戶端 IP【免費下載鏈接】ginGin is a high-performance HTTP web framework written in Go. It provides a Martini-like API but with significantly better performance—up to 40 times faster—thanks to httprouter. Gin is designed for building REST APIs, web applications, and microservices.項目地址: https://gitcode.com/GitHub_Trending/gi/ginGin 服務(wù)放在反向代理或 CDN 后面時c.ClientIP()應(yīng)該返回真實客戶端 IP而不是代理的地址。但 Gin 默認(rèn)信任所有代理TrustedProxies功能默認(rèn)開啟且默認(rèn)信任全部來源這意味著任何人都可以偽造X-Forwarded-For頭。這篇文檔給出兩條互補的配置路徑用Engine.SetTrustedProxies()限定哪些直接連接來源的 IP 頭可以被信任自建代理場景以及在接入 CDN 時用Engine.TrustedPlatform直接讀取 CDN 寫入的專用頭。前提是一個已引入 Gin 的 Go 項目。ClientIP() 的判定鏈先看 context.go 中ClientIP()的注釋和實現(xiàn)它按以下順序決定返回值TrustedPlatform非空且請求中存在該名稱的頭 → 直接返回該頭的值否則從Request.RemoteAddr解析直接連接 IPRemoteIP()若直接連接 IP 落在SetTrustedProxies()設(shè)置的信任列表內(nèi)且ForwardedByClientIP為truegin.go 中New()的默認(rèn)值就是true則解析Engine.RemoteIPHeaders中定義的頭默認(rèn)[X-Forwarded-For, X-Real-IP]頭不合法、或直接連接 IP 不受信任 → 返回直接連接 IP。其中第 3 步的具體規(guī)則在 gin.go 的validateHeader中實現(xiàn)X-Forwarded-For按逗號拆分后從后往前檢查返回第一個不在信任列表中的 IP如果所有 IP 都在信任列表里返回頭中的第一個 IP遇到無法解析的條目則停止并判定該頭無效。起步檢查默認(rèn)配置會打印警告Gin 的默認(rèn)信任列表是0.0.0.0/0與::/0gin.go 中New()的初始值即信任全部代理。docs/doc.md 明確標(biāo)注this is NOT safe。Run、RunTLS、RunUnix、RunFd、RunQUIC、RunListener這些啟動入口都會檢查信任列表是否覆蓋全部 IP若是則打印[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.因此啟動時是否出現(xiàn)這條警告可以作為一條現(xiàn)成的核對信號配置正確后它不應(yīng)再出現(xiàn)。步驟一用 SetTrustedProxies 限定可信代理按 docs/doc.md 的 Dont trust all proxies 一節(jié)在gin.Engine上調(diào)用SetTrustedProxies()參數(shù)支持 IPv4 地址、IPv4 CIDR、IPv6 地址、IPv6 CIDR。文檔給出的示例192.168.1.2替換為你自己的代理地址func main() { router : gin.Default() router.SetTrustedProxies([]string{192.168.1.2}) router.GET(/, func(c *gin.Context) { // If the client is 192.168.1.2, use the X-Forwarded-For // header to deduce the original client IP from the trust- // worthy parts of that header. // Otherwise, simply return the direct client IP fmt.Printf(ClientIP: %s\n, c.ClientIP()) }) router.Run() }router.Run()未指定端口時默認(rèn)監(jiān)聽:8080除非設(shè)置了PORT環(huán)境變量文檔路由章節(jié)有說明。幾個直接影響執(zhí)行的細(xì)節(jié)返回值是error必須檢查。gin_test.go 的TestPrepareTrustedCIRDsWith展示了哪些輸入合法192.168.1.33合法單個 IP 會被解析為/322002:0000:0000:1234:abcd:ffff:c0a8:0101合法IPv6 單地址解析為/128::/0、192.168.0.0/16等組合合法而192.168.1.33/33、192.168.1.256、gggg:0000:0000:1234:abcd:ffff:c0a8:0101這類無效值會返回 error。完全不使用代理時用router.SetTrustedProxies(nil)禁用該功能此時Context.ClientIP()直接返回直接連接地址避免不必要的計算——這是 docs/doc.md 給出的做法文檔原文說明其目的是 avoid some unnecessary computation。列表為空切片[]string{}與nil效果不同nil是關(guān)閉功能空切片是沒有任何可信代理。兩者的結(jié)果都是ClientIP()回退到直接連接 IP見 context_test.go 中兩條相鄰的測試斷言但文檔明確描述的是nil這一種優(yōu)先使用文檔說明的寫法。步驟二接入 CDN 時改用 TrustedPlatformdocs/doc.md 的 Notice 指出Engine.TrustedPlatform可以跳過 TrustedProxies 檢查它的優(yōu)先級高于 TrustedProxies。設(shè)置后ClientIP()會解析對應(yīng)的頭并直接返回其中的 IP。gin.go 中預(yù)定義了三個平臺常量對應(yīng)各自讀取的頭常量讀取的請求頭gin.PlatformGoogleAppEngineX-Appengine-Remote-Addrgin.PlatformCloudflareCF-Connecting-IPgin.PlatformFlyIOFly-Client-IP文檔示例192.168.1.2一節(jié)的同款結(jié)構(gòu)此處為 CDN 分支func main() { router : gin.Default() // Use predefined header gin.PlatformXXX // Google App Engine router.TrustedPlatform gin.PlatformGoogleAppEngine // Cloudflare router.TrustedPlatform gin.PlatformCloudflare // Fly.io router.TrustedPlatform gin.PlatformFlyIO // Or, you can set your own trusted request header. But be sure your CDN // prevents users from passing this header! For example, if your CDN puts // the client IP in X-CDN-Client-IP: router.TrustedPlatform X-CDN-Client-IP router.GET(/, func(c *gin.Context) { // If you set TrustedPlatform, ClientIP() will resolve the // corresponding header and return IP directly fmt.Printf(ClientIP: %s\n, c.ClientIP()) }) router.Run() }注意文檔的警告如果用自己的頭名如X-CDN-Client-IP必須確認(rèn)你的 CDN 會阻止用戶直接傳入該頭否則客戶端仍可偽造。另外當(dāng)請求中該頭為空時ClientIP()不會報錯而是回落到 TrustedProxies 判定路徑context_test.go 中有對應(yīng)斷言TrustedPlatform指向一個不存在的頭時返回直接連接 IP。驗證配置是否生效1. 啟動檢查運行服務(wù)確認(rèn)[WARNING] You trusted all proxies, this is NOT safe.不再出現(xiàn)在啟動日志中。2. 請求檢查按步驟一/二的示例程序運行用curl http://localhost:8080/發(fā)請求觀察 handler 打印的ClientIP:輸出是否符合預(yù)期。context_test.go 的ClientIP測試用例給出了一組可參照的行為數(shù)據(jù)以下為測試用例中的示例值不是生產(chǎn)環(huán)境的固定預(yù)期RemoteAddr為40.40.40.40:42123X-Forwarded-For為20.20.20.20, 30.30.30.30信任列表只含40.40.40.40→ClientIP()返回30.30.30.30從后往前第一個不受信任的 IP信任列表包含40.40.40.40、30.30.30.30、20.20.20.20全部受信任→ 返回頭中第一個 IP20.20.20.20信任列表用 CIDR40.40.25.25/1630.30.30.30時直接連接40.40.40.40命中該 CIDR同樣返回20.20.20.20直接連接不受信任 → 返回直接連接 IP40.40.40.40X-Forwarded-For內(nèi)容不是合法 IP如 blah → 回退返回直接連接 IP。3. 錯誤檢查SetTrustedProxies返回非 nil 的error說明列表里有無法解析的地址或 CIDR需要修正輸入格式見上一步的合法/非法示例。限制與已廢棄項默認(rèn)信任所有代理是不安全狀態(tài)docs/doc.md 原文標(biāo)注this is NOT safe不配置SetTrustedProxies或接入 CDN 前的狀態(tài)都應(yīng)視為待修正項。Engine.AppEngine字段已廢棄gin.go 中的注釋要求改用TrustedPlatform并取值gin.PlatformGoogleAppEngine。舊標(biāo)志仍然生效讀取X-Appengine-Remote-Addr頭但每次請求都會打印一條 deprecation 日志context.go 中ClientIP()的實現(xiàn)。需要更換讀頭順序時可調(diào)整Engine.RemoteIPHeaders默認(rèn)為[X-Forwarded-For, X-Real-IP]ClientIP()按該列表順序逐個嘗試取第一個能解析出有效 IP 的頭。配置完成后核對點就是兩個啟動日志無 trust-all 警告handler 打印的ClientIP:與代理鏈中的真實來源一致。更多細(xì)節(jié)可回到 docs/doc.md 的 Dont trust all proxies 一節(jié)。【免費下載鏈接】ginGin is a high-performance HTTP web framework written in Go. It provides a Martini-like API but with significantly better performance—up to 40 times faster—thanks to httprouter. Gin is designed for building REST APIs, web applications, and microservices.項目地址: https://gitcode.com/GitHub_Trending/gi/gin創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考