Skip to content

Защита от SSRF

SSRF (Server-Side Request Forgery, подделка серверных запросов) — атака, при которой злоумышленник побуждает сервер отправлять запросы во внутреннюю сеть. Возможные последствия: кража учётных данных метаданных облачных instances (токены IAM-ролей), сканирование портов и сервисов intranet, обращение к неавторизованным внутренним административным интерфейсам, обход firewall для доступа к защищённым ресурсам. HTTPC включает защиту SSRF по умолчанию, блокируя соединения с приватными/зарезервированными диапазонами IP.

Поведение по умолчанию

go
cfg := httpc.DefaultConfig()
// AllowPrivateIPs = false (по умолчанию) → блокируются все приватные/зарезервированные IP

AllowPrivateIPs по умолчанию false, валидация SSRF на уровне диалера полностью включена. Это отличается от проверки только имени хоста в URL — HTTPC проверяет разрешённый IP при фактическом установлении TCP-соединения, что защищает от перепривязки DNS (см. ниже).

Блокируемые диапазоны IP

HTTPC блокирует все IP-адреса, не подходящие для публичной связи, покрывая IPv4, IPv6 и их обходные варианты.

Блокируемые диапазоны IPv4

ДиапазонCIDRОписание
Loopback127.0.0.0/8localhost (включая весь диапазон 127.x.x.x)
Класс A приватные10.0.0.0/8Внутренняя сеть (RFC 1918)
Класс B приватные172.16.0.0/12Внутренняя сеть (RFC 1918)
Класс C приватные192.168.0.0/16Внутренняя сеть (RFC 1918)
Link-local169.254.0.0/16Автоконфигурация (включая метаданные AWS/Azure)
CGNAT100.64.0.0/10Carrier-grade NAT (включая метаданные Alibaba Cloud 100.100.100.200)
Класс E зарезервированные240.0.0.0/4Зарезервированные адреса (ip4[0] >= 240)
«Эта сеть»0.0.0.0/8Идентификатор данной сети (ip4[0] == 0)
Выделения IETF протокол192.0.0.0/24Специальное назначение
TEST-NET-1192.0.2.0/24Документация (RFC 5737)
TEST-NET-2198.51.100.0/24Документация (RFC 5737)
TEST-NET-3203.0.113.0/24Документация (RFC 5737)
6to4 relay192.88.99.0/24Устаревший anycast

Кроме того, блокируются диапазоны, покрываемые IsLoopback, IsPrivate, IsLinkLocalUnicast, IsLinkLocalMulticast, IsMulticast, IsUnspecified.

Блокируемые диапазоны IPv6

ДиапазонCIDRОписание
Loopback::1/128localhost
Уникальные локальныеfc00::/7Внутренняя сеть (соответствует приватным IPv4)
Link-localfe80::/10Автоконфигурация
Префикс документации2001:db8::/32Документация (RFC 3849)
NAT6464:ff9b::/96Рекурсивная проверка встроенного IPv4

Защита от обхода

HTTPC дополнительно блокирует следующие распространённые приёмы обхода SSRF:

ПриёмПримерЗащита
IPv4-mapped IPv6::ffff:127.0.0.1Нормализация к IPv4 с последующей проверкой
Десятичное целое2130706433 (= 127.0.0.1)Распознавание как традиционного IP-литерала с блокировкой
Шестнадцатеричное0x7f000001, 0x7f.0.0.1Распознавание префикса 0x с блокировкой
Восьмеричное0177.0.0.1Распознавание ведущих нулей с блокировкой
Встроенный NAT6464:ff9b::7f00:1Рекурсивная проверка встроенного IPv4

TIP

Эта защита от обхода особенно важна в cgo-сборках: getaddrinfo может принимать традиционные IP-литералы и отображать их на приватные IP. HTTPC перехватывает эти формы до разрешения DNS.

Защита endpoint метаданных облака

Службы метаданных instances (IMDS) на облачных платформах — высокоценные цели SSRF-атак: один доступ позволяет похитить временные учётные данные. HTTPC по умолчанию блокирует эти адреса:

ПлатформаАдрес метаданныхМеханизм блокировки
AWS EC2169.254.169.254Блокировка link-local 169.254.0.0/16
Azure169.254.169.254Аналогично (блокировка link-local)
GCPmetadata.google.internalПроверка IP после разрешения DNS
Alibaba Cloud100.100.100.200Блокировка CGNAT 100.64.0.0/10

WARNING

Хотя метаданные AWS IMDSv2 требуют токен, SSRF всё ещё может сначала получить токен, а затем обратиться к данным. IP-блокировка HTTPC работает на более низком уровне, чем IMDSv2, напрямую перехватывая соединение. Рекомендуется комбинировать: блокировка HTTPC + включение IMDSv2 для эшелонированной обороны.

WARNING

Метаданные Alibaba Cloud (100.100.100.200) находятся в диапазоне CGNAT (100.64.0.0/10), который HTTPC блокирует по умолчанию. Если для VPN (Tailscale/WireGuard и др.) или внутренней маршрутизации действительно требуется доступ к 100.64.0.0/10, необходимо явно освободить через SSRFExemptCIDRs: []string{"100.64.0.0/10"} — после освобождения метаданные Alibaba Cloud в этом диапазоне также станут доступны, оцените риски.

Защита от перепривязки DNS

Перепривязка DNS (DNS Rebinding) — классический приём обхода SSRF-проверок. Злоумышленник контролирует DNS-сервер домена: первое разрешение возвращает публичный IP (проходит проверку), а при фактическом соединении возвращается 127.0.0.1 (обходит проверку).

HTTPC использует модель «разрешение - проверка - прямое подключение» для защиты от таких атак:

  1. Разрешение: домен разрешается в список IP
  2. Проверка: каждый IP проверяется на принадлежность к приватным/зарезервированным адресам
  3. Фильтрация: заблокированные IP удаляются, остаются только разрешённые (FilterAllowedIPs)
  4. Прямое подключение: прямое соединение с проверенным IP без повторного разрешения домена
go
// Сценарий атаки:
// 1. Злоумышленник контролирует DNS evil.com
// 2. На этапе проверки разрешение возвращает публичный IP (проходит валидацию)
// 3. Стандартный net/http повторно разрешает домен (теперь возвращает 127.0.0.1, обходя проверку)
//
// Защита HTTPC: при дозвоне используется уже проверенный IP без повторного разрешения домена

TIP

В среде «Split-Horizon DNS» (один домен разрешается в публичные и внутренние IP) FilterAllowedIPs HTTPC автоматически отфильтрует приватные IP и установит соединение только по публичным IP, вместо прямого отказа для всего домена.

Точные исключения SSRFExemptCIDRs

В микросервисной среде часто требуется доступ к сервисам внутри VPC, Kubernetes Service или VPN. SSRFExemptCIDRs позволяет точно освободить определённые диапазоны CIDR, сохраняя блокировку остальных приватных IP — это рекомендуемый способ доступа к внутренним сервисам.

go
cfg := httpc.DefaultConfig()
cfg.Security.SSRFExemptCIDRs = []string{
    "10.0.0.0/8",       // Внутренний VPC
    "100.64.0.0/10",    // Tailscale VPN
    "172.20.0.0/16",    // Kubernetes Service CIDR
}
client, _ := httpc.New(cfg)

Типовые варианты освобождения

СценарийCIDRОписание
Внутренние сервисы VPC10.0.0.0/8VPC по умолчанию AWS/GCP/Azure
Tailscale VPN100.64.0.0/10Сеть Tailscale (RFC 6598)
Kubernetes172.20.0.0/16 и др.Pod/Service CIDR
WireGuard10.13.0.0/16 и др.Пользовательская сеть VPN

Неверный CIDR приведёт к ошибке httpc.New() (например, SSRFExemptCIDRs: invalid CIDR "10.0.0/8"), конфигурация завершится ошибкой на этапе запуска, а не будет тихо пропущена во время выполнения.

WARNING

Освобождаемые CIDR должны быть максимально точными. Избегайте слишком больших диапазонов (например, 0.0.0.0/0) — это равносильно полному отключению защиты SSRF. Даже для 10.0.0.0/8 оцените возможность сужения до фактически используемых подсетей.

Сравнение AllowPrivateIPs и SSRFExemptCIDRs

Оба варианта позволяют обращаться к внутренним сервисам, но семантика безопасности совершенно разная:

АспектAllowPrivateIPs = trueSSRFExemptCIDRs
Состояние защитыПолный обход валидации SSRFОсвобождение только указанных CIDR, остальное блокируется
ОхватВсе приватные/зарезервированные/loopback/link-local IPТолько перечисленные CIDR
localhostРазрешёнПо умолчанию блокируется (если явно не освободить 127.0.0.0/8)
Метаданные облакаДоступны (опасно)По умолчанию блокируются
Уровень рискаВысокий — поверхность атаки равна отключению SSRFНизкий — точечное разрешение
РекомендацияТолько для тестов/полностью внутренних клиентовРекомендуется для продакшена

DANGER

AllowPrivateIPs = true полностью обходит валидацию SSRF на уровне диалера (не просто «разрешает приватные IP»), включая проверки localhost, link-local и всех зарезервированных адресов. Категорически нельзя использовать в продакшене при обработке любых недоверенных URL. Для доступа к внутренним сервисам предпочтите SSRFExemptCIDRs.

Освобождение приватных IP на уровне запроса

Если клиент в целом использует безопасные умолчания (AllowPrivateIPs = false), но отдельным запросам нужен доступ к intranet (например, endpoint проверки здоровья на localhost), используйте опцию запроса WithAllowPrivateIPs для поэтапного освобождения без глобального ослабления политики безопасности:

go
package main

import (
	"fmt"
	"log"

	"github.com/cybergodev/httpc"
)

func main() {
	// Клиент по умолчанию блокирует приватные IP; этот вызов освобождает на уровне запроса
	result, err := httpc.Get("http://localhost:8080/health",
		httpc.WithAllowPrivateIPs(true),
	)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Статус проверки здоровья: %d\n", result.StatusCode())
}

WARNING

Включайте WithAllowPrivateIPs(true) только для URL, которые надёжны и не поступают от пользовательского ввода. Цель защиты SSRF — не дать злоумышленнику заставить ваш процесс обращаться к внутренним endpoint; поэтапное отключение вновь открывает этот риск для данного вызова. Если весь клиент должен обращаться к внутренним сервисам, установите Security.AllowPrivateIPs = true в Config.

Обратное применение также работает: клиент настроен с AllowPrivateIPs = true (например, полностью внутренний клиент), но для отдельного запроса нужно принудительно включить проверку SSRF — используйте WithAllowPrivateIPs(false).

Проверка SSRF при перенаправлениях

Перенаправления — важный носитель SSRF-атак: публичный сервис может выполнить 302 на http://169.254.169.254/ (метаданные облака) или внутренний адрес. HTTPC выполняет SSRF IP-валидацию и для целей перенаправлений.

Конфигурация клиентаПоведение при перенаправлении на приватный IP
AllowPrivateIPs = false (по умолчанию)Блокировка — ошибка IP-валидации цели перенаправления
AllowPrivateIPs = trueРазрешение — обход SSRF (включая перенаправления)
WithAllowPrivateIPs(true) на уровне запросаРазрешение перенаправления на приватный IP для данного запроса
Попадание в SSRFExemptCIDRsРазрешение перенаправления в освобождённый CIDR
go
// Сценарий: запрос к public-api.com, сервер выполняет 302 на http://169.254.169.254/
// HTTPC проверяет IP цели перенаправления, блокируя доступ к службе метаданных облака

Белый список доменов перенаправлений

RedirectWhitelist накладывает контроль на уровне домена поверх IP-валидации, предотвращая уязвимости открытых перенаправлений:

go
cfg := httpc.DefaultConfig()
cfg.Security.RedirectWhitelist = []string{
    "api.example.com",
    "auth.example.com",
    "*.cdn.example.com", // Подстановочный знак: сопоставление строгих поддоменов
}
// Перенаправления на домены не из белого списка блокируются

Подстановочный знак *.example.com сопоставляется со строгими поддоменами api.example.com, static.cdn.example.com и т.п., но не с голым доменом example.com (нужно указывать отдельно). IsAllowed возвращает true (разрешить все) при nil белом списке.

Примеры конфигурации

Безопасная конфигурация (обработка пользовательских URL)

При обработке пользовательских URL используйте SecureConfig() для получения наиболее строгой защиты SSRF:

go
cfg := httpc.SecureConfig()
// AllowPrivateIPs = false (строгий SSRF)
// FollowRedirects = false (блокировка SSRF через перенаправления)
// MaxResponseBodySize = 5MB
client, _ := httpc.New(cfg)

Конфигурация внутренних сервисов (доступ к VPC)

Для доступа к внутренним сервисам VPC/Kubernetes используйте SSRFExemptCIDRs для точного освобождения:

go
cfg := httpc.DefaultConfig()
cfg.Security.SSRFExemptCIDRs = []string{
    "10.0.0.0/8",     // VPC
    "172.20.0.0/16",  // Kubernetes Service
}
client, _ := httpc.New(cfg)

Смешанная конфигурация (публичная сеть + intranet)

Один клиент обращается и к публичным API, и к внутренним сервисам, причём диапазон внутренних сервисов известен:

go
cfg := httpc.DefaultConfig()
cfg.Security.SSRFExemptCIDRs = []string{
    "10.50.0.0/16",   // Выделенная подсеть внутренних сервисов (точно)
}
cfg.Security.RedirectWhitelist = []string{
    "api.public.com",
    "*.internal.corp", // Разрешать перенаправления только на внутренние доверенные домены
}
client, _ := httpc.New(cfg)

Полное отключение защиты SSRF

Используйте только в тестовой среде. Два способа:

go
// Способ 1: TestingConfig (одновременно отключает проверку TLS и другие функции безопасности)
client, _ := httpc.New(httpc.TestingConfig())

// Способ 2: ручная настройка
cfg := httpc.DefaultConfig()
cfg.Security.AllowPrivateIPs = true
client, _ := httpc.New(cfg)

TestingConfig() выводит предупреждение безопасности в stderr в не-тестовой среде (см. Обзор безопасности).

DANGER

Никогда не устанавливайте AllowPrivateIPs = true в продакшене. Это равносильно полному отказу от защиты SSRF — злоумышленник сможет обращаться к метаданным облака, внутренним сервисам, административным интерфейсам.

Лучшие практики

  1. Используйте SecureConfig() как базовую линию безопасности для обработки недоверенных URL
  2. Освобождайте только необходимые диапазоны CIDR через SSRFExemptCIDRs, избегайте AllowPrivateIPs
  3. Настройте RedirectWhitelist для ограничения целевых доменов перенаправлений
  4. Отключайте перенаправления при обработке пользовательских URL (FollowRedirects = false)
  5. Регулярно аудитируйте конфигурацию SSRFExemptCIDRs, удаляйте неиспользуемые диапазоны
  6. Используйте AuditMiddleware для записи всех запросов — это поможет при ретроспективном анализе попыток SSRF-атак

Что дальше