Захват трафика пугает: кажется, что это инструмент для специалистов по безопасности и что в нём тысячи непонятных строк. На деле это самый честный способ узнать, что происходит в сети, — честнее любых логов, потому что показывает то, что реально ушло в провод. Снимем один запрос к сайту целиком, от DNS до ответа, и посмотрим, что в нём видно, а что спрятано шифрованием.
Это шестая часть цикла «Что происходит, когда открываешь сайт».
Чем снимать
- tcpdump — есть почти на любом Linux-сервере, работает в консоли. Удобно снять на сервере, где нет графики;
- tshark — консольный Wireshark: понимает протоколы так же глубоко и умеет выводить отдельные поля;
- Wireshark — графический, для разбора на своём компьютере. Обычная схема: снять на сервере в файл, скачать, открыть в Wireshark.
Если на сервере нет tcpdump и нет прав root, но есть Docker, можно запустить контейнер с сетевыми утилитами в сети хоста: docker run --rm --net=host --cap-add=NET_RAW nicolaka/netshoot tcpdump …. Важно: интерфейс указывать явно (-i eth0), а фильтр писать без переменных оболочки.
Два вида фильтров — не путать
Фильтр захвата решает, что вообще записывать. Синтаксис BPF, тот же у tcpdump и Wireshark: host 203.0.113.22 and tcp port 443. Записанное мимо фильтра потеряно навсегда, зато файл маленький.
Фильтр отображения — синтаксис Wireshark, применяется к уже записанному: tls.handshake.type == 1, dns.qry.name contains "alekseychikun", tcp.analysis.retransmission. Его можно менять сколько угодно.
Правило: на сервере снимайте узко, но не слишком (весь обмен с нужным адресом), а разбирайтесь фильтром отображения.
Один запрос целиком
# записать 6 секунд обмена с резолвером и сайтом
tshark -i eth0 -a duration:6 -w /tmp/c.pcap -f "host 1.1.1.1 or host 203.0.113.22" &
dig alekseychikun.ru A @1.1.1.1 +short
curl -so /dev/null https://alekseychikun.ru/robots.txt
$ tshark -r /tmp/c.pcap
1 0.000000 198.51.100.10 → 1.1.1.1 DNS 99 Standard query A alekseychikun.ru
2 0.090584 1.1.1.1 → 198.51.100.10 DNS 103 Standard query response A alekseychikun.ru A 203.0.113.22
3 0.221905 198.51.100.10 → 203.0.113.22 TCP 74 58094 → 443 [SYN] MSS=1460 WS=128
4 0.251098 203.0.113.22 → 198.51.100.10 TCP 74 443 → 58094 [SYN, ACK] MSS=1460 WS=512
5 0.251160 198.51.100.10 → 203.0.113.22 TCP 66 58094 → 443 [ACK]
6 0.254232 198.51.100.10 → 203.0.113.22 TLS 1633 Client Hello (SNI=alekseychikun.ru)
8 0.347951 203.0.113.22 → 198.51.100.10 TLS 1514 Server Hello, Change Cipher Spec, Application Data
12 0.348046 203.0.113.22 → 198.51.100.10 TLS 2962 Application Data
14 0.348052 203.0.113.22 → 198.51.100.10 TLS 657 Application Data, Application Data, Application Data
16 0.349910 198.51.100.10 → 203.0.113.22 TLS 130 Change Cipher Spec, Application Data
17 0.350168 198.51.100.10 → 203.0.113.22 TLS 202 Application Data
…
В тридцати строках — вся история из прошлых частей: DNS-вопрос и ответ за 90 мс, тройное рукопожатие за 29 мс, приветствие TLS, ответ сервера, и дальше — сплошное Application Data.
Что видно в HTTPS тому, кто смотрит со стороны
Представьте, что этот захват снял не я, а кто-то на пути: провайдер, администратор публичной сети, сосед по Wi-Fi без шифрования. Что он узнает:
| Видно | Откуда |
|---|---|
| какое имя вы спросили у DNS и какой адрес получили | обычный DNS идёт открытым текстом (строки 1–2) |
| с каким адресом и портом вы соединились | заголовки IP и TCP не шифруются |
| имя сайта | поле SNI в приветствии TLS — открытым текстом, иначе сервер не понял бы, какой сертификат показать |
| какие протоколы поддерживаете | там же: h2,http/1.1 |
| сколько байт и когда передано | длины пакетов и время |
Поле SNI можно вытащить одной командой — так это и делают системы, которые фильтруют трафик по имени сайта:
$ tshark -r /tmp/c.pcap -Y "tls.handshake.type==1" -T fields \
-e frame.len -e tls.handshake.extensions_server_name -e tls.handshake.extensions_alpn_str
1633 alekseychikun.ru h2,http/1.1
Что не видно
- адрес страницы:
/robots.txtв захвате нет. Путь, параметры, всё после имени сайта едет внутри шифрования; - заголовки и куки, включая авторизацию;
- содержимое — и запроса, и ответа;
- даже сертификат: в TLS 1.3 он уже зашифрован, поэтому после
Server HelloWireshark показывает толькоApplication Data. В TLS 1.2 сертификат шёл открыто.
Обратите внимание на строку 6: Wireshark подписал приветствие «TLSv1.2», хотя соединение — 1.3. Это не ошибка: ради совместимости со старым оборудованием TLS 1.3 притворяется в заголовке версией 1.2, а настоящая версия согласуется в расширении. Верить надо строке Server Hello и выводу curl -v.
Но и по размерам многое понятно
Не читая содержимого, по захвату видно: в строках 8–14 сервер отправил около 6,4 КБ — это сертификаты и подпись, такого размера ответ бывает только на рукопожатии. Дальше маленькие пакеты — запрос и короткий ответ. Если бы мы скачивали картинку, был бы длинный поток крупных пакетов в одну сторону. По длинам и времени можно отличить просмотр страницы от загрузки файла или видеозвонка — шифрование этого не прячет.
Разбор в Wireshark: пять фильтров, которые нужны чаще всего
| Фильтр | Зачем |
|---|---|
tcp.flags.syn == 1 && tcp.flags.ack == 0 | все попытки начать соединение — сколько их и к кому |
tcp.analysis.retransmission | повторные отправки: признак потерь |
tcp.flags.reset == 1 | кто и когда оборвал соединение |
tls.handshake.type == 1 | приветствия TLS с именами сайтов |
dns && dns.flags.rcode != 0 | DNS-ответы с ошибкой: NXDOMAIN, SERVFAIL |
Ещё полезно меню Statistics → Conversations (кто с кем и сколько байт) и правый клик по пакету → Follow → TCP Stream: весь обмен одного соединения подряд.
Этика и здравый смысл
Снимайте свой трафик и трафик своих серверов. Захват в чужой сети без разрешения — не «отладка», а перехват. И не выкладывайте файлы захвата целиком: в них адреса, имена и, если где-то нет шифрования, пароли.
Соединение рвётся, а в логах пусто?
Пришлите захват или описание — найду, на каком шаге обрывается и кто его обрывает.
// загружаю комментарии…