Чек-лист заголовков безопасности HTTP (с готовыми конфигами)
Несколько заголовков ответа блокируют целые классы атак: кликджекинг, MIME-сниффинг, понижение протокола и значительную часть XSS, почти без затрат. Ниже — заголовки, которые стоит отправлять, безопасные стартовые значения и способ внедрить самый сложный из них (CSP), не сломав сайт.
Чек-лист
| Заголовок | Безопасное значение | Защищает от |
|---|---|---|
Strict-Transport-Security | max-age=31536000; includeSubDomains | Понижения до HTTPS и кражи cookie в публичных Wi-Fi сетях |
Content-Security-Policy | Начните в режиме report-only (см. ниже) | XSS, внедрённые скрипты, утечка данных |
X-Content-Type-Options | nosniff | Запуск загруженных файлов браузером как скриптов |
CSP frame-ancestors | 'self' (или X-Frame-Options: SAMEORIGIN) | Кликджекинг |
Referrer-Policy | strict-origin-when-cross-origin | Утечка полных URL (токенов, ID) на другие сайты |
Permissions-Policy | camera=(), microphone=(), geolocation=() | Сторонние скрипты, использующие возможности устройства |
Проверьте, какие из этих заголовков отдаёт ваш сайт сейчас, и получите оценку в проверке заголовков безопасности.
HSTS: начните с малого
Увидев HSTS, браузер в течение всего max-age отказывается открывать сайт по обычному HTTP. Сначала убедитесь, что все поддомены работают по HTTPS (сертификаты можно проверить в SSL-чекере), начните с max-age=300, а затем увеличьте до года. Добавляйте preload и отправляйте сайт в список HSTS preload только тогда, когда вы уверены: удаление из списка занимает месяцы.
Content-Security-Policy без поломок
CSP задаёт, откуда могут загружаться скрипты, стили, изображения и соединения. Внедряйте политику в режиме report-only: она фиксирует нарушения, ничего не блокируя:
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' https://www.googletagmanager.com; img-src 'self' data: https:; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'; report-uri /csp-report
Неделю следите за консолью браузера и эндпоинтом отчётов, добавьте источники, которые вы действительно используете, а затем переименуйте заголовок в Content-Security-Policy. Не используйте 'unsafe-inline' для скриптов; для встроенных скриптов, которые вы контролируете, применяйте nonce или хеши. Собрать политику по источникам поможет генератор CSP.
Конфигурации
Nginx (внутри server; параметр always сохраняет заголовки и на страницах ошибок):
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "frame-ancestors 'self'" always;
Apache (.htaccess, с mod_headers):
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Vercel (vercel.json):
{ "headers": [ { "source": "/(.*)", "headers": [
{ "key": "Strict-Transport-Security", "value": "max-age=31536000; includeSubDomains" },
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" }
] } ] }
Полные конфиги серверов можно сгенерировать в генераторе конфигов Nginx или в генераторе .htaccess.
Заголовки, от которых можно отказаться
X-XSS-Protection устарел: современные браузеры удалили фильтр, которым он управлял, а если заголовок всё же отправляется, рекомендуемое значение — 0. Expect-CT объявлен устаревшим. Скрытие Server и X-Powered-By — хорошая гигиена, но не реальная защита.