SSL — это поток
ноября 28 2009 by admin in БезопасностьВ отличие от других рассмотренных протоколов, в которых предполагается, что данные, которыми обменивается стороны, сформированы в виде блобов (с помощью функций InitializeSecurityContext и AcceptSecurityContext), в SSL вообще не передаются блобы! Получая блоб от InitializeSecurityContext, вы передаете данные в «чистом виде», не посылая предварительно размер этих данных.
Хотя SSL предполагает передачу и получение данных «в чистом виде», ничто не мешает вам реализовать некий «мета-протокол» с указанием размера передаваемых блобов. Это может радикально упростить ваш SSL-код, но формально вы отойдете от спецификации HTTPS. Если вы будете передавать по сети, кроме данных, их размер, ваш клиент или сервер скорей всего не смогут взаимодействовать с клиентами и серверами, реализующими протокол HTTPS, очень распространенный в Web-браузерах и Web-серверах.
Вы можете удивиться: откуда принимающая сторона знает, сколько данных нужно прочитать? А она и не знает. Дело в том, что в SSL обмен данными производится в виде потоков. Приведенный сценарий показывает, как SSL реагирует на поток информации. Здесь говорится о том, как считывается информация, пока не закончится сообщение.
1. Одна сторона (например, клиент) посылает неизмененный блоб по сети.
2. Принимающая сторона читает столько информации, сколько может и передает ее функции «обработки блоба». (В нашем случае сервер передает данные функции AcceptSecurityContext.)
3. Если принимающая сторона не прочитала из сети достаточно информации, чтобы закончить этот проход транзакции, функция обработки блоба выдает код завершения SEC_E_INCOMPLETE_MESSAGE.
4. Если возвращается такой код, указывающий, что сообщение не получено полностью, вам нужно сохранить уже полученные данные и продолжать получать дополнительные данные, пока функция не вернет значение, отличное от SEC_E_INCOMPLETE_MESSAGE.
Нужно понимать, что потоковая природа SSL порождает еще одну проблему, кроме получения не всех данных. Ваша программа может получать слишком много данных из сети. При этом AcceptSecurityContext или InitializeSecurity-Context укажет на наличие излишних данных, которые нужно сохранить для дальнейшего использования (видимо, после чтения дополнительных данных.)
Так что, как видите, в SSL больше сценариев. Две следующие ситуации вы всегда должны четко представлять.
1. Вам может не хватать полученных данных, чтобы выполнилась функция SSPI, и потребуется получать дополнительные данные.
2. У вас может быть избыток информации для SSPI-функции, и вам придется сохранить ее для следующих обращений к функциям SSPI.
А. Вам требуется получить дополнительную информацию из сети. Б. Вам не требуется получать дополнительную информацию из сети.
Во втором сценарии два «подсценария». Сценарий 2А достаточно очевиден, а вот 2Б — неожиданность. Случается, что AcceptSecurityContext или Initialize-SecurityContext указывают, что вы передали им лишние данные, и требуется «продолжение». Более того, в этих случаях функции обработки блобов могут не предоставить данных для возврата по сети. Так что вам придется изменить буфер и снова передать его этим функциям.
По-моему, сценарий с избыточными данными никогда не обнаружит себя в приложениях с SSPI, потому что AcceptSecurityContext и InitializeSecurityContext обладают всей нужной информацией для обработки данных. Эти функции прервут свое выполнение, только если им не хватит данных, чтобы обработать законченное сообщение.
Проблему с лишними данными не так просто решить, как может показаться. Представьте, что вы получаете из сети блоб, разбитый на три «раздела», последний из которых не завершен, и вам требуются дополнительные данные из сети. Вы передаете этот блоб, например в AcceptSecurityContext, и она обрабатывает первые два внутренних раздела. Закончив, она обнаруживает, что последний раздел неполный и ей нужны дополнительные данные. Однако нежелательно передавать весь блоб этой функции, получив дополнительные данные, так как она уже обработала первые два внутренних раздела.
Чтобы избежать такой ситуации, разработчики системы решили, что, если любой внутренний раздел или подраздел блоба обработан, функции AcceptSecurityContext и InitializeSecurityContext должны вернуть управление независимо от того, достаточно ли у них данных для дальнейшей обработки. Таким образом, вы поймете, что нужны дополнительные данные, скорректируете буфер и снова вызовите нужную функцию.