Что такое HSTS и как безопасно его включить
Практика3 минРедакция Innovialabs
Коротко
HSTS — заголовок ответа, который велит браузеру ходить на ваш домен только по HTTPS в течение заданного срока и тем самым блокирует атаки понижения; включать его нужно постепенно, увеличивая max-age шагами и добавляя includeSubDomains и preload только когда все поддомены работают по HTTPS.
Коротко
HSTS (HTTP Strict Transport Security) — это один заголовок ответа:
Strict-Transport-Security: max-age=31536000; includeSubDomains
Получив его по HTTPS, браузер в течение max-age секунд:
- сам превращает любой запрос
http://к вашему домену вhttps://ещё до отправки в сеть; - не даёт пользователю «пройти дальше» при ошибке сертификата на этом домене.
От какой атаки защищает HSTS
Редиректа с HTTP на HTTPS недостаточно. Когда пользователь вводит example.com или открывает старую ссылку http://, первый запрос браузера уходит без шифрования. Злоумышленник в том же Wi-Fi или на взломанном роутере может его перехватить и провести SSL stripping:
- Атакующий отвечает пользователю по обычному HTTP.
- Параллельно он общается с вашим настоящим сервером по HTTPS и пересылает страницы.
- Пользователь видит работающий сайт без замка и вводит пароль, который атакующий читает.
С HSTS браузер вообще не отправляет первый HTTP-запрос — перехватывать нечего. Остаётся только самый первый визит, до того как браузер увидел заголовок, — его закрывает preload-список.
Директивы
| Директива | Что делает | Рекомендация |
|---|---|---|
max-age | Сколько секунд браузер помнит правило | Наращивать постепенно до одного или двух лет |
includeSubDomains | Распространяет правило на все поддомены | Только после проверки всех поддоменов |
preload | Сообщает о согласии на включение во встроенные списки браузеров | Только после стабильного внедрения, см. ниже |
Браузеры игнорируют заголовок, пришедший по обычному HTTP, поэтому отдавать его нужно в HTTPS-ответах.
Безопасный план внедрения
- Составьте список поддоменов. DNS-записи, старые админки, веб-интерфейсы почты, staging, внутренние сервисы, оборудование. У каждого должен быть действующий сертификат и рабочий HTTPS.
- Начните с малого:
max-age=300безincludeSubDomains. Проверьте сайт, вход, оплату, встроенные виджеты. - Увеличивайте шагами: сутки (
86400), неделя (604800), месяц (2592000). Между шагами следите за ошибками. - Добавьте
includeSubDomainsснова с коротким max-age и затем увеличивайте. - Дойдите до года (
31536000) или двух (63072000). - Рассматривайте preload, только когда уверены, что весь домен останется на HTTPS.
Если что-то сломалось, отдайте max-age=0. Это сбросит правило только у тех браузеров, которые зайдут снова, — пользователи, получившие длинный max-age и не вернувшиеся, останутся привязаны к HTTPS до его истечения. Поэтому постепенность и важна.
Preload-список
Браузеры поставляются со встроенным списком доменов, которые работают только по HTTPS с первого визита. Чтобы подать домен на hstspreload.org, как правило, нужно:
- действующий сертификат и редирект с HTTP на HTTPS на том же хосте;
- все поддомены работают по HTTPS;
- на основном домене заголовок с
max-ageне меньше года, плюсincludeSubDomainsиpreload.
Удаление возможно, но медленно: оно доходит до пользователей только с новыми версиями браузеров. Считайте preload долгосрочным обязательством для всего домена, включая поддомены, которые вы создадите в будущем.
Настройка в nginx и частая ловушка
server {
listen 443 ssl;
server_name example.com;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
alwaysзаставляет nginx отдавать заголовок и в ответах с ошибками.- Если в блоке
locationесть свойadd_header, nginx не наследует заголовки с уровняserver, и HSTS там молча пропадает. Повторите его или вынесите общие заголовки в отдельный include-файл.
Проверка:
curl -sI https://example.com | grep -i strict-transport-security
В Chrome посмотреть и удалить сохранённое правило для домена можно на странице chrome://net-internals/#hsts.
Частые ошибки
includeSubDomainsвключён, а внутренний или старый поддомен работает только по HTTP.- Сразу выставлен max-age на год.
- Домен подан в preload «на всякий случай», без плана для будущих поддоменов.
- Заголовок задан только в приложении, а статика и страницы ошибок отдаются без него.
- Для локальной разработки используются
.devили.app: эти зоны целиком в preload-списке и требуют HTTPS.