← Назад в базу знаний

TLS-инспекция и MITM: как VPN и прокси видят ваш зашифрованный трафик

TLS-инспекция и MITM: как VPN и прокси видят ваш зашифрованный трафик

Терминология: чем отличается инспекция от перехвата

TLS-инспекция — это процесс расшифровки, анализа и повторного шифрования трафика. MITM (Man-in-the-Middle) — это техника, которая для этого используется. Разница принципиальная: инспекция — легальный инструмент корпоративной безопасности, MITM — атака.

Но технически это одно и то же. Прокси встаёт между клиентом и сервером, притворяясь сервером для клиента и клиентом для сервера. Клиент видит сертификат прокси, а не оригинальный. Если клиент доверяет корневому сертификату прокси — всё работает прозрачно.

Как устроен TLS handshake

Разберём на пальцах. Клиент шлёт ClientHello с списком поддерживаемых шифров. Сервер отвечает ServerHello, выбирает шифр, отдаёт сертификат. Клиент проверяет подпись сертификата через цепочку доверия к корневому CA. После этого генерируется pre-master secret, шифруется публичным ключом сервера и отправляется обратно. Обе стороны вычисляют session keys.

Прокси при MITM делает то же самое, но дважды: один handshake с клиентом (со своим сертификатом), второй — с реальным сервером. Ключевой момент — клиент должен доверять корневому сертификату прокси. Без этого браузер покажет ошибку.

Технические детали: как прокси расшифровывает трафик

Когда прокси имеет доступ к session keys, он может расшифровать любой поток. Это работает на уровне TCP-прокси, который терминирует TLS-соединение. Пример на nginx:

```nginx

http {

server {

listen 443 ssl;

ssl_certificate /etc/nginx/certs/proxy.crt;

ssl_certificate_key /etc/nginx/certs/proxy.key;

location / {

proxy_pass https://backend-server;

proxy_ssl_certificate /etc/nginx/certs/backend.crt;

proxy_ssl_certificate_key /etc/nginx/certs/backend.key;

}

}

}

```

Здесь nginx выступает MITM: клиент видит proxy.crt, backend видит backend.crt. Всё прозрачно для обеих сторон, но nginx видит весь трафик в открытом виде.

Certificate Pinning: защита от MITM

Certificate Pinning — это когда клиент жёстко зашивает отпечаток (fingerprint) сертификата сервера. Даже если прокси имеет доверенный корневой сертификат, он не сможет подделать конкретный сертификат с правильным pin.

Реализация на Python:

```python

import ssl

import socket

import hashlib

hostname = 'api.example.com'

port = 443

pinned_fingerprint = 'AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99'

context = ssl.create_default_context()

with socket.create_connection((hostname, port)) as sock:

with context.wrap_socket(sock, server_hostname=hostname) as ssock:

cert = ssock.getpeercert(binary_form=True)

fingerprint = hashlib.sha256(cert).hexdigest()

if fingerprint != pinned_fingerprint.replace(':', '').lower():

raise Exception('Certificate pinning failed')

```

Браузеры используют HPKP (HTTP Public Key Pinning), но он deprecated. Современные приложения часто реализуют pinning на уровне кода.

Как VPN видит трафик

VPN работает на сетевом уровне (L3), а не на прикладном (L7). Он шифрует весь IP-пакет целиком, но не может заглянуть внутрь TLS-сессии. VPN видит только то, что идёт на IP-адрес и порт 443. Без TLS-инспекции содержимое остаётся зашифрованным.

Но есть нюанс: DNS-запросы. Если VPN не использует собственный DNS, запросы уходят через системный резолвер. Это позволяет провайдеру видеть, какие домены вы посещаете, даже без расшифровки трафика. SNI (Server Name Indication) тоже передаётся открыто в TLS-handshake.

SNI и ECH: как скрыть домены

SNI — это поле в ClientHello, которое содержит имя сервера. Оно передаётся открыто. Любой прокси на пути видит, к какому домену вы обращаетесь. Решение — ECH (Encrypted Client Hello), ранее известный как ESNI. ECH шифрует SNI с помощью публичного ключа сервера, полученного через DNS.

Проблема ECH — поддержка. На момент 2024 года ECH работает только в Firefox и частично в Chrome. Cloudflare поддерживает ECH на своих серверах, но большинство сайтов — нет.

Кейс: корпоративный прокси на Squid

Пример: компания использует Squid 6.0 с SSL-Bump для инспекции трафика. Настройка:

```bash

http_port 3128 ssl-bump generate-host-certificates=on dynamic_cert_mem_cache_size=4MB cert=/etc/squid/certs/squid.pem

ssl_bump peek all

ssl_bump bump all

sslproxy_cert_error allow all

```

Проблема: пользователи получают ошибки сертификатов на сайтах с HPKP. Решение: добавить исключения для финансовых приложений:

```bash

ssl_bump splice acl_NoBump

acl_NoBump dstdomain .bank.com

```

Splice — это режим, при котором Squid пропускает трафик без расшифровки. Это костыль, но работает.

Кейс: MITM-атака на публичном Wi-Fi

Пример: злоумышленник разворачивает точку доступа с именем "Free_WiFi" и поднимает прокси с самоподписанным сертификатом. Клиент не проверяет сертификаты — атака успешна. Атакующий получает логины, пароли, cookie.

Технические детали: атакующий использует Bettercap или mitmproxy, настраивает iptables для перенаправления порта 80/443 на прокси. Для HTTPS создаёт корневой CA и устанавливает его в систему жертвы. Если жертва не заметила предупреждение браузера — всё, трафик открыт.

Кейс: TLS-инспекция на провайдере

Пример: провайдер в стране с авторитарным режимом внедряет DPI (Deep Packet Inspection) с TLS-инспекцией. Пользователи с Android и iOS получают ошибки сертификатов при подключении к Google и Facebook. Причина: мобильные ОС не доверяют корневому сертификату провайдера.

Решение для пользователей: VPN с шифрованием поверх TLS. Но если VPN-сервер тоже находится под контролем — бесполезно. Единственный выход — ECH и собственный DNS-over-HTTPS.

Как проверить, видит ли прокси ваш трафик

Метод: сравнить отпечаток сертификата с эталонным. Используем openssl:

```bash

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -fingerprint -sha256

```

Если отпечаток отличается от того, что публикует владелец сайта — вы под MITM. Для автоматизации можно использовать скрипт:

```python

import ssl

import socket

def get_cert_fingerprint(hostname, port=443):

context = ssl.create_default_context()

with socket.create_connection((hostname, port), timeout=5) as sock:

with context.wrap_socket(sock, server_hostname=hostname) as ssock:

cert = ssock.getpeercert(binary_form=True)

import hashlib

return hashlib.sha256(cert).hexdigest()

expected = 'abc123...'

actual = get_cert_fingerprint('example.com')

print(f"Expected: {expected}")

print(f"Actual: {actual}")

```

Что делать, если обнаружен MITM

Первое — не паникуйте. Проверьте, доверяете ли вы корневому сертификату прокси. Если это корпоративная сеть — это нормально. Если нет — меняйте пароли, используйте VPN с собственными сертификатами, включайте ECH в браузере.

Второе — используйте TLS 1.3. Он имеет forward secrecy по умолчанию, что затрудняет расшифровку даже при наличии session keys. Но не спасает от MITM, потому что прокси сам участвует в handshake.

Итоговая таблица: кто что видит

| Компонент | Видит SNI | Видит домены через DNS | Видит содержимое TLS |

|-----------|-----------|------------------------|----------------------|

| Провайдер | Да | Да (если DNS не зашифрован) | Нет |

| VPN без TLS-инспекции | Да | Нет (если свой DNS) | Нет |

| Корпоративный прокси с SSL-Bump | Да | Да | Да |

| MITM-атака на Wi-Fi | Да | Да | Да (если клиент доверяет CA) |

| VPN с TLS-инспекцией | Да | Да | Да |

Защита от MITM: практические шаги

Используйте pinning в своих приложениях. Включайте ECH в браузере. Проверяйте сертификаты вручную для критичных сервисов. Для прокси с инспекцией — например, на lexic.ml — всегда проверяйте, что сертификат принадлежит именно тому, кому должен.

Если вы разработчик — не отключайте проверку сертификатов в коде. Это самая частая причина успешных MITM-атак. Один неправильный `verify=False` в Python-скрипте — и все данные уходят злоумышленнику.

Выводы

TLS-инспекция — это палка о двух концах. С одной стороны, корпоративная безопасность невозможна без неё. С другой — она создаёт точки отказа и риски. MITM-атаки используют те же механизмы, но с злым умыслом. Разница только в том, доверяете ли вы корневому сертификату.

Проверяйте сертификаты, используйте ECH, не отключайте проверки в коде. И помните: даже с TLS 1.3 и forward secrecy, если прокси участвует в handshake — он видит всё. Шифрование защищает от посторонних, но не от тех, кому вы доверили свой корневой сертификат.

✔️Купить прокси