HTTP-заголовки безопасности служат основой защиты от различных угроз, таких как межсайтовый скриптинг (XSS), кликджекинг и атаки с внедрением данных. Однако в 2024 году только около 12% из топ-1 миллиона сайтов применяют Content Security Policy. В своей практике я неоднократно наблюдал, как правильная настройка этих заголовков предотвращает множество уязвимостей всего за несколько минут. В этом руководстве вы найдете подробные рекомендации и примеры конфигураций для Nginx и Apache.
- Почему заголовки безопасности важны
- Content Security Policy (CSP): что это и как настроить
- Strict-Transport-Security (HSTS): настройка заголовка
- X-Frame-Options
- X-Content-Type-Options
- Referrer-Policy
- Permissions-Policy
- Дополнительные полезные заголовки
- Настройка HTTP Security Headers в Nginx и Apache
- Nginx
- Apache
- Лучшие практики
- Распространённые ошибки при настройке заголовков безопасности
- Инструменты проверки HTTP Security Headers
- Ссылки
- Ответы на эти вопросы могут быть для вас полезными
Почему заголовки безопасности важны
Заголовки безопасности направляют браузеры в том, как обрабатывать ваш контент — определяют допустимые скрипты, возможность встраивания страницы в фрейм и передачи данных через рефереры. Их внедрение не требует затрат и обеспечивает защиту от множества атак, перечисленных в OWASP Top 10.
📖 Определение — HTTP-заголовки безопасности (HTTP Security Headers) — это заголовки ответа, отправляемые сервером, которые активируют механизмы безопасности на стороне браузера, ограничивая поведение, которое могут эксплуатировать злоумышленники.
Если вы выстраиваете защиту веб-приложения на уровне браузера, полезно отдельно посмотреть Безопасность API в 2026 году: поверхность атаки, которую пентест часто упускает, чтобы не ограничиваться только HTTP-заголовками и видеть полный контур риска.
Content Security Policy (CSP): что это и как настроить
CSP — самый мощный заголовок безопасности. Он определяет список разрешённых источников контента, эффективно нейтрализуя XSS, внедрение данных и несанкционированные встроенные скрипты.
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests;
| Директива | Управляет | Рекомендуемое значение |
|---|---|---|
| default-src | Запасной вариант для всех типов ресурсов | ‘self’ |
| script-src | Источники JavaScript | ‘self’ + конкретные CDN |
| style-src | Источники CSS | ‘self’ (избегайте ‘unsafe-inline’) |
| img-src | Источники изображений | ‘self’ data: https: |
| frame-ancestors | Кто может встраивать вашу страницу | ‘none’ |
| base-uri | Ограничивает элемент <base> | ‘self’ |
🎯 Начните с режима Content-Security-Policy-Report-Only, чтобы фиксировать нарушения без блокировки. Используйте директиву report-uri или report-to для сбора отчётов, затем итеративно ужесточайте политику.
🚫 Никогда не используйте 'unsafe-eval' в продакшен-CSP. Это повторно включает eval(), полностью подрывая защиту от XSS. Переработайте код, который вызывает eval(), new Function() или встроенные обработчики событий.
После настройки заголовков безопасности полезно отдельно посмотреть Firebase Cloud Functions: создание безопасных функций с правами администратора, чтобы сопоставить защиту фронтенда с практиками hardening на серверной стороне.
Strict-Transport-Security (HSTS): настройка заголовка
Принуждает браузеры подключаться только через HTTPS, предотвращая атаки на понижение протокола и SSL-стриппинг (SSL stripping).
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
X-Frame-Options
Предотвращает встраивание вашей страницы в элементы <iframe>, <frame> или <object> на других сайтах — блокируя атаки кликджекинга (clickjacking).
X-Frame-Options: DENY
| Значение | Поведение |
|---|---|
| DENY | Никогда не разрешать фреймирование (наиболее безопасно) |
| SAMEORIGIN | Разрешать фреймирование только с того же источника |
💡 Директива frame-ancestors в CSP предлагает современный и более детальный подход по сравнению с X-Frame-Options, обеспечивая гибкость в управлении фреймами. Рекомендуется использовать оба заголовка для максимальной совместимости с устаревшими браузерами.
X-Content-Type-Options
Предотвращает MIME-сниффинг (MIME sniffing) — ситуацию, когда браузер интерпретирует ответ в обход объявленного Content-Type. Блокирует атаки, которые маскируют исполняемый контент под безвредные типы файлов.
X-Content-Type-Options: nosniff
Это один из самых простых заголовков в настройке: одна строка конфигурации закрывает целый класс атак через подмену типа контента
Referrer-Policy
Управляет тем, какой объём информации о реферере (referrer) отправляется при переходе с вашего сайта на внешние ресурсы.
Referrer-Policy: strict-origin-when-cross-origin
Значение strict-origin-when-cross-origin — разумный баланс: при переходах внутри одного источника передаётся полный URL, при кросс-доменных переходах — только домен, а при переходе с HTTPS на HTTP реферер не передаётся вовсе.
Permissions-Policy
Управляет тем, какие функции браузера — камера, микрофон, геолокация и другие — могут использовать ваш сайт и встроенные iframe. Ранее этот заголовок назывался Feature-Policy.
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(self), usb=()
⚡ Совет: установите для неиспользуемых функций значение () (пустой список разрешений), чтобы явно отключить их. Это предотвращает скрытый доступ встроенных сторонних скриптов к чувствительным API — таким как камера или микрофон.
Дополнительные полезные заголовки
| Заголовок | Значение | Назначение |
|---|---|---|
| Cross-Origin-Opener-Policy | same-origin | Изолирует контекст просмотра, включает SharedArrayBuffer |
| Cross-Origin-Embedder-Policy | require-corp | Гарантирует, что все встроенные ресурсы явно разрешают загрузку |
| Cross-Origin-Resource-Policy | same-origin | Предотвращает загрузку ваших ресурсов другими источниками |
| X-DNS-Prefetch-Control | off | Предотвращает спекулятивные DNS-запросы (конфиденциальность) |
Эти заголовки особенно важны для приложений, использующих SharedArrayBuffer или требующих строгой изоляции кросс-доменных ресурсов.
Настройка HTTP Security Headers в Nginx и Apache
Nginx
# /etc/nginx/snippets/security-headers.conf
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data: https:; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options "DENY" 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 Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Embedder-Policy "require-corp" always;
# Include in server block:
# include snippets/security-headers.conf;
Apache
# .htaccess or httpd.conf
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; frame-ancestors 'none';"
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
Header always set X-Frame-Options "DENY"
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=()"
Лучшие практики
- Сначала разверните CSP в режиме
report-only, проанализируйте нарушения, затем включите принудительное применение - Используйте CSP на основе nonce (
'nonce-{random}') вместо'unsafe-inline'для встроенных скриптов - Добавляйте ключевое слово
alwaysв Nginx, чтобы заголовки отправлялись при всех кодах ответа (включая 4xx/5xx) - Тестируйте заголовки в staging-среде перед продакшеном — слишком строгий CSP может сломать легитимную функциональность
- Регулярно проверяйте заголовки с помощью автоматических сканеров по мере изменения зависимостей вашего сайта
- На нашем опыте удобнее всего запускать такой сканер прямо в CI/CD-пайплайне — регрессии выявляются до попадания изменений в продакшен
Распространённые ошибки при настройке заголовков безопасности
| Ошибка | Последствие | Исправление |
|---|---|---|
Использование 'unsafe-inline' + 'unsafe-eval' в CSP | Нейтрализует защиту от XSS | Используйте nonce или хэши вместо этого |
Отсутствие ключевого слова always в Nginx | Заголовки отсутствуют на страницах ошибок | Добавьте always к каждому add_header |
| HSTS без полного покрытия HTTPS | Поддомены становятся недоступными | Сначала убедитесь, что все поддомены имеют действительные TLS-сертификаты |
Забытый frame-ancestors в CSP | Кликджекинг по-прежнему возможен | Добавьте frame-ancestors 'none' в CSP |
Установка Referrer-Policy: unsafe-url | Полный URL утекает к третьим сторонам | Используйте strict-origin-when-cross-origin |
Инструменты проверки HTTP Security Headers
Просканируйте заголовки безопасности вашего сайта:
🔧 Security Header Scanner — проанализируйте все заголовки безопасности и получите практический отчёт с оценками.
Ссылки
- 📄 MDN — Content Security Policy (CSP)
- 📄 MDN — Strict-Transport-Security
- 📄 MDN — Permissions-Policy
- 📄 OWASP Secure Headers Project
- 📄 OWASP HTTP Headers Cheat Sheet
- 📄 MDN — Referrer-Policy
🎯 Ключевой вывод: заголовки безопасности — это бесплатные, высокоэффективные средства защиты. Как минимум разверните CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy и Permissions-Policy. Начните с CSP в режиме report-only, итерируйте на основе реальных отчётов о нарушениях, затем включите принудительное применение. Сочетайте это с регулярным сканированием, чтобы выявлять регрессии по мере изменения сторонних зависимостей.
Ответы на эти вопросы могут быть для вас полезными
Можно ли сломать сайт, включив заголовки безопасности?
Да, если не тестировать предварительно. Слишком строгий CSP заблокирует легитимные скрипты и стили. Именно поэтому рекомендуется начинать с режима Content-Security-Policy-Report-Only и анализировать отчёты о нарушениях перед включением принудительного применения.
Что делать, если на сайте используются сторонние скрипты — аналитика, чаты, рекламные сети?
Добавьте домены этих сервисов в соответствующие директивы CSP: например, script-src 'self' https://www.googletagmanager.com. Используйте режим report-only для выявления всех необходимых источников до перехода в боевой режим.
Нужно ли указывать always в конфигурации Nginx?
Обязательно. Без ключевого слова always заголовки отправляются только при кодах ответа 2xx. Страницы ошибок (404, 500 и другие) останутся без защиты, что создаёт уязвимость именно там, где пользователь может видеть чужой контент.
Чем frame-ancestors в CSP отличается от X-Frame-Options?
frame-ancestors — более современный механизм с поддержкой нескольких источников и гибкими правилами. X-Frame-Options поддерживается старыми браузерами, но не позволяет задавать список разрешённых доменов. Рекомендуется использовать оба заголовка одновременно для максимальной совместимости.
Как часто нужно пересматривать конфигурацию заголовков безопасности?
При каждом значимом изменении зависимостей: подключении нового CDN, сторонней библиотеки или виджета. Автоматический сканер, запускаемый в CI/CD-пайплайне, позволяет выявлять регрессии до попадания изменений в продакшен.



