Доверенные прокси
Gin позволяет указать, какие заголовки содержат реальный IP клиента (если есть), а также указать, каким прокси (или прямым клиентам) вы доверяете устанавливать эти заголовки.
Почему важна конфигурация доверенных прокси
Когда ваше приложение находится за обратным прокси (Nginx, HAProxy, облачным балансировщиком нагрузки и т.д.), прокси передаёт оригинальный IP-адрес клиента в заголовках, таких как X-Forwarded-For или X-Real-Ip. Проблема в том, что любой клиент может установить эти заголовки. Без правильной конфигурации доверенных прокси злоумышленник может подделать X-Forwarded-For чтобы:
- Обойти контроль доступа на основе IP — Если ваше приложение ограничивает определённые маршруты внутренним диапазоном IP (например,
10.0.0.0/8), злоумышленник может отправитьX-Forwarded-For: 10.0.0.1с публичного IP и полностью обойти ограничение. - Отравить логи и аудиторские записи — Поддельные IP делают расследование инцидентов ненадёжным, поскольку вы больше не можете отследить запросы до реального источника.
- Обойти ограничение частоты запросов — Если ограничение частоты привязано к
ClientIP(), каждый запрос может заявить другой IP-адрес, чтобы избежать ограничения.
SetTrustedProxies решает эту проблему, сообщая Gin, какие сетевые адреса являются легитимными прокси. Когда ClientIP() разбирает цепочку X-Forwarded-For, он доверяет только записям, добавленным этими прокси, и отбрасывает всё, что мог добавить клиент. Если запрос приходит напрямую (не от доверенного прокси), заголовки перенаправления полностью игнорируются, и используется необработанный удалённый адрес.
Используйте функцию SetTrustedProxies() на вашем gin.Engine для указания сетевых адресов
или CIDR сетей, от которых можно доверять заголовкам запросов клиентов,
связанным с IP. Это могут быть IPv4-адреса, IPv4 CIDR, IPv6-адреса или
IPv6 CIDR.
Внимание: Gin по умолчанию доверяет всем прокси, если вы не укажете доверенный
прокси с помощью указанной функции, это НЕ безопасно. В то же время, если вы не
используете прокси, вы можете отключить эту функцию с помощью Engine.SetTrustedProxies(nil),
тогда Context.ClientIP() будет возвращать удалённый адрес напрямую, избегая
ненужных вычислений.
import ( "fmt"
"github.com/gin-gonic/gin")
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()}Примечание: Если вы используете CDN-сервис, вы можете установить Engine.TrustedPlatform
для пропуска проверки TrustedProxies — он имеет более высокий приоритет, чем TrustedProxies.
Смотрите пример ниже:
import ( "fmt"
"github.com/gin-gonic/gin")
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()}