Что такое MITM (man-in-the-middle) атака и как с ней бороться
Что проверяют
Различаете ли вы шифрование и проверку подлинности стороны. Канал можно честно зашифровать и всё равно отдать его посреднику, если сертификат не проверен. Для серверной позиции на Go вопрос быстро сводится к тому, что вы пишете в tls.Config и как поднимаете соединение между своими сервисами.
Как отвечать
Атакующий встаёт между сторонами, терминирует оба соединения и при желании правит содержимое, а обе стороны считают, что говорят напрямую. Встать посередине позволяют подмена ARP или DNS, подставная точка доступа, угон маршрута BGP, чужой корневой сертификат в хранилище устройства.
Защита строится на аутентификации, а не на самом факте шифрования:
- TLS с проверкой цепочки и имени хоста; в Go это поведение по умолчанию, отключают его руками.
- HSTS и отказ обслуживать открытый HTTP, чтобы посредник не снял TLS на редиректе.
- Взаимный TLS между своими сервисами: сертификат предъявляют обе стороны.
- Пиннинг там, где список доверенных центров вам не подконтролен.
tr := &http.Transport{TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
RootCAs: pool, // свой корень для внутреннего сервиса
}}Где спотыкаются
Ставят InsecureSkipVerify в истину, чтобы «временно заработало» с самоподписанным сертификатом. Флаг выключает и проверку цепочки, и сверку имени, то есть ровно ту защиту, о которой вопрос. Правильно положить свой корень в RootCAs, а при несовпадении имени задать ServerName.
Называют защитой второй фактор и VPN. Второй фактор не мешает посреднику работать внутри уже открытой сессии, а туннель переносит доверие на его оператора. Посредника выдерживают только методы с привязкой к адресу сайта, то есть WebAuthn.
Заканчивают TLS на балансировщике и считают вопрос закрытым, оставляя внутреннюю сеть открытым текстом. Периметр это не граница доверия: тот, кто попал внутрь, читает и правит трафик между сервисами.