Сетевая безопасность/Сетевой стек и DNS
Рассмотрим, что будет происходить, когда Вы набираете URL в браузере и жмете Enter на примере запроса "google.com".
URL или нет?
Браузер определяет, что перед ним - URL или поисковый запрос. Если в запросе не получилось выделить протокол или доменное имя, браузер отправляет запрос в поиск, установленный по умолчанию.
Это URL
Поскольку в запросе "google.com" удалось распознать доменное имя, браузер будет обращаться к соответствующему веб-ресурсу. У браузера есть следующая информация (т.к. не указано иное):
- Использовать протокол HTTP
- Показать главную страницу («/»)
Проверка HSTS
Браузер проверяет, не находится ли сайт в списке preloaded HSTS (HTTP Strict Transport Security). Если да, обращение произойдет по HTTPS.
Сайт может не находиться в списке, но придерживаться политике HSTS, тогда на первый HTTP-запрос от пришлет ответ, содержащий информацию, что к нему требуется обращаться по HTTPS.
DNS
Далее необходимо определить IP-адрес соответствующего веб-ресурса.
Первым делом браузер проверит свой DNS-кэш.
Затем браузер вызывает библиотечную функцию gethostbyname. Осуществляется проверка наличия нужной записи в файле hosts.
Если не удалось найти нужный адрес в DNS кэше и файле hosts, gethostbyname отправляет ARP-запрос к сетевому DNS-серверу.
Если DNS-сервер, находится в той же подсети, то ARP-запрос отправляется напрямую этому серверу.
Если в другой подсети - запрос отправляется на IP-адрес шлюза по умолчанию (default gateway).
ARP
ARP (Address Resolution Protocol) — протокол канального уровня, предназначенный для определения MAC-адреса по IP-адресу.
Принцип работы
- A и B соединены по Ethernet. A известен IP-адрес B. A хочет передать B пакет данных.
- Задача: узнать MAC-адрес B.
- Принцип работы: A отправляет broadcast ARP-запрос по сегменту сети: «Хост с IP-адресом <ip_b>, сообщите свой MAC-адрес хосту с MAC-адресом <mac_a>».
- B получает ARP-запрос и отправляет A ARP-ответ со своим MAC.
Запрос к DNS-серверу
Перед отправкой запроса осуществляется проверка ARP-кэша на предмет наличия нужного IP-адреса.
После этого проверяется таблица маршрутизации — это делается для того, чтобы узнать, есть ли искомый IP-адрес в какой-либо из подсетей локальной таблицы.
На этом этапе мы знаем MAC-адрес локального DNS-сервера (или DNS-сервера на стороне провайдера)
DNS lookup
По UDP отправляется запрос локальному DNS серверу (на 53 порт).
DNS-сервер возвращает ответ. Если он «не знает» нужный IP, запускается рекурсивный поиск (пока не найдется SOA запись).
Подробнее про DNS
DNS (Domain Name System) - распределенная система для получения информации о доменах (например, получения IP-адреса по имени хоста, получения информации о маршрутизации почты).
Запись DNS
Запись состоит из следующих полей:
- имя (NAME) - доменное имя
- тип (TYPE)
- класс (CLASS) - тип сети. DNS была разработана как система, потенциально совместимая не только с TCP/IP стеком, но и с другими возможными типами сетей. Фактически это поле обычно содержит значение IN (означает Internet), но очень редко встречаются другие классы (см. ссылку в конце статьи).
- TTL - допустимое время хранения кэшированной записи на DNS-сервере
- длина поля данных (RDLEN) - содержится в некоторых типах записей
- поле данных (RDATA) - содержится в некоторых типах записей
Типы записей
- A - связывает имя хоста с адресом протокола IPv4
- AAAA - связывает имя хоста с адресом протокола IPv6
- CNAME (canonical name record) - псевдоним, переправление на другое имя
- MX (mail exchange) - сервер обмена почтой для данного домена
- NS (name server) - DNS-сервер для данного домена
- PTR (pointer) - обратная DNS-запись, связывает IP с FQDN
- SOA (start of authority) - указывает, на каком сервере хранится эталонная информация о данном домене
DNS клиент
DNS клиент - утилита, позволяющая осуществить доступ к системе DNS.
Примеры:
- nslookup
- dig
- Альтернативы с GUI
По умолчанию dig осуществляет поиск записи типа A:
Флаг -t позволяет задать желаемый тип записи:
Опция +short позволяет опустить всю дополнительную информацию, будет выведен только IP-адрес.
Scapy
Также можно просто вручную создать UDP-пакет и отправить его на DNS-сервер.
Для этого можно использовать Scapy - библиотеку для манипулирования сетевыми пакетами на языке Python. Она позволяет собрать сетевой пакет по уровням сетевого стека.
Пример: отправка Ping на google.com
Для формирования пакета p необходимо задать тип пакета на уровне протокола ICMP (на самом деле, в случае типа "echo-request" это не обязательно, так как этот тип будет установлен по умолчанию) и адрес получателя на уровне протокола IP.
Далее отправляем пакет с помощью функции sr1, ответ окажется в переменной r.
В результате в r окажется пакет типа echo-reply.
Пример: DNS запрос
Необходимо указать:
- Для уровня протокола DNS - разрешить рекурсивный поиск (параметр rd) и указать содержимое запроса
- Для уровня протокола UDP - указать порт (на самом деле, поскольку указан протокол DNS, обращение по умолчанию произойдет на 53 порт, так что достаточно просто обозначить, что обращение должно осуществляться по протоколу UDP, что видно далее в примере)
- Для уровня протокола IP - адрес локального DNS-сервера
В результате в пакете r получаем DNS-ответ.
DNSSEC
Исторически сложилось, что DNS разрабатывалась только как распределенная система, поэтому она не защищает пользователя от подмены предоставляемых ему данных.
Пример атаки: DNS cache poisoning - кэш доменных имен изменяется с целью возврата ложного IP-адреса.
DNSSEC - набор расширений DNS, направленный на обеспечение защиты клиентов от фальшивых данных. Все ответы DNSSEC имеют цифровую подпись, используется асимметричное шифрование.
DNSSEC не обеспечивает конфиденциальность данных, осуществляется только аутентификация отправляемых данных, сами данные не шифруются.
WHOIS
WHOIS - протокол прикладного уровня (и одноименная утилита для обращений к нему), базирующийся на протоколе TCP для получения информации о владельцах доменных имен и IP-адресов.
Используется для доступа к публичным серверам баз данных регистраторов IP-адресов и доменных имён.
Установка соединения
На этом этапе у нас есть IP-адрес нужного веб ресурса и порт для установки соединения.
Браузер осуществляет вызов функции socket системной библиотеки и запрашивает поток TCP сокета - AF_INET и SOCK_STREAM, формируется пакет для передачи.
Формирование пакета
- Транспортный уровень - собирается TCP-сегмент. В заголовок добавляется порт назначения, исходный порт выбирается из динамического пула ядра.
- Сетевой уровень - добавляется дополнительный IP-заголовок. Также включаются IP-адрес сервера назначения и адрес текущей машины — после этого пакет сформирован.
- Канальный уровень - добавляется заголовок кадра, включающий MAC-адрес сетевой карты компьютера, а также MAC-адрес шлюза. Если ядру ничего не известно о MAC-адресе шлюза, то для его нахождения отправляется широковещательный ARP-запрос.
Отправка пакета
По Ethernet/WiFi пакет доберётся до маршрутизатора, управляющего локальной подсетью. Затем он отправится на следующий роутер и т.д., пока не доберётся до сервера назначения.
Каждый маршрутизатор на пути будет извлекать адрес назначения из IP-заголовка и отправлять пакет на следующий хоп, уменьшая TTL. Если значение поля TTL достигнет нуля, пакет будет отброшен (это произойдёт также если у маршрутизатора не будет места в текущей очереди — например, из-за перегрузки сети).
TCP соединение
- Клиент выбирает номер начальной последовательности (ISN) и отправляет пакет серверу с установленным битом SYN для открытия соединения.
- Сервер получает пакет с битом SYN и, если готов к установлению соединения, то:
- Выбирает собственный номер начальной последовательности;
- Устанавливает SYN-бит, чтобы сообщить о выборе начальной последовательности;
- Копирует ISN клиента +1 в поле ACK и добавляет ACK-флаг для обозначения подтверждения получения первого пакета.
- Клиент подтверждает соединение путём отправки пакета:
- Увеличивает номер своей начальной последовательности;
- Увеличивает номер подтверждения получения;
- Устанавливает поле ACK.
- Данные передаются следующим образом:
- Когда одна сторона отправляет N байтов, то увеличивает значение поля SEQ на это число.
- Когда вторая сторона подтверждает получение этого пакета (или цепочки пакетов), она отправляет пакет ACK, в котором значение поля ACK равняется последней полученной последовательности.
- Закрытие соединения:
- Сторона, которая хочет закрыть соединение, отправляет пакет FIN;
- Другая сторона подтверждает FIN (с помощью ACK) и отправляет собственный FIN-пакет;
- Инициатор прекращения соединения подтверждает получение FIN отправкой собственного ACK.
TLS handshake
- Клиентский компьютер отправляет сообщение ClientHello серверу со своей версией протокола TLS, списком поддерживаемых алгоритмов шифрования и методов компрессии данных.
- Сервер отвечает клиенту сообщением ServerHello, содержащим версию TLS, выбранный метод шифрования, выбранные методы компрессии и публичный сертификат сервиса, подписанный центром сертификации. Сертификат содержит публичный ключ, который будет использоваться клиентом для шифрования оставшейся части процедуры «рукопожатия», пока не будет согласован симметричный ключ.
- Клиент подтверждает сертификат сервера с помощью своего списка центров сертификации. Если сертификат подписан центром из списка, то серверу можно доверять, и клиент генерирует строку псевдослучайных байтов и шифрует её с помощью публичного ключа сервера. Эти случайные байты могут быть использованы для определения симметричного ключа.
- Сервер расшифровывает случайные байты с помощью своего секретного ключа и использует эти байты для генерации своей копии симметричного мастер-ключа.
- Сервер генерирует собственный хеш, а затем расшифровывает полученный от клиента хеш, чтобы проверить, совпадёт ли он с собственным. Если совпадение обнаружено, сервер отправляет клиенту собственный ответ Finished, также зашифрованный симметричным ключом.
- После этого TLS-сессия передаёт данные приложения (HTTP), зашифрованные с помощью подтверждённого симметричного ключа.
HTTP
- Клиент отправляет серверу HTTP-запрос:
GET / HTTP/1.1 Host: google.com Connection: close (закрыть соединение по завершении взаимодействия) [другие заголовки] [пустая строка]
- Сервер отвечает:
200 OK [заголовки ответа] [пустая строка] [контент HTML-страницы www.google.com] и закрывает соединение (так как клиент отправил заголовок Connection: close)