Включение Content Security Policy на работающем сайте может сломать функциональность: скрипты аналитики, виджеты, inline-скрипты окажутся заблокированными. Режим Report-Only позволяет проверить политику без блокировки — браузер только отправляет отчёты о нарушениях.
Проверить текущую CSP и отладить политику можно с помощью CSP Analyzer на rechecker.ru.
Как работает Report-Only
Заголовок Content-Security-Policy-Report-Only действует так же, как Content-Security-Policy, но при нарушениях не блокирует ресурсы — только отправляет отчёт на указанный endpoint. Это даёт возможность:
- Увидеть все ресурсы, которые загружает сайт
- Выявить inline-скрипты и стили
- Собрать список сторонних доменов
- Настроить политику до включения блокировки
Синтаксис
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
Или с 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"}]}
report-uri vs report-to
| Параметр | report-uri | report-to |
|---|---|---|
| Статус | Устаревает (deprecated) | Рекомендуется |
| Формат | POST на URL | Report API |
| Поддержка | Широкая | Современные браузеры |
| Группировка | Нет | Да (группа endpoints) |
Для максимальной совместимости можно указать оба:
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report; report-to csp-endpoint
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"/csp-report"}]}
Формат отчёта (report-uri)
POST-запрос на report-uri с телом:
{
"csp-report": {
"document-uri": "https://example.com/page",
"referrer": "https://example.com/",
"violated-directive": "script-src",
"effective-directive": "script-src",
"blocked-uri": "https://evil.com/malicious.js",
"original-policy": "default-src 'self'; script-src 'self'",
"disposition": "report",
"status-code": 200,
"source-file": "https://example.com/page",
"line-number": 15,
"column-number": 10
}
}
Content-Type: application/csp-report
Обработка отчётов на сервере
Node.js (Express)
app.post('/csp-report', express.json({ type: 'application/csp-report' }), (req, res) => {
const report = req.body['csp-report'];
if (report) {
console.log('CSP violation:', {
document: report['document-uri'],
directive: report['violated-directive'],
blocked: report['blocked-uri'],
line: report['line-number'],
column: report['column-number']
});
// Сохранить в БД, отправить в Sentry и т.д.
}
res.status(204).end();
});
Nginx
Nginx не обрабатывает POST-тело для CSP-отчётов. Нужен backend (Node, PHP, Python) или сервис вроде report-uri.com.
Логирование в файл
app.post('/csp-report', express.raw({ type: 'application/csp-report' }), (req, res) => {
fs.appendFileSync('csp-reports.log', JSON.stringify(req.body) + '\n');
res.status(204).end();
});
Стратегия тестирования
Этап 1: Строгая политика в Report-Only
Включите максимально строгую политику, которую хотите достичь:
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; report-uri /csp-report
Соберите отчёты за 1–2 недели. Вы получите полный список нарушений.
Этап 2: Анализ отчётов
Группируйте по:
violated-directive— какая директива нарушенаblocked-uri— какие источники нужно добавитьdocument-uri— на каких страницах проблемы
Этап 3: Постепенное ужесточение
Добавляйте легитимные источники в политику. Для inline-скриптов решайте:
- Вынести во внешний файл
- Добавить nonce
- Вычислить hash (для статики)
Этап 4: Переход на блокирующий режим
Когда отчётов станет мало или они будут только от ботов/расширений — замените на Content-Security-Policy.
Одновременное использование обоих заголовков
Можно иметь оба: блокирующую политику и Report-Only для мониторинга:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.com
Content-Security-Policy-Report-Only: default-src 'none'; report-uri /csp-report
Report-Only с более строгой политикой покажет потенциальные нарушения, которые текущая политика ещё разрешает.
Интеграция с Sentry
Sentry поддерживает CSP-отчёты. Настройте report-uri на endpoint Sentry или проксируйте отчёты:
app.post('/csp-report', express.json({ type: 'application/csp-report' }), (req, res) => {
const report = req.body['csp-report'];
if (report) {
Sentry.captureMessage('CSP violation', {
level: 'warning',
extra: report
});
}
res.status(204).end();
});
Типичные нарушения при первом запуске
- Inline-скрипты — Google Analytics, плагины, реклама
- Сторонние CDN — jQuery, Bootstrap, шрифты
- data: URI — inline images, base64
- eval() — некоторые старые библиотеки
- blob: — генерация файлов в браузере
Рекомендации
- Не оставляйте Report-Only навсегда без обработки — отчёты будут накапливаться
- Фильтруйте шум (боты, расширения с внедрённым контентом)
- Используйте Report-Only перед каждым ужесточением политики
- Полное руководство по CSP: Content Security Policy: полное руководство по настройке