Content Security Policy (CSP) — один из самых мощных механизмов защиты веб-приложений от атак межсайтового скриптинга (XSS). В отличие от фильтрации входных данных, CSP работает на уровне браузера: вы явно указываете, из каких источников разрешено загружать скрипты, стили, изображения и другие ресурсы. Любая попытка загрузить контент из неразрешённого источника блокируется до выполнения.
Зачем нужен CSP
XSS-атаки остаются в топе уязвимостей OWASP. Злоумышленник может внедрить вредоносный скрипт через комментарии, формы обратной связи, параметры URL или уязвимости в сторонних библиотеках. CSP не устраняет уязвимость в коде, но предотвращает выполнение внедрённого скрипта — браузер просто откажется его загружать.
Дополнительно CSP защищает от:
- Загрузки ресурсов с компрометированных CDN
- Внедрения скриптов через уязвимости в плагинах
- Data URI injection в атрибутах
Проверить текущую конфигурацию CSP и других заголовков безопасности можно с помощью анализатора заголовков безопасности и CSP-анализатора на rechecker.ru.
Основные директивы CSP
script-src и style-src
Директивы script-src и style-src контролируют источники JavaScript и CSS. Без явного указания 'unsafe-inline' inline-скрипты и стили блокируются.
Content-Security-Policy: script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'
| Ключевое слово | Описание |
|---|---|
'self' | Только с того же origin (схема + домен + порт) |
'none' | Запретить все источники |
'unsafe-inline' | Разрешить inline-скрипты/стили (снижает защиту) |
'unsafe-eval' | Разрешить eval(), new Function() (избегать) |
'strict-dynamic' | Скрипты, загруженные доверенным скриптом, считаются доверенными |
default-src
Директива по умолчанию для всех типов ресурсов, если конкретная директива не указана.
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com
img-src, font-src, connect-src
img-src— источники изображенийfont-src— шрифты (Google Fonts, self-hosted)connect-src— XHR, fetch, WebSocket, EventSource
Content-Security-Policy: img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.example.com
frame-ancestors
Контролирует, кто может встраивать страницу в iframe. Заменяет X-Frame-Options с расширенными возможностями.
Content-Security-Policy: frame-ancestors 'self' https://trusted-partner.com
Режим Report-Only
Перед включением блокирующей политики используйте Content-Security-Policy-Report-Only. Браузер будет отправлять отчёты о нарушениях, но не блокировать контент. Подробнее о тестировании политики без блокировки — в статье CSP Report-Only: как тестировать политику без блокировки.
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
Современный вариант — report-to с Report API:
Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpoint
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"/csp-report"}]}
Примеры конфигурации
Минимальная политика для статического сайта
Content-Security-Policy: default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'
Сайт с Google Analytics и reCAPTCHA
Content-Security-Policy: default-src 'self'; script-src 'self' https://www.googletagmanager.com https://www.google.com https://www.gstatic.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https://www.google-analytics.com
SPA с CDN и API
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; connect-src 'self' https://api.example.com wss://realtime.example.com; img-src 'self' data: https:; font-src 'self' https://cdn.jsdelivr.net
Nonce и Hash для inline-скриптов
Вместо 'unsafe-inline' используйте nonce — одноразовый токен, генерируемый сервером для каждого запроса:
<script nonce="r4nd0mV4lu3">
// Этот скрипт выполнится, если nonce совпадает с CSP
console.log('Authorized inline script');
</script>
Content-Security-Policy: script-src 'self' 'nonce-r4nd0mV4lu3'
Альтернатива — hash: SHA-256 от содержимого скрипта. Подходит для статического контента.
Внедрение в Nginx
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://trusted-cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;" always;
Внедрение в Apache
Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://trusted-cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;"
Внедрение в Node.js (Express)
app.use((req, res, next) => {
res.setHeader(
'Content-Security-Policy',
"default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;"
);
next();
});
Типичные ошибки
- Слишком широкий
img-src 'self' https:— разрешает любые HTTPS-изображения. Укажите конкретные домены. 'unsafe-inline'в script-src — сводит защиту от XSS к минимуму. Используйте nonce или hash.- Забыли connect-src — API-запросы и WebSocket могут блокироваться.
- Не тестировали в Report-Only — блокирующая политика может сломать функциональность.
Пошаговый план внедрения
- Соберите список всех внешних ресурсов (CDN, аналитика, виджеты).
- Включите политику в режиме Report-Only с
report-uriилиreport-to. - Соберите отчёты за 1–2 недели, проанализируйте нарушения.
- Добавьте легитимные источники в директивы.
- Замените inline-скрипты на внешние или добавьте nonce/hash.
- Переключите на блокирующий режим
Content-Security-Policy. - Мониторьте отчёты на предмет новых нарушений.
Полное руководство по настройке CSP с учётом всех директив и edge cases — в материале Content Security Policy: полное руководство по настройке.