Защита #
Какую безопасность имеет WebRTC? #
Каждое WebRTC-соединение аутентифицировано и зашифровано. Вы можете быть уверены, что третья сторона не может видеть, что вы отправляете, или вставлять поддельные сообщения. Вы также можете быть уверены, что WebRTC-агент, который сгенерировал Session Description, - тот, с кем вы общаетесь.
Очень важно, чтобы никто не изменял эти сообщения. Нормально, если третья сторона читает Session Description в транзите. Однако WebRTC не защищает от его изменения. Злоумышленник может выполнить атаку “человек посередине”, изменив ICE-кандидаты и обновив отпечаток сертификата.
Как это работает? #
WebRTC использует два существующих протокола: Datagram Transport Layer Security (DTLS) и Secure Real-time Transport Protocol (SRTP).
DTLS позволяет согласовать сеанс и затем безопасно обмениваться данными между двумя пирами. Это родственник TLS, той же технологии, которая работает в HTTPS, но DTLS использует UDP вместо TCP в качестве транспортного уровня. Это означает, что протокол должен справляться с ненадежной доставкой. SRTP специально разработан для безопасного обмена медиа. Есть некоторые оптимизации, которые мы можем сделать, используя его вместо DTLS.
Сначала используется DTLS. Он выполняет рукопожатие поверх соединения, предоставленного ICE. DTLS - это клиент/серверный протокол, поэтому одна сторона должна начать рукопожатие. Роли клиента/сервера выбираются во время сигнализации. Во время DTLS-рукопожатия обе стороны предлагают сертификат. После завершения рукопожатия этот сертификат сравнивается с хешем сертификата в Session Description. Это делается для обеспечения того, что рукопожатие произошло с ожидаемым WebRTC-агентом. DTLS-соединение затем становится доступным для использования в коммуникации DataChannel.
Чтобы создать SRTP-сессию, мы инициализируем ее, используя ключи, сгенерированные DTLS. У SRTP нет механизма рукопожатия, поэтому он должен быть загружен с внешними ключами. После этого медиа могут обмениваться, будучи зашифрованными с помощью SRTP!
Безопасность 101 #
Чтобы понять технологию, представленную в этой главе, вам сначала нужно понять эти термины. Криптография - сложный предмет, поэтому было бы полезно проконсультироваться и с другими источниками!
Открытый текст и шифротекст #
Открытый текст - это вход для шифра. Шифротекст - это выход шифра.
Шифр #
Шифр - это серия шагов, которая преобразует открытый текст в шифротекст. Шифр затем может быть обращен, так что вы можете преобразовать свой шифротекст обратно в открытый текст. У шифра обычно есть ключ для изменения его поведения. Другой термин для этого - шифрование и дешифрование.
Простой шифр - ROT13. Каждая буква перемещается на 13 символов вперед. Чтобы отменить шифр, вы перемещаете 13 символов назад. Открытый текст HELLO
станет шифротекстом URYYB
. В этом случае шифр - ROT, а ключ - 13.
Хеш-функции #
Криптографическая хеш-функция - это необратимый процесс, который генерирует дайджест. При заданном входе она генерирует один и тот же выход каждый раз. Важно, чтобы выход не был обратимым. Имея выход, вы не должны иметь возможность определить его вход. Хеширование полезно, когда вы хотите убедиться, что сообщение не было изменено.
Простая (хотя и явно не подходящая для реальной криптографии) хеш-функция будет заключаться в том, чтобы брать только каждую вторую букву. HELLO
станет HLO
. Вы не можете предположить, что HELLO
был входом, но можете подтвердить, что HELLO
будет соответствовать хеш-дайджесту.
Криптография с открытым/закрытым ключом #
Криптография с открытым/закрытым ключом описывает тип шифров, которые использует DTLS и SRTP. В этой системе у вас есть два ключа: открытый и закрытый. Открытый ключ предназначен для шифрования сообщений и безопасен для обмена. Закрытый ключ предназначен для дешифрования и никогда не должен быть раскрыт. Это единственный ключ, который может дешифровать сообщения, зашифрованные открытым ключом.
Обмен Диффи-Хеллмана #
Обмен Диффи-Хеллмана позволяет двум пользователям, которые никогда не встречались, безопасно создать общий секрет через интернет. Пользователь A
может отправить секрет пользователю B
без беспокойства о перехвате. Это зависит от сложности решения проблемы дискретного логарифма.
Вам не нужно полностью понимать, как это работает, но полезно знать, что именно это делает DTLS-рукопожатие возможным.
Wikipedia имеет пример этого в действии здесь.
Псевдослучайная функция #
Псевдослучайная функция (PRF) - это предопределенная функция для генерации значения, которое выглядит случайным. Она может принимать несколько входов и генерировать один выход.
Функция генерации ключа #
Генерация ключа - это тип псевдослучайной функции. Генерация ключа - это функция, используемая для усиления ключа. Один распространенный шаблон - растяжение ключа.
Допустим, вам дан ключ размером 8 байт. Вы могли бы использовать KDF, чтобы сделать его сильнее.
Nonce #
Nonce - это дополнительный вход в шифр. Это используется для того, чтобы получить разный выход от шифра, даже если вы шифруете одно и то же сообщение несколько раз.
Если вы зашифруете одно и то же сообщение 10 раз, шифр даст вам один и тот же шифротекст 10 раз. Используя nonce, вы можете получить разный выход, все еще используя тот же ключ. Важно использовать разный nonce для каждого сообщения! В противном случае это сводит на нет большую часть ценности.
Код аутентификации сообщения #
Код аутентификации сообщения - это хеш, который помещается в конец сообщения. MAC доказывает, что сообщение исходит от ожидаемого пользователя.
Если вы не используете MAC, злоумышленник может вставлять недопустимые сообщения. После дешифрования у вас будет просто мусор, потому что они не знают ключ.
Ротация ключа #
Ротация ключа - это практика смены ключа через интервал. Это делает украденный ключ менее значимым. Если ключ украден или утек, можно расшифровать меньше данных.
DTLS #
DTLS (Datagram Transport Layer Security) позволяет двум пирам устанавливать безопасную связь без предварительной конфигурации. Даже если кто-то подслушивает разговор, он не сможет расшифровать сообщения.
Для связи DTLS-клиента и сервера им нужно согласовать шифр и ключ. Они определяют эти значения, выполняя DTLS-рукопожатие. Во время рукопожатия сообщения находятся в открытом тексте.
Когда DTLS-клиент/сервер обменялся достаточным количеством деталей для начала шифрования, он отправляет Change Cipher Spec
. После этого сообщения каждое последующее сообщение будет зашифровано!
Формат пакета #
Каждый DTLS-пакет начинается с заголовка.
Тип содержимого #
Вы можете ожидать следующие типы:
20
- Change Cipher Spec22
- Рукопожатие23
- Прикладные данные
Рукопожатие
используется для обмена деталями для запуска сеанса. Change Cipher Spec
используется для уведомления другой стороны, что все будет зашифровано. Прикладные данные
- это зашифрованные сообщения.
Версия #
Версия может быть 0x0000feff
(DTLS v1.0) или 0x0000fefd
(DTLS v1.2), версии v1.1 не существует.
Эпоха #
Эпоха начинается с 0
, но становится 1
после Change Cipher Spec
. Любое сообщение с ненулевой эпохой зашифровано.
Порядковый номер #
Порядковый номер используется для сохранения сообщений в порядке. Каждое сообщение увеличивает порядковый номер. Когда эпоха увеличивается, порядковый номер начинается заново.
Длина и полезная нагрузка #
Полезная нагрузка зависит от Типа содержимого
. Для Прикладных данных
Полезная нагрузка
- это зашифрованные данные. Для Рукопожатия
она будет разной в зависимости от сообщения. Длина указывает, насколько большой Полезная нагрузка
.
Конечный автомат рукопожатия #
Во время рукопожатия клиент/сервер обмениваются серией сообщений. Эти сообщения сгруппированы в полеты. Каждый полет может содержать несколько сообщений (или только одно). Полет не считается завершенным, пока не будут получены все сообщения в полете. Мы подробнее опишем цель каждого сообщения ниже.
ClientHello #
ClientHello - это начальное сообщение, отправляемое клиентом. Оно содержит список атрибутов. Эти атрибуты сообщают серверу о шифрах и функциях, которые поддерживает клиент. Для WebRTC это также способ выбрать SRTP-шифр. Он также содержит случайные данные, которые будут использованы для генерации ключей для сеанса.
HelloVerifyRequest #
HelloVerifyRequest отправляется сервером клиенту. Это делается для того, чтобы убедиться, что клиент намеревался отправить запрос. Затем клиент повторно отправляет ClientHello, но с токеном, предоставленным в HelloVerifyRequest.
ServerHello #
ServerHello - это ответ сервера для конфигурации этого сеанса. Он содержит, какой шифр будет использоваться, когда этот сеанс закончится. Он также содержит случайные данные сервера.
Сертификат #
Сертификат содержит сертификат для клиента или сервера. Это используется для уникальной идентификации, с кем мы общались. После завершения рукопожатия мы убедимся, что этот сертификат при хешировании соответствует отпечатку в SessionDescription
.
ServerKeyExchange/ClientKeyExchange #
Эти сообщения используются для передачи открытого ключа. При запуске клиент и сервер генерируют пару ключей. После рукопожатия эти значения будут использованы для генерации Pre-Master Secret
.
CertificateRequest #
CertificateRequest отправляется сервером, уведомляя клиента, что он хочет сертификат. Сервер может либо запросить, либо потребовать сертификат.
ServerHelloDone #
ServerHelloDone уведомляет клиента, что сервер закончил рукопожатие.
CertificateVerify #
CertificateVerify - это способ, которым отправитель доказывает, что у него есть закрытый ключ, отправленный в сообщении Certificate.
ChangeCipherSpec #
ChangeCipherSpec информирует получателя, что все, отправленное после этого сообщения, будет зашифровано.
Finished #
Finished зашифрован и содержит хеш всех сообщений. Это утверждение, что рукопожатие не было изменено.
Генерация ключа #
После завершения рукопожатия вы можете начать отправлять зашифрованные данные. Шифр был выбран сервером и находится в ServerHello. Как был выбран ключ?
Сначала мы генерируем Pre-Master Secret
. Чтобы получить это значение, используется Диффи-Хеллман на ключах, обмененных ServerKeyExchange
и ClientKeyExchange
. Детали различаются в зависимости от выбранного шифра.
Затем генерируется Master Secret
. Каждая версия DTLS имеет определенную Псевдослучайную функцию
. Для DTLS 1.2 функция принимает Pre-Master Secret
и случайные значения в ClientHello
и ServerHello
.
Выход от запуска Псевдослучайной функции
- это Master Secret
. Master Secret
- это значение, используемое для шифра.
Обмен ApplicationData #
Основной движитель DTLS - ApplicationData
. Теперь, когда у нас инициализирован шифр, мы можем начать шифровать и отправлять значения.
Сообщения ApplicationData
используют заголовок DTLS, как описано ранее. Полезная нагрузка
заполняется шифротекстом. Теперь у вас есть работающий DTLS-сеанс, и вы можете общаться безопасно.
DTLS имеет много других интересных функций, таких как повторные переговоры. Они не используются WebRTC, поэтому здесь не будут рассмотрены.
SRTP #
SRTP - это протокол, специально разработанный для шифрования RTP-пакетов. Чтобы начать SRTP-сессию, вы указываете свои ключи и шифр. В отличие от DTLS, у него нет механизма рукопожатия. Вся конфигурация и ключи были сгенерированы во время DTLS-рукопожатия.
DTLS предоставляет выделенный API для экспорта ключей, которые будут использоваться другим процессом. Это определено в RFC 5705.
Создание сессии #
SRTP определяет функцию генерации ключа, которая используется на входах. При создании SRTP-сессии входы проходят через нее для генерации ключей для нашего SRTP-шифра. После этого вы можете перейти к обработке медиа.
Обмен медиа #
Каждый RTP-пакет имеет 16-битный порядковый номер. Эти порядковые номера используются для сохранения пакетов в порядке, как первичный ключ. Во время вызова они будут переполняться. SRTP отслеживает это и называет это счетчиком переполнения.
При шифровании пакета SRTP использует счетчик переполнения и порядковый номер в качестве nonce. Это для обеспечения того, что даже если вы отправите одни и те же данные дважды, шифротекст будет разным. Это важно для предотвращения возможности атакующего идентифицировать шаблоны или попытаться выполнить атаку повторного воспроизведения.