Веб
Заголовки безопасности: CSP, HSTS и другие — как получить A+ в сканерах
Какие HTTP-заголовки безопасности нужны, от чего защищает каждый и как правильно добавить их в nginx — с готовой конфигурацией.
· 7 мин. чтения

Заголовки безопасности — дополнительные инструкции, которые сервер отправляет браузеру с каждым ответом. Они говорят браузеру, как защищать страницу: открывать только по HTTPS, не выполнять чужие скрипты, не встраивать страницу в рамку на другом сайте и так далее.
Отсутствие заголовков — один из самых быстро обнаруживаемых недочётов и на экспертизе кибербезопасности, и в открытых сканерах (например, securityheaders.com или Mozilla Observatory). Хорошая новость: добавить их обычно можно несколькими строками конфигурации.
Основные заголовки и их назначение
Strict-Transport-Security (HSTS)
Приказывает браузеру в течение заданного срока открывать этот домен только по HTTPS. Даже если пользователь введёт http://, незашифрованный запрос не уйдёт.
Strict-Transport-Security: max-age=31536000; includeSubDomains
Перед добавлением includeSubDomains убедитесь, что все поддомены работают по HTTPS. Директиву preload добавляйте, только понимая последствия: выход из preload-списка занимает время.
Content-Security-Policy (CSP)
Самый мощный и самый сложный заголовок. Он определяет, из каких источников страница может загружать скрипты, стили, изображения, шрифты и куда может отправлять запросы. Правильно настроенный CSP заметно снижает последствия XSS-уязвимостей.
Строгая стартовая политика:
default-src 'self'; script-src 'self'; style-src 'self';
img-src 'self' data:; font-src 'self'; connect-src 'self';
object-src 'none'; base-uri 'self'; frame-ancestors 'self';
form-action 'self'
Важные моменты:
- Избегайте
'unsafe-inline'и'unsafe-eval'— они отменяют большую часть защиты CSP. Если нужен inline-скрипт, используйтеnonceили хеш. - Внешние сервисы (аналитика, платёжный виджет, карта) добавляйте с точным доменом, а не через
*. frame-ancestorsзащищает от clickjacking и в современных браузерах заменяетX-Frame-Options.
X-Content-Type-Options
X-Content-Type-Options: nosniff
Запрещает браузеру «угадывать» тип файла. Например, загруженный текстовый файл не будет выполнен как скрипт.
X-Frame-Options
X-Frame-Options: SAMEORIGIN
Запрещает открывать страницу внутри <iframe> на других сайтах. Полезно добавить для старых браузеров вместе с frame-ancestors в CSP.
Referrer-Policy
Referrer-Policy: strict-origin-when-cross-origin
При переходе на другой сайт передаётся только домен, а не полный URL с параметрами и токенами.
Permissions-Policy
Permissions-Policy: camera=(), microphone=(), geolocation=()
Отключает возможности браузера, которые сайт не использует. Даже если на страницу попадёт чужой код, он не сможет обратиться к камере или геолокации.
Скрытие версии сервера
По умолчанию nginx показывает свою версию в заголовке Server и на страницах ошибок. Это небольшой, но фиксируемый на экспертизе вид раскрытия информации. Его закрывает server_tokens off;.
Заметка:
X-XSS-Protection— устаревший заголовок. Современные браузеры его не поддерживают; добавлять его не обязательно, защиту даёт CSP.
Конфигурация nginx
Добавьте следующий блок внутрь server { ... } (в HTTPS-часть):
server_tokens off;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
Параметр always гарантирует, что заголовки отправляются и в ответах с ошибками (404, 500).
Частая ловушка: наследование add_header
В nginx директивы add_header наследуются вложенным блоком, только если в нём нет ни одного собственного add_header. Если вы напишете location /assets/ { add_header Cache-Control ...; }, в ответах этого location все заголовки безопасности пропадут.
Решение: вынести заголовки в отдельный файл и подключать его там, где нужно.
# в /etc/nginx/snippets/security-headers.conf — строки add_header выше
server {
include snippets/security-headers.conf;
location /assets/ {
include snippets/security-headers.conf;
add_header Cache-Control "public, max-age=31536000, immutable";
}
}
Безопасное внедрение CSP
Если сразу включить строгий CSP на существующем сайте, часть функций может сломаться. Поэтому действуйте поэтапно:
- Сначала включите политику через заголовок
Content-Security-Policy-Report-Only— браузер ничего не блокирует, только записывает нарушения в консоль (или на адресreport-uri). - Несколько дней собирайте нарушения и разбирайте каждое: это действительно нужный источник или лишний/чужой код?
- Вынесите inline-скрипты и стили в отдельные файлы или добавьте
nonce. - Когда политика станет чистой, переименуйте заголовок в
Content-Security-Policy.
Проверка результата
Посмотрите заголовки в браузере или в терминале:
curl -sI https://your-domain.uz | grep -iE "strict|content-security|x-content|x-frame|referrer|permissions|server"
Затем проверьте сайт на securityheaders.com и в Mozilla Observatory. Сканеры время от времени меняют критерии оценки, но обычно для высокой оценки решающее значение имеют HSTS и CSP без 'unsafe-inline'.
Помните: A+ в сканере означает только то, что заголовки настроены правильно. Это не говорит об отсутствии ошибок бизнес-логики или контроля доступа в приложении. Заголовки — лишь один слой защиты.
Итог
Заголовки безопасности — настройка, которая требует мало усилий и даёт ощутимую пользу. Добавьте HSTS, CSP, nosniff, Referrer-Policy, Permissions-Policy и server_tokens off, учтите наследование add_header и сначала обкатайте CSP в режиме report-only.
Хотите проверить заголовки и другие настройки своего сайта? Оставьте заявку на сканирование — Claude AI агент и наш специалист посмотрят конфигурацию и покажут, что нужно исправить.


