Кратко

  • Маскирование WebSocket не обеспечивает секретность: четыре байта ключа передаются в кадре, однако непредсказуемость не даёт приложению заранее назначить точный вид кадра на линии.
  • Правило возникло из реального сбоя посредников: клиентские кадры получают новый ключ, серверные не маскируются, а приложение не вправе менять кадр после начала передачи.

Первые кадры доверяли собственным границам

Проект IETF от мая 2010 года предлагал двусторонний канал браузера после начального обмена HTTP. Ранний формат был нарочито мал: текстовый кадр открывался 0x00 и закрывался 0xff, а другая форма несла длину. Двум корректным оконечным узлам WebSocket этого хватало для разделения сообщений.

Но границы не управляли каждым устройством, уже стоявшим на пути. Перехватывающий прокси мог пропустить Upgrade, а затем продолжить искать новый HTTP-запрос в следующих байтах. Конечные точки уже сменили грамматику, посреднический анализатор — ещё нет.

Прокси не обязан был быть злоумышленником. Браузер и сервер могли точно соблюдать соглашение. Достаточно, чтобы третий участник дал последующим байтам неверное протокольное имя и тем самым совершил операцию с кэшем, которой не разрешала ни одна сторона.

Постоянное преобразование не отняло выбор у отправителя

К январю 2011 года проект -04 уже требовал маскировать каждый кадр клиента к серверу. Однако ключ выводился из величин рукопожатия и оставался одним на всё соединение.

Стабильное преобразование меняет внешний вид данных, но не лишает знающего отправителя контроля над результатом. Приложение способно подобрать вход, дающий желаемый выход. Перемешивание мешает лишь тому, кто ещё не узнал правило.

Требовалось более точное свойство: для каждого кадра приложение вправе выбрать логическое сообщение или знать следующее преобразование, но не обладать обоими до фиксации байтов на линии. На каждой границе кадра нужно было новое обязательство.

Прокси присвоил ответу чужое имя

Работа 2011 года Talking to Yourself for Fun and Profit исследовала браузерные сокеты при наличии прозрачных — точнее, перехватывающих — прокси. Некоторые устройства передавали согласие или Upgrade, не понимая смену состояния, а затем читали управляемые атакующим данные как HTTP-запрос.

Цепочка пересекала полномочия нескольких сторон. Вредоносный сайт заставлял браузер соединиться с сервером атакующего. Запутавшийся посредник толковал последующие байты как запрос другого ресурса. Сервер атакующего отдавал данные, похожие на ответ. Кэш сохранял их под ложным именем, после чего другие пользователи могли получить содержимое не от обозначенного источника.

В рекламном эксперименте марта 2011 года исследователи обнаружили условия отравления кэша на малой, но ненулевой доле измеренных путей Java и Flash. Из 47 338 основанных на Upgrade пробных рукопожатий WebSocket, дошедших до проверки, успешными оказались восемь. Эти числа относятся только к тому опыту и времени, а не к современному парку прокси.

Устойчивый вывод работы не сводился к доле. Добавление префикса, не похожего на HTTP, не могло доказать, что неизвестный дефектный анализатор не пропустит его и не начнёт чтение с полезной нагрузки. Надёжнее было отнять у враждебного приложения возможность намеренно построить опасное представление данных на линии.

Ключ перешёл в каждый кадр

Решающий шаг появился в проекте -05 от февраля 2011 года. Каждый клиентский кадр получил собственный 32-битный ключ из сильного источника энтропии; следующий ключ нельзя было предсказать по предыдущим. RFC 4086 объясняет осторожность: выход может казаться статистически беспорядочным и всё же быть предсказуемым, если основан на часах, счётчике или малом пространстве начальных значений.

Окончательная RFC 6455 сохранила покадровую схему. Бит MASK сообщает о четырёх октетах ключа. Октет полезной нагрузки i объединяется XOR с октетом ключа i mod 4. Длина нагрузки не меняется и не включает ключ.

Получатель может обратить XOR. Наблюдатель тоже. Так и задумано. Приложение фиксирует содержимое прежде, чем узнаёт непредсказуемый ключ, а сервер получает ключ, чтобы восстановить сообщение. Защитное свойство создаёт порядок решений, а не тайна.

С началом передачи кадр становился неизменным

Нового ключа недостаточно, если приложение способно вывести его из известного начала длинного кадра, а затем переписать ещё не отправленный хвост. Начало раскрывает повторяющееся четырёхбайтовое преобразование; изменяемый остаток можно подобрать так, чтобы после маскирования он выглядел HTTP-запросом.

Поэтому RFC 6455 устанавливает временную границу. Когда передача клиентского кадра началась, приложение больше не может изменять его полезную нагрузку. Новые или изменённые данные идут в другом кадре с другим свежим ключом.

Это не просто указание «использовать случайность». До отправки приложение владеет смыслом, после начала клиентская реализация хранит уже зафиксированную последовательность. Без такой передачи контроля наблюдение начала снова превращается во власть над концом.

Направление выражало модель угроз

Все кадры от клиента к серверу должны быть маскированы, а серверу запрещено маскировать кадры к клиенту. Сервер закрывает соединение при немаскированном клиентском кадре, клиент — при маскированном серверном; нарушение можно обозначить кодом протокольной ошибки 1002.

Асимметрия повторяет цепь атаки. Для ложной идентичности в кэше нужны байты, похожие на запрос, по направлению браузер—сервер. Враждебный сервер уже способен выбирать ответоподобные данные, но без поддельного запроса у сбитого с толку кэша нет ложного имени ресурса, завершающего отравление.

Это не делает серверный трафик доверенным. Аутентификация, авторизация, политика Origin, проверка содержимого и защита канала сохраняют отдельные задачи. Маска в обратном направлении просто не была средством от этого конкретного инфраструктурного сбоя.

TLS не сделал маску лишней

Клиентское маскирование применяется и в ws, и в wss внутри TLS. Под шифрованием оно кажется избыточным: устройство на пути не видит правильно защищённый поток TLS. Но обещания различны. TLS обеспечивает конфиденциальность и целостность между своими оконечными точками; маска ограничивает, какие байты кадров недоверенный браузерный код может заставить совместимый клиент WebSocket вывести.

Единое правило также не позволяет допустимости кадра зависеть от места завершения TLS. Шлюз может снять TLS до следующего внутреннего участка, а схема развёртывания — измениться. Защита одного слоя не должна незаметно освобождать другой от его грамматики.

Новые транспорты HTTP сохранили прежнюю обязанность

RFC 8441 позднее стала запускать WebSocket через Extended CONNECT в потоке HTTP/2. Поскольку переход обозначал :protocol, обработка HTTP/1.1-полей Sec-WebSocket-Key и Sec-WebSocket-Accept там отпала. Маскирование кадров не исчезло: требования безопасности RFC 6455 продолжают действовать, кроме относящегося к рукопожатию обсуждения SHA-1 в разделе 10.8.

RFC 9220 перенесла Extended CONNECT в HTTP/3 и не добавила нового исключения. Внешний запуск прошёл путь от переключения всего соединения HTTP/1.1 к выбранному потоку HTTP/2 и затем к потоку QUIC; кадр WebSocket сохранил то же свидетельство направления.

Эта преемственность показательна. Маска не была заплатой для одного написания заголовка Upgrade. Она закрепляла отношения между выбором приложения, обязательством клиента и ошибкой посредника, пережившие смену окружающего транспорта.

Что доказывает открытый ключ — и чего не доказывает

Свежий ключ не доказывает личность, принятие Origin, разрешение действия или целостность вне защищённого транспорта. Видимый в записи ключ — норма. Повтор или предсказуемость свидетельствуют о нарушенной предпосылке.

Совместимое маскирование не чинит каждый посредник. RFC 6455 отмечает, что несовместимые клиенты и серверы по-прежнему могут открыть уязвимые прокси той же категории атак. Протокол сузил набор действий, к которым можно склонить совместимый браузерный путь, но не получил власть над всеми кэшами Интернета.

Исторический урок скромен и долговечен. Если старая инфраструктура может читать байты общей линии по неверной грамматике, новому протоколу недостаточно объявить собственный переход правильным. Иногда он должен ещё и ограничить опасные последовательности, которые недоверенный участник способен намеренно поместить на общий путь.

Источники и границы свидетельств

Проекты и RFC подтверждают развитие решения и нормативное поведение. Работа описывает ограниченный эксперимент 2011 года, а не нынешнюю уязвимость или рыночную долю. Ни один источник не устанавливает поведение конкретного современного браузера, прокси, CDN или шлюза. Маска не является шифрованием, защитой целостности, аутентификацией точки или доказательством того, что кэшированный ответ принадлежит кажущемуся источнику.