Кратко

  • EOF сообщает о прекращении транспортного потока, но не доказывает, что получено всё задуманное отправителем. close_notify — защищённое заявление о том, что в данном направлении сообщений TLS больше не будет.
  • TLS 1.3 перестал требовать немедленно закрывать встречное направление и выбрасывать ожидающие записи. Полноту HTTP-сообщения по-прежнему подтверждают длина, конец chunked-кодирования или END_STREAM.

Подлинная часть не обязательно является целым

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

Прикладное обрамление иногда выдаёт потерю. Объявленная Content-Length требует точного числа октетов. Chunked-кодирование требует последнего блока нулевого размера. Если же ответ ограничивается только закрытием соединения, корректный финал и исчезнувшее окончание выглядят для получателя одинаково.

TLS 1.0 описал это как угрозу усечения. Протокол ввёл предупреждение close_notify: отправитель внутри защищённой последовательности заявляет, что больше не пошлёт сообщений в соединении. Записи, пришедшие после предупреждения, следует игнорировать.

Это не делает TLS форматом документов. Протокол способен засвидетельствовать лишь конец собственных сообщений от одного отправителя. Закончены ли HTTP-ответ, файл, команда или операция, должна определить система, которая понимает их структуру.

TLS 1.0 связывал плохое закрытие с будущей сессией

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

Реальные реализации не удержали эту связь. TLS 1.2 отмечает, что уже TLS 1.1 отменил автоматический запрет на возобновление, следуя распространённой практике. Обязанность отправлять close_notify сохранилась, но его отсутствие само по себе больше не делало сессию непригодной.

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

Симметричное закрытие могло обрезать обратный путь

До TLS 1.3 получатель close_notify должен был сразу послать собственное предупреждение, закрыть соединение и отбросить ожидающие записи. Правило предполагало, что оба направления заканчиваются одновременно.

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

TLS 1.3 исправил модель. close_notify упорядоченно закрывает одно направление: передающая сторона прекращает запись, но продолжает чтение. Получатель не обязан немедленно отвечать или отбрасывать встречные данные. Каждое направление заканчивается тогда, когда использующее его приложение действительно завершило работу.

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

HTTP знает границы, которых не видит TLS

Документ HTTP over TLS разделил защищённость принятой части и полноту сообщения. Раннее закрытие не делает принятые данные небезопасными, однако позволяет предположить потерю продолжения. TLS не различает границы HTTP-запросов и ответов, поэтому клиент должен исследовать прикладное обрамление.

Современная спецификация HTTP/1.1 сохраняет это разделение. Content-Length считается выполненной при получении ровно объявленного числа октетов; chunked-сообщение заканчивается нулевым блоком. Без нужной границы сообщение неполно. Ответ, ограниченный закрытием соединения, поверх TLS можно признать полным только при действительном предупреждении о закрытии.

В HTTP/2 уровни различаются ещё нагляднее. END_STREAM из RFC 9113 закрывает одно направление одного HTTP-потока, тогда как другие потоки продолжаются в том же соединении. Конец потока и конец общего канала TLS подтверждаются разными событиями.

Одно предупреждение — одно утверждение

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

EOF — событие транспорта. Предупреждение — защищённое свидетельство намерения отправителя. Длина, конечный chunk или END_STREAM — свидетельства прикладной структуры. Надёжная система не сворачивает их в один флаг «успех», а соединяет лишь там, где совпадают границы их полномочий.

Источники и ограничения

Материал основан на RFC 2246, RFC 2818, RFC 5246, RFC 8446, RFC 9112 и RFC 9113. Они подтверждают правила и историю изменений, но не описывают нынешние настройки библиотек, доли внедрения или причину отсутствия предупреждения в конкретном инциденте.