HTTP и HTTPS: одно содержимое, разная упаковка
HTTPS передаёт те же запросы и ответы, что и HTTP, но внутри защищённого канала TLS. Это не отдельный протокол, а тот же обмен данными, обёрнутый в шифрование: методы, заголовки и коды ответа остаются прежними, но содержимое скрыто от посторонних. TLS добавляет три свойства: тайну содержимого (его не прочитать на пути), целостность (изменение обнаруживается, и соединение рвётся) и подлинность сервера (её подтверждает сертификат). Подлинность клиента по умолчанию не проверяется — сервер не знает, кто именно к нему подключился.
Защита действует не на уровне страниц, а на уровне соединения. Браузер открывает канал до домена, а не до конкретной страницы: если сертификат действителен, всё, что передаётся по этому соединению, защищено одинаково — и страница входа, и картинка. Запрос к тому же домену, действительно отправленный по HTTP, в этот канал не попадает и идёт открыто. Защищённый канал не значит, что сайт безопасен, — только то, что на участке от браузера до узла, принявшего соединение, посторонний не прочитает передаваемое и не изменит его незаметно.
Что видит посторонний
Без TLS любой узел на пути — провайдер, владелец точки доступа, промежуточный сервер — может не только читать передаваемое, но и менять его. Вставленный скрипт, подмена ссылки или файла, перенаправление на фишинговый сайт — всё это возможно, если соединение не защищено. HTTPS не скрывает сам факт обмена, но прячет его содержимое.
При HTTPS посторонний видит:
- сетевые адреса (IP и порт) клиента и сервера;
- объём передаваемых данных и время обмена;
- как правило, имя домена (его раскрывают DNS-запрос или поле SNI в рукопожатии TLS).
Не видит он:
- путь и строку запроса;
- заголовки и cookie;
- тело запроса и ответа;
- код ответа.
Длина ответов не скрывается, и по ней иногда можно угадать, какая страница открыта. Имя сайта выдают не только DNS-запрос и поле имени сервера в рукопожатии: в более старых версиях протокола открытым передаётся и сертификат сервера со списком имён, а IP-адрес во многих случаях сам указывает на сайт. Поэтому рассчитывать, что имя сайта останется тайной, не стоит: HTTPS скрывает содержимое обмена, а не факт обращения к домену.
Сертификат: что он подтверждает
Сертификат связывает открытый ключ с доменным именем. Браузер проверяет как минимум три вещи:
- Цепочку подписей до доверенного корневого сертификата.
- Срок действия сертификата: с истёкшим браузер покажет предупреждение, а почему сертификаты истекают снова и снова, разобрано в материале Сертификат истёк: почему это повторяется.
- Совпадение имени в адресе со списком альтернативных имён в сертификате.
Кроме того, проверяется назначение сертификата: он должен быть предназначен для аутентификации сервера, а не для других целей. Для сертификатов публичных центров сертификации браузер может требовать отметку о записи в журналы выпуска, и если сертификат не соответствует этому требованию, соединение будет отклонено даже при совпадении имени и срока действия.
Сертификат с проверкой домена подтверждает только одно: тот, кто его получил, управлял этим доменом на момент выпуска. О честности владельца, надёжности сайта или личности человека за ним он не говорит ничего. Такой сертификат получает и мошеннический сайт — браузер примет его, если проверки пройдены успешно.
Значок в адресной строке зависит от браузера: часть браузеров убрала замок, часть сохранила, часть помечает только незащищённое соединение. И значок, и отсутствие предупреждения означают только одно: канал до этого домена защищён. О том, можно ли доверять сайту, они не говорят.
Откуда берётся доверие
Браузер доверяет сертификату, если его подписал центр, чей корневой сертификат есть в хранилище доверенных корней. Это хранилище поставляется либо с операционной системой, либо с самим браузером: часть браузеров несёт собственный список и проверяет сертификаты самостоятельно. Поэтому один и тот же сайт на одном устройстве может открываться в одном браузере и давать предупреждение в другом.
Тот, чей корневой сертификат добавлен в хранилище — администратор рабочего компьютера или сайт, попросивший установить свой корень, — может выпускать сертификаты для любых имён и читать трафик через свой прокси. Самоподписанный сертификат шифрует канал, но не подтверждает подлинность сервера: браузер не может отличить его от сертификата того, кто встал посередине, поэтому показывает предупреждение.
Где защита кончается
Защита действует на участке от клиента до точки завершения TLS. Это может быть сам сервер, обратный прокси или сеть доставки — дальше трафик может идти открытым. Содержимое при HTTPS видят:
- сама точка завершения TLS;
- сервер сайта;
- узлы на пути, если трафик между точкой завершения и сервером не защищён;
- расширения браузера;
- вредоносная программа на устройстве;
- владелец добавленного в хранилище корня, если трафик идёт через его прокси.
Провайдер и владелец точки доступа, как правило, видят домен, но не страницы. О том, как данные хранятся на сервере и нет ли уязвимостей в приложении, HTTPS не говорит ничего.
Первый запрос к сайту браузер может отправить по HTTPS, даже если ссылка начинается с http://. Если защищённое соединение не удалось, браузер может молча откатиться на HTTP, а может сначала показать предупреждение и спросить разрешения — это зависит от браузера и его настроек, проверьте в своём. Там, где откат происходит молча, тот, кто стоит на пути, может не пропустить защищённую попытку и добиться открытого соединения.
Со стороны сайта запретить откат может только строгий транспорт — заголовок Strict-Transport-Security: получив его по HTTPS без ошибок сертификата, браузер в течение срока, заданного в самом заголовке, сам заменяет http:// на https:// для этого узла ещё до отправки запроса. Самый первый визит остаётся без этой защиты, если домена нет в списке, встроенном в браузер. Как включить строгий транспорт — в материале HTTPS с нуля: сертификат, перенаправление, проверка, параметры заголовка — в материале Заголовки безопасности: какие ставить и что они ломают. Пока браузер о строгом транспорте сайта не знает, открытый запрос остаётся возможным.
Смешанное содержимое на странице, загруженной по HTTPS, делится на два класса:
- скрипты, стили, фреймы и запросы из кода по HTTP браузер блокирует;
- картинки, аудио и видео сам переписывает на
https://, а если по защищённому соединению они недоступны — не загружает.
Страницы одного домена по http:// и по https:// — разные источники. Сеансовую cookie — ту, по которой сайт узнаёт вошедшего пользователя, — на таком сайте браузер может отправить открыто. Для этого должны сойтись два условия: у cookie нет атрибута Secure, и запрос действительно идёт по HTTP, то есть пользователь перешёл на страницу, оставленную без шифрования. Браузер может и не отправить по HTTP cookie, поставленную по HTTPS: часть браузеров привязывает её к схеме. Проверьте в своём, но рассчитывать на это нельзя: от отправки по HTTP наверняка защищает только Secure. Атрибут Secure означает, что браузер отправит cookie только по защищённому соединению. Где держать то, по чему сайт узнаёт пользователя, и как закрыть cookie от чужого скрипта, разобрано в материале Токен в браузере: где его хранить.
Тупик: значок в адресной строке
Первым делом о безопасности сайта судят по значку в адресной строке и по отсутствию предупреждения. Это не помогает, потому что значок говорит только о канале до домена, а сертификат с проверкой домена получает и мошеннический сайт. Та же ошибка со стороны владельца сайта — включить HTTPS только на входе и оплате: открытую страницу на пути можно изменить так, что ссылка на форму входа поведёт куда угодно.
Позиция редакции
Всё содержимое сайта отдаётся только по HTTPS, включая страницы без форм и статические файлы, а HTTP отвечает одним перенаправлением. Значок в адресной строке и отсутствие предупреждения читают как «канал до этого домена защищён», но не как «сайту можно доверять». Неверна эта позиция, если адрес доступен только с той же машины через петлевой интерфейс: перехватывать на этом пути некому, а браузер считает такой адрес защищённым контекстом и без сертификата.
Проверить своё соединение можно одной командой: curl -v https://узел, где вместо узел стоит имя сайта, покажет ход рукопожатия, сведения о сертификате и результат проверки цепочки и имени; точный вид вывода зависит от сборки. Набор доверенных корней у этой команды свой или системный и с браузерным может не совпадать, поэтому успешная проверка в командной строке не означает, что сертификат примет браузер, и наоборот.