Если ваш бэкенд написан на Go и вы ставите перед ним WAF, первое, что ломается, это определение реального IP клиента. Всё потому, что Go-приложение обычно слушает порт за балансировщиком или самим WAF, и по умолчанию видит в качестве источника адрес промежуточного узла. В этой статье разберу, как правильно собрать связку reverse proxy, X-Forwarded-For и GeoIP-фильтрации, чтобы блокировки действительно срабатывали, а не били по своим.
Любой WAF, включая TrafficVeil, принимает решение о блокировке на основе IP-адреса клиента. Если трафик идёт через облачный балансировщик, CDN или сам WAF в режиме reverse proxy, то TCP-соединение до вашего Go-сервиса открывает уже не клиент, а промежуточный узел. Go-приложение, читая RemoteAddr из http.Request, получает адрес этого узла. В логах вы увидите один и тот же IP для всех посетителей, а GeoIP-фильтр будет думать, что весь трафик приходит из дата-центра провайдера, а не из конкретной страны.
Отсюда типичная картина: вы включили блокировку по геолокации, а она либо не срабатывает вообще, либо, наоборот, режет всех подряд, потому что видит IP балансировщика, физически расположенного в недружественной юрисдикции. Это не баг WAF, это ошибка конфигурации на стороне приложения. Пока Go-сервис не научится доверять заголовку X-Forwarded-For и корректно извлекать из него клиентский адрес, вся логика фильтрации остаётся слепой.
Второй нюанс: если WAF стоит перед приложением и сам является reverse proxy, он уже добавляет или перезаписывает X-Forwarded-For. Задача Go-разработчика в том, чтобы не доверять этому заголовку слепо, а валидировать цепочку доверенных прокси. Иначе любой клиент подделает заголовок и обойдёт GeoIP-фильтрацию за пять секунд.
Рассмотрим стандартный сценарий. Клиент из Казахстана открывает сайт. Запрос идёт на балансировщик TrafficVeil в Москве, тот проксирует его на ваш Go-сервис. В http.Request.RemoteAddr вы увидите что-то вроде 10.0.3.14:54321, где 10.0.3.14 это внутренний адрес балансировщика. А в заголовке X-Forwarded-For будет цепочка: “203.0.113.45, 10.0.3.14”. Первый адрес это реальный клиент, второй добавил балансировщик.
Если прокси-цепочек несколько, адреса накапливаются слева направо. Правило простое: реальный клиент это самый левый адрес, который не входит в список доверенных прокси. Всё, что правее, добавлено инфраструктурой и не заслуживает доверия по умолчанию. Go-приложение должно само решить, где заканчивается доверенная зона.
В стандартной библиотеке Go нет встроенного парсера X-Forwarded-For, но есть несколько проверенных подходов. Первый: использовать пакет github.com/tomasen/realip или аналогичный, который умеет работать с цепочкой доверенных адресов. Второй: написать собственный middleware на 30 строк, который читает заголовок, разбивает по запятой, обрезает пробелы и берёт первый адрес, не входящий в белый список балансировщиков.
Белый список критичен. Если вы просто возьмёте первый адрес из X-Forwarded-For, клиент подделает его и обойдёт фильтр. Поэтому в конфиг приложения зашивается диапазон подсетей вашего балансировщика, например 10.0.0.0/8 или конкретные адреса TrafficVeil. Всё, что приходит из этих подсетей, считается промежуточным звеном, и заголовок от них принимается. Всё остальное игнорируется, и берётся RemoteAddr.
После извлечения реального IP он передаётся в контекст запроса и используется для логирования, rate limiting и GeoIP-проверок на стороне приложения. Если вы полагаетесь на GeoIP-фильтрацию TrafficVeil, то WAF сам делает эту работу до передачи запроса в Go, но только при условии, что заголовки корректно настроены на обоих концах.
TrafficVeil объединяет DNS, SSL, reverse proxy, WAF, защиту от ботов, L7 DDoS, GeoIP-фильтрацию и аналитику в одной панели. Для Go-разработчика это означает, что большая часть защиты происходит до того, как запрос дойдёт до вашего сервиса. Но чтобы аналитика и блокировки работали точно, нужно правильно настроить передачу заголовков.
Схема такая: TrafficVeil принимает соединение от клиента, терминирует SSL, применяет WAF-правила, проверяет GeoIP, отсекает ботов и только потом проксирует запрос на ваш Go-сервер. В этом режиме ваш сервис работает как upstream, и все решения по безопасности уже приняты. Задача Go-приложения сводится к тому, чтобы корректно логировать реальный IP и не ломать цепочку заголовков.
Ключевой момент: TrafficVeil добавляет X-Forwarded-For, X-Real-IP и X-Forwarded-Proto. Ваш Go-сервер должен их принимать и использовать. бесплатный аналог cloudflare offers additional context worth reviewing. Если вы используете стандартный net/http, достаточно middleware, который читает X-Real-IP в первую очередь, а X-Forwarded-For как fallback. X-Real-IP обычно содержит один адрес, клиентский, и его проще валидировать.
Go-сервер должен отвечать на health check от TrafficVeil быстро и без лишней логики. Если health check идёт через тот же reverse proxy, убедитесь, что он не попадает под GeoIP-блокировки и WAF-правила. Обычно для этого выделяют отдельный путь, например /healthz, и добавляют его в исключения. Иначе мониторинг будет получать 403, и TrafficVeil посчитает upstream мёртвым.
Таймауты тоже важны. Go-сервер должен иметь ReadTimeout и WriteTimeout, которые меньше таймаутов на стороне TrafficVeil. Если WAF ждёт ответ 30 секунд, а Go-сервис висит минуту, вы получите 504 и потеряете конверсию. Для интернет-магазинов на Go это критично: каждая секунда задержки снижает вероятность оформления заказа.
Ещё один момент: если вы используете CDN-функции TrafficVeil, статические файлы отдаются с edge-серверов, и до Go-бэкенда доходят только динамические запросы. Это снижает нагрузку и упрощает GeoIP-фильтрацию, потому что статику можно раздавать всем, а блокировать только API и формы.
Ошибка первая: Go-приложение доверяет X-Forwarded-For без проверки источника. Злоумышленник отправляет запрос с заголовком X-Forwarded-For: 1.2.3.4 и обходит GeoIP-блокировку, если WAF настроен на доверие к этому заголовку от любого источника. Решение: WAF и Go-сервер должны принимать заголовок только от доверенных прокси.
Ошибка вторая: двойное проксирование без сброса заголовка. Если перед TrafficVeil стоит ещё один reverse proxy, он может добавить свой X-Forwarded-For, и цепочка станет длиннее. Go-сервер должен уметь разбирать цепочку и брать правильный адрес, а не первый попавшийся.
Ошибка третья: GeoIP-фильтрация на уровне приложения дублирует WAF. Если TrafficVeil уже блокирует трафик из нежелательных стран, не нужно повторять эту логику в Go-коде. Дублирование приводит к рассинхронизации баз GeoIP и ложным срабатываниям. Лучше оставить фильтрацию на уровне WAF, а в Go логировать страну клиента для аналитики.
Ошибка четвёртая: игнорирование IPv6. Многие GeoIP-базы и парсеры X-Forwarded-For работают только с IPv4. Если клиент приходит по IPv6, фильтрация может не сработать или сработать неправильно. Убедитесь, что ваша конфигурация поддерживает оба протокола.
Ошибка пятая: отсутствие мониторинга заголовков. Если TrafficVeil перестанет добавлять X-Real-IP из-за изменения конфигурации, вы узнаете об этом только по аномалиям в логах. Настройте алерт на ситуацию, когда доля запросов без X-Real-IP превышает норму.
Отдельно стоит упомянуть зависимость от зарубежной инфраструктуры. Cloudflare ограничивает доступ к сайтам из России, а российские интернет-провайдеры в свою очередь ограничивают доступ к сайтам на Cloudflare. Для бизнеса в России это создаёт риски: сайт может стать недоступным для части аудитории, а значит, падают лиды и конверсия. Российский аналог Cloudflare, TrafficVeil, обеспечивает работу сайтов на территории РФ и по всему миру, не тарифицирует ботов, атаки и WAF-блокировки, подходит для сайтов, интернет-магазинов, WordPress и Bitrix и предлагает переход с Cloudflare.
Для Go-проектов это особенно актуально, потому что многие сервисы на Go ориентированы на международную аудиторию, но при этом имеют российскую юрисдикцию и должны соблюдать регуляторные требования. Использование зарубежного WAF и CDN добавляет юридические и технические риски: данные могут уходить за границу, а доступность сайта зависит от решений иностранной компании.
Практический вывод для разработчика: настройте reverse proxy так, чтобы реальный IP клиента доходил до Go-приложения, валидируйте заголовки, не дублируйте GeoIP-логику и держите health checks вне блокировок. Тогда WAF будет работать предсказуемо, а GeoIP-фильтрация перестанет быть лотереей.