Summary

  • RFC 9931 уточняет: полностью отправить запрос Upgrade или CONNECT необходимо, но этого недостаточно для смены состояния соединения HTTP/1.1. Недавний успех помогает прогнозу; только нынешний 101 Switching Protocols или успешный 2xx подтверждает нынешний переход.
  • Если доверенный HTTP-клиент до подтверждения выпускает байты, выбранные недоверенной третьей стороной, при отказе сервер может принять их за следующий аутентифицированный HTTP-запрос. Операторам нужен не архив полезной нагрузки, а квитанция границы: что удерживалось, какой ответ пришёл, какое правило открыло поток и какой анализатор стал действующим.

Быстрый путь авансом расходует определённость

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

RFC 9931 рассматривает противоположный исход именно для HTTP/1.1. Документ опубликован в марте 2026 года в потоке IETF как Standards Track и обновляет RFC 9112 и RFC 9298. Он не объявляет любую оптимизацию ошибкой. Он разводит два близких события, которые легко слить в одном журнале: клиент закончил просить о переходе; сервер согласился перейти.

Upgrade предлагает другой прикладной протокол на существующем соединении. Ответ 101 Switching Protocols сообщает, что сервер понял и принял предложение, и указывает протокол после ответа. CONNECT просит прокси создать туннель. Успешный 2xx переводит соединение в режим туннеля после заголовков ответа. Любой иной ответ означает, что туннель не сформирован.

HTTP и раньше запрещал начинать новый протокол посреди сообщения запроса. RFC 9931 добавляет вторую границу: завершение запроса — условие необходимое, но не достаточное. Сервер может не поддерживать токен, запросить аутентификацию, отклонить порт или адрес, не разрешить имя либо не установить удалённое соединение. До ответа существует ожидание, а не подтверждённое состояние.

Частота успеха отвечает за вероятность

История нужна эксплуатации. Документация совместимости, тесты, версии, доля отказов и недавние результаты позволяют выбрать группу развёртывания, оценить ресурсы и решить, стоит ли выигрыш по времени усложнения защиты. Ответственное управление не требует забыть прошлое.

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

Подмена часто скрыта в сокращениях. «Прокси поддерживает CONNECT» превращается в «этот CONNECT принят». «Токен зарегистрирован» — в «соединение переключилось». «Всегда работало» становится бессрочным разрешением выпускать данные заранее. На каждом шаге исчезает идентификатор соединения, запроса, ответа или момента.

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

Одни байты могут получить чужого автора

RFC 9931 не утверждает, что всякая связь двух участников создаёт эту угрозу. Если оба и без того готовы получать произвольные данные друг друга, ошибочный прогноз может остаться обычным протокольным сбоем. Опасная конструкция возникает, когда сервер доверяет HTTP-клиенту, а пересылаемые им данные выбирает недоверенное третье приложение.

Пусть локальное приложение просит аутентифицированный прокси-клиент открыть TCP-туннель. Оно тут же отдаёт первые байты для удалённой службы, а клиент пересылает их до 2xx. Если цель недоступна, прокси отклоняет CONNECT и ждёт на том же соединении следующий запрос HTTP/1.1.

Злонамеренное приложение может составить данные так, чтобы они одновременно выглядели корректным HTTP-запросом к самому прокси. Сервер увидит их на соединении доверенного клиента, возможно с клиентским сертификатом на уровне соединения. Выбранные третьей стороной байты получат чужую идентичность. RFC 9112 описывает request smuggling как использование разницы разбора для сокрытия запросов, которые иначе запретила бы политика.

Это три разных отказа. Прогноз перехода оказался неверным. Отправитель и получатель выбрали разные грамматики. Действие приписали субъекту, который не выбирал его байты. Счётчик отклонённых переходов видит только первый уровень.

Даже неполный запрос способен попасть в анализатор, разработанный с расчётом на доверенный HTTP-ввод. Источники не доказывают уязвимость конкретного продукта или реальный инцидент. Они фиксируют условие: выпуск до подтверждения меняет круг тех, кто может подавать данные старому анализатору.

WebSocket, UDP и IP используют разные правила

WebSocket требует ожидания. После начального рукопожатия клиент должен дождаться и проверить ответ сервера, прежде чем отправлять дополнительные данные. Отдельно кадры от клиента к серверу маскируются с высокой энтропией. Одно решение регулирует время, другое — форму байтов.

RFC 9298 разрешал оптимистически отправлять UDP-пакеты до ответа прокси. RFC 9931 оставляет это только для HTTP/2 и более новых версий, запрещая в HTTP/1.x. RFC 9484 проводит ту же границу для IP-пакетов. Посредник, преобразующий HTTP/2 или HTTP/3 в HTTP/1.1, обязан удерживать капсулы до разбора успешного ответа.

Причина структурна. Запросы HTTP/1.1 последовательны, а следующая граница неявно определяется окончанием предыдущего запроса. HTTP/2 и HTTP/3 разделяют запросы явными потоками. Поэтому данные отклонённого перехода не занимают автоматически синтаксическое место следующего HTTP/1.1-запроса. Это устраняет конкретную неоднозначность, но не доказывает общую безопасность новой версии, цели или действий внутри туннеля.

Для будущих токенов Upgrade RFC 9931 предлагает несколько подходов: запретить раннюю отправку, начать новый протокол фиксированной преамбулой, однозначно прекращающей разбор HTTP/1.1, или использовать высокоэнтропийное маскирование. Если HTTP-метод после перехода больше не несёт смысла, GET без содержимого также уменьшает материал с двойным прочтением.

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

Отказ CONNECT требует действий обеих сторон

HTTP/1.1 прокси-клиент, работающий для недоверенного TCP-клиента, согласно RFC 9931 обязан выбрать по крайней мере одну из двух мер. Первая — ждать успешный 2xx до пересылки TCP-данных. Вторая — послать Connection: close, чтобы отказ завершил соединение и ранние байты не стали следующим запросом. Можно применить обе.

Отклоняющий CONNECT прокси-сервер также должен закрыть нижележащее соединение и не обрабатывать на нём дальнейшие запросы. Это сдерживает клиентов, отправивших данные слишком рано, но имеет цену. После ответа 407 с запросом аутентификации новое соединение медленнее повторного использования существующего.

Поэтому RFC разрешает отключить это смягчение для клиента, про которого известно, что он ждёт 2xx. Для распознавания названы User-Agent и документация поставщика. RFC 9110 определяет User-Agent как сведения о программном продукте и рекомендует не маскироваться под другие продукты; это не криптографически подтверждённая идентичность.

Исключение по производительности должно иметь срок. В нём указываются продукт и версия, проверенный документ поставщика, локальный тест, цепочка посредников, владелец, дата пересмотра и условие отката. Обновление может изменить порядок отправки. «Известный клиент» — датированный вывод, а не вечное качество.

Квитанция подтверждения без копии трафика

Решающий ответ уже есть в протоколе. Однако журналы часто разрывают попытку перехода, выпуск чужих байтов и конечное состояние анализатора. Daniel Kade предлагает компактную квитанцию подтверждения перехода для путей с данными третьих сторон.

Первый блок называет эпоху соединения и версию HTTP. Он фиксирует Upgrade или CONNECT, токен либо тип туннеля и при необходимости защищённую ссылку на цель. Источник данных классифицируется как собственное управление, ограниченная подсистема или недоверенная третья сторона, но сами байты не копируются.

Второй блок описывает шлюз. Какая версия клиента и политики определяла выпуск? Ожидал ли путь 101 или 2xx, требовал закрытия, применял преамбулу, маску либо явный поток? Были ли байты отправлены до ответа и, если да, какая безопасная конструкция это допускала, а не какая историческая доля успеха внушала уверенность?

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

Квитанция не хранит полезную нагрузку, учётные данные, секреты сертификата или заголовки авторизации. Она также не превращает 2xx в бизнес-разрешение: ответ подтверждает туннель, но не всякое действие внутри него. У приложения и удалённой службы остаются собственные решения.

Это редакционное предложение Daniel Kade, а не поле RFC 9931 и не требование IETF к организации. Его задача мала: показать, какой текущий ответ разрешил какому классу данных пересечь границу анализаторов по какому правилу.

Где останавливаются доказательства

Источники не называют уязвимый продукт, событие, масштаб внедрения или частоту неверной реализации. Они не выбирают одно средство для всех архитектур. Ожидание, закрытие, буфер, преамбула, маскирование и переход на другую версию несут разные издержки.

Задержка и ресурсы — реальные ограничения. Управляемая оптимизация не обязана быть медленной. Она обязана при неверном прогнозе не смешивать анализатор, автора и состояние, а также сохранять путь проверки и исправления.

Надёжный вывод остаётся узким: прошлый успех улучшает прогноз. Нынешний переход подтверждает только нынешний ответ.

Sources

  1. RFC 9931: вопросы безопасности оптимистических переходов протокола в HTTP/1.1
  2. Страница RFC 9931 в RFC Editor
  3. RFC 9110: семантика HTTP
  4. RFC 9112: HTTP/1.1
  5. RFC 9298: проксирование UDP через HTTP
  6. RFC 6455: протокол WebSocket
  7. RFC 9484: проксирование IP через HTTP
  8. RFC 9113: HTTP/2
  9. RFC 9114: HTTP/3
  10. Реестр токенов HTTP Upgrade IANA
  11. Heng Lu, «The Policy Mirror»
  12. Heng Lu, «Minimum Initial Specification, Localized Future Decision, Voluntary Adoption»
  13. Heng Lu, «On Why BTW Media Exists, and Why Reality, Not Advocacy, Is the Product»