Кратко

  • В ALPN клиент передаёт упорядоченный список непрозрачных идентификаторов, а сервер выбирает одно общее значение. Оно определяет прикладные данные данного TLS-соединения, а не другого участка и не постоянное свойство сервиса.
  • Терминирующий прокси выступает сервером вниз по потоку и новым клиентом вверх. HTTP/2 с браузером и HTTP/1.1 с origin могут быть одновременно верными результатами; им нужны раздельные доказательства.
  • Запись IANA, конфигурация и установленный callback показывают возможность. Факт выполнения требует предложения, выбора или предупреждения, вызова callback, завершённого handshake и запуска приложения, связанных с конкретным соединением.

Где зелёный статус сменил владельца

На внешнем участке доказательства были полными. В ClientHello находились два значения, EncryptedExtensions содержал h2, Finished аутентифицировал транскрипт, затем стороны обменялись preface и SETTINGS HTTP/2.

Но origin не являлся вторым концом этого соединения. Пограничный узел расшифровал запрос и создал новое TCP/TLS-соединение с другими ключами, сертификатом и поколением политики. Там мог быть выбран http/1.1; при отсутствии ALPN мог сработать явный переход к HTTP/1.1.

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

Идентификатор — последовательность байтов

IANA назначает расширению application_layer_protocol_negotiation значение 16. RFC 7301 задаёт каждый ProtocolName как непрозрачную непустую строку длиной от одного до 255 октетов с однобайтовым префиксом. Пустые и усечённые элементы недопустимы.

Поэтому нельзя менять регистр, обрезать или сравнивать приблизительно. HTTP/2 поверх TLS использует ровно h2. RFC 9113 запрещает предлагать или выбирать h2c в TLS ALPN.

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

Если пересечения нет, RFC 7301 требует фатальный no_application_protocol. RFC 9325 усиливает строгую границу против межпротокольной путаницы. Сервер не вправе вернуть значение, которого клиент не предлагал.

Сильное утверждение с малой областью

Выбранный идентификатор окончателен для прикладных данных того же соединения. После ответа h2 сервер не может разбирать поток как HTTP/1.1. Для HTTP/2 preface и SETTINGS дают дополнительное подтверждение запуска.

Нужно сохранять лестницу событий: предложение, ответ, аутентифицированный Finished, корректный preface, полезный обмен. Один ClientHello не доказывает окончание handshake. Успех ALPN без preface не доказывает работоспособность HTTP/2.

Результат не наследуется во времени. RFC 9113 предупреждает: прежняя поддержка — слабый сигнал для будущего соединения, поскольку меняются экземпляры, конфигурация и сеть. Правильная единица утверждения — соединение.

Два журнала на одном прокси

По отношению к браузеру прокси — TLS-сервер, к защищённому origin — TLS-клиент. У каждого участка свои offer, selection, предупреждение и поколение политики.

Официальные настройки Envoy показывают независимость: можно явно использовать downstream-протокол, отдельно согласовать HTTP/1.1 или HTTP/2 с upstream либо перейти к HTTP/1.1 при отсутствии upstream ALPN. Непрерывность — исполненная политика, а не автоматическое наследование.

Туннель отличается от терминации. Посредник может только пересылать байты и не знать внутренний результат TLS. Заголовок из RFC 7639 способен передать намерение использовать протокол внутри CONNECT, но намерение не равно завершённому внутреннему handshake.

Надёжная модель хранит два tuple и связывает их событием «терминация», «преобразование» или «туннель», не смешивая полномочия.

Конфигурация ещё не запустила callback

В OpenSSL нулевая длина клиентского списка удаляет расширение ALPN. Если в ClientHello нет предложения, серверный callback не вызывается. Установка подтверждает способность кода, не выполнение.

Callback servername выполняется раньше и может заменить SSL_CTX; затем ALPN использует выбранный контекст. Глобальный список не обязательно совпадает с политикой виртуального хоста.

SSL_get0_alpn_selected возвращает заимствованную память с длиной, без NUL-терминатора. Обращение как с обычной строкой может усечь или исказить идентификатор.

Ключевой отрицательный тест есть в SSL_select_next_proto: при отсутствии пересечения функция всё равно помещает первый клиентский элемент в output и возвращает OPENSSL_NPN_NO_OVERLAP. В ALPN такой output следует игнорировать. Запись до проверки кода создаёт несуществующее согласование.

Отсутствие offer, плохой вектор, отсутствие пересечения, NOACK, ошибка callback и успешный выбор должны иметь разные статусы. Булево поле уничтожает маршрут отказа.

Возобновление начинается с нового соединения

RFC 7301 относит ALPN к соединению, не к сессии. При возобновлении старые значения не действуют; решают новые сообщения handshake.

Ticket, выпущенный при включённом h2, не обязывает новый экземпляр выбрать его. Копирование старого значения скрывает изменение развёртывания.

В TLS 1.3 параметры PSK для 0-RTT включают ALPN. Сервер принимает ранние данные только при совпадении нового выбора. Если данные отвергнуты и итоговый протокол другой, приложению может потребоваться построить иное сообщение.

Поэтому RFC 9846 запрещает TLS автоматически повторять ранние данные, если не выбран тот же ALPN. Решение принадлежит приложению, которое знает framing и семантику.

Способ разговора, личность и право действия

ALPN определяет способ разговора. Проверка сертификата и service identity определяет собеседника. Прикладная политика отдельно определяет разрешённое действие.

HTTP/3 хорошо показывает границу: h3 обычно выбирается в TLS поверх QUIC, однако RFC 9114 также требует проверить сертификат для origin из URI. Настоящий h3 не делает сервер авторитетным при неверной личности.

Реестр IANA тоже определяет значение байтов, но не развёртывание. Исходный код и конфигурация объясняют возможный результат; они не заменяют наблюдавшиеся offer, selection и запуск протокола.

Отрицательные проверки границы

Предложить h2,http/1.1, а серверу дать предпочтение http/1.1; журнал обязан сохранить выбор. Ответ не предложенным значением должен остановить handshake.

Отправить ClientHello без ALPN и подтвердить отсутствие вызова. Развести no_application_protocol и намеренный NOACK. Вызвать OPENSSL_NPN_NO_OVERLAP, не превратив его output в selection. Заменить SSL_CTX через SNI и указать правильное поколение.

На прокси создать h2 downstream и HTTP/1.1 upstream, сохранив обе connection ID и преобразование. После смены политики возобновить соединение без старого ALPN. При изменении финального ALPN отвергнуть 0-RTT и не допустить автоматической отправки.

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

Источники