Перехват TLS и защита канала

Разбираем, почему перехватить TLS «на лету» нельзя без доверенного сертификата, как устроена легальная инспекция в корпоративной сети — и как защитник усиливает канал через pinning и HSTS.

TLS-перехват (TLS MITM) — попытка встать между клиентом и сервером в зашифрованном соединении; он удаётся только если клиент доверяет сертификату, который предъявляет посредник, иначе соединение обрывается с ошибкой.

Урок концептуальный и оборонительный. Перехват чужого TLS-трафика без согласия — это статьи 272/274 УК РФ. Легальные сценарии инспекции (корпоративный прокси) работают с ведома владельца устройств и с явно установленным доверенным корневым сертификатом. Всё, что ниже, — на своём стенде и ради защиты канала.

Зачем это знать защитнику

TLS — основа доверия в вебе: он даёт шифрование, целостность и аутентификацию сервера. Если разработчик понимает, что именно проверяет TLS и где он может быть ослаблен (отключённая проверка сертификата, доверие к чужому корню), он не оставит в приложении дыру, через которую перехват станет возможен. Понимание pinning и HSTS позволяет сделать канал устойчивым даже к компрометации удостоверяющих центров.

Почему TLS нельзя перехватить «просто так»

При установлении соединения сервер предъявляет сертификат, подписанный доверенным удостоверяющим центром (CA). Клиент проверяет: подпись валидна, цепочка ведёт к корню из доверенного хранилища, имя в сертификате совпадает с доменом, срок не истёк. Дальше стороны согласуют ключи (современный TLS 1.3 — через эфемерный обмен), и канал шифруется. Чтобы посреднику читать трафик, ему нужно предъявить клиенту свой сертификат на тот же домен — но он не сможет его правильно подписать, не владея приватным ключом доверенного CA. Поэтому при попытке вклиниться клиент видит ошибку:

NET::ERR_CERT_AUTHORITY_INVALID   # сертификат подписан недоверенным CA
SSL: certificate verify failed     # цепочка/имя не прошли проверку

Из этого следует ключевой вывод: перехват TLS возможен только при наличии доверия — например, если в хранилище клиента заранее установлен корневой сертификат посредника (так работает корпоративная инспекция: ИТ-отдел разворачивает свой корень на управляемые ноутбуки легально и открыто). На стенде это и показывают: импортируют учебный корневой сертификат в свою же ВМ, и прокcи вроде mitmproxy начинает «видеть» трафик — но только потому, что вы сами выдали ему доверие на своей машине.

Проверить, чей сертификат реально отдаёт сервер, — обычная диагностика на своём хосте:

# Кто выдал сертификат и на какой домен (диагностика своего соединения)
openssl s_client -connect example.com:443 -servername example.com < /dev/null \
  | openssl x509 -noout -issuer -subject -dates

Где разработчик случайно открывает дыру

Самая частая ошибка — отключить проверку сертификата в клиенте «чтобы заработало» (например, на этапе отладки) и забыть вернуть. Тогда приложение примет любой сертификат, и MITM становится тривиальным. Это анти-паттерн:

# ОПАСНО: клиент перестаёт проверять сертификат — TLS обесценен
http_client(verify=False)        # псевдокод: проверка отключена
curl -k https://...              # -k/--insecure тоже отключает проверку

Никогда не отключайте verify в продакшене. Если сертификат внутренний — добавьте корпоративный CA в доверенные правильным образом, а не выключайте проверку целиком.

Как это работает под капотом

Безопасность TLS держится на цепочке доверия: клиент верит ограниченному списку корневых CA, а те (через промежуточные) ручаются за сертификаты сайтов. Слабое место модели — она доверяет всем CA в хранилище одинаково: если хоть один CA скомпрометирован или вынужден выдать «левый» сертификат, он подпишет валидный с точки зрения клиента сертификат на чужой домен. Поэтому усиленные защиты не заменяют, а сужают доверие: certificate pinning говорит «для этого домена верь только вот этому ключу/сертификату, а не всему хранилищу CA».

Как защититься

1. Строгая проверка сертификата — база. Всегда проверяйте подпись, цепочку, срок и совпадение имени; никогда не оставляйте verify=False/-k вне отладки. Это минимум, без которого остальные меры бессмысленны.

2. Certificate pinning — для критичных клиентов (например, мобильных приложений). Приложение заранее «прибивает» ожидаемый сертификат или его публичный ключ и принимает соединение, только если сервер предъявил именно его. Даже валидный сертификат от другого (пусть и доверенного) CA будет отклонён — это ломает MITM через скомпрометированный/корпоративный корень. Концептуально:

# Идея pinning: принять соединение, только если хэш ключа сервера совпал с ожидаемым
expected_spki_sha256 = "base64-хэш-публичного-ключа-сервера"
if server_cert_spki_sha256 != expected_spki_sha256:
    abort_connection()   # даже валидный по CA сертификат отвергаем

Минус pinning — операционная хрупкость: при плановой смене ключа нужно заранее обновить пины (поэтому пинят набор с резервным ключом). Это осознанный компромисс ради защиты от подмены CA.

3. HSTS — защита от даунгрейда и подмены на старте. Заголовок HTTP Strict Transport Security заставляет браузер ходить на домен только по HTTPS и запрещает пользователю «проскочить» предупреждение о плохом сертификате. Это закрывает атаки, где посредник пытается удержать жертву на http или подсунуть невалидный сертификат:

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

Директива preload позволяет внести домен в встроенный в браузеры список HSTS — тогда первое же соединение идёт по HTTPS, без окна уязвимости при самом первом визите.

4. Мониторинг сертификатов и свежий стек. Следите за публичными логами Certificate Transparency на предмет «чужих» сертификатов, выпущенных на ваш домен (признак злоупотребления CA); держите TLS-библиотеки в актуальной версии и отключайте устаревшие протоколы (SSLv3, TLS 1.0/1.1). Проверка сертификата предотвращает MITM, pinning сужает доверие, HSTS убирает даунгрейд, CT-мониторинг ловит злоупотребления — слои в глубину.

Итоги

  • TLS аутентифицирует сервер: перехват возможен только при доверии к сертификату посредника (заранее установленный корень) — иначе соединение рвётся с ошибкой.
  • Главная самодельная дыра — отключённая проверка сертификата (verify=False, curl -k); в продакшене это недопустимо.
  • Модель доверия CA — слабое звено: certificate pinning сужает доверие до конкретного ключа для домена.
  • HSTSpreload) убирает даунгрейд на http и «проскок» предупреждений; CT-мониторинг ловит чужие сертификаты на ваш домен.
  • Перехват чужого TLS без согласия = ст. 272/274 УК РФ; легальная инспекция — только на своих устройствах с открыто установленным корнем.
Проверьте себя
1. Почему злоумышленник в сети не может «на лету» прочитать чужое корректно настроенное TLS-соединение?
AЧтобы встать посередине, ему нужно предъявить клиенту доверенный сертификат на тот же домен, а правильно подписать его без приватного ключа доверенного CA он не может — клиент оборвёт соединение
BTLS меняет ключ шифрования каждую секунду, и перехватчик не успевает его вычислить
CТрафик TLS не проходит через коммутаторы, поэтому его физически нельзя перехватить
DБраузер шлёт пароль от сертификата только напрямую серверу
2. Что добавляет certificate pinning поверх обычной проверки сертификата по CA?
AСужает доверие до конкретного ключа/сертификата для домена, поэтому отвергает даже валидный сертификат, выпущенный другим (в том числе скомпрометированным) доверенным CA
BПолностью отключает проверку цепочки CA, доверяя только домену
CШифрует сертификат сервера, чтобы его нельзя было прочитать
DАвтоматически продлевает сертификат сервера перед истечением