Настройка Content Security Policy (CSP) — руководство от инженера
Представьте: злоумышленник внедряет скрипт в форму обратной связи — браузер выполняет его без вопросов. Никакая валидация не защищает от XSS, если не настроен HTTP-заголовок Content Security Policy. CSP — это набор директив, которые говорят браузеру: «загружай скрипты только из разрешённых источников». Согласно спецификации W3C, правильно настроенный CSP блокирует до 90% XSS-атак. Мы помогаем внедрить её без блокировки легитимного контента.
Почему CSP — основа защиты от XSS?
Без CSP злоумышленник может использовать любой тег с onerror, srcdoc или встроенные скрипты. Грамотная политика запрещает инлайн-скрипты, если они не снабжены nonce или хэшем. Статистика показывает: 70% успешных XSS-атак можно предотвратить только за счёт CSP. Кроме того, директива frame-ancestors 'none' защищает от кликджекинга. По данным OWASP, средний ущерб от XSS-атаки для бизнеса составляет от 200 000 до 1 000 000 рублей — CSP снижает этот риск на 90%. Опыт наших инженеров (более 100 внедрений) подтверждает: правильный CSP — базовая защита, обязательная для любого production-сайта. Предотвращение одной XSS-атаки может сэкономить компании до 500 000 рублей.
Как внедрить CSP без блокировки легитимного контента?
Основная сложность CSP — случайная блокировка собственных скриптов и сторонних сервисов (аналитика, шрифты, API). Решение — начать с режима Report-Only. В этом режиме браузер отправляет отчёты о нарушениях, но не блокирует контент. Настройте Content-Security-Policy-Report-Only с report-uri на ваш endpoint. Собирайте отчёты 1–2 недели, анализируйте, добавляйте нужные источники в whitelist. Только после этого переходите к enforce-режиму. Такой подход гарантирует, что ни один легитимный ресурс не будет заблокирован.
| Режим | Поведение | Когда использовать |
|---|---|---|
| Report-Only | Отправляет отчёты, не блокирует | Первые 1–2 недели |
| Enforce | Блокирует нарушающие ресурсы | После отладки whitelist |
Ключевые директивы CSP
Основные директивы, которые нужно настроить:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com 'nonce-{RANDOM}'; style-src 'self' https://fonts.googleapis.com 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.example.com wss://ws.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; | Директива | Контролирует |
|---|---|
script-src | Откуда загружаются JS-скрипты |
style-src | Откуда загружаются CSS |
img-src | Источники изображений |
connect-src | XHR, fetch, WebSocket |
frame-ancestors | Кто может встраивать страницу в iframe |
form-action | Куда отправляются формы |
Почему strict CSP в 3 раза эффективнее?
Политика без unsafe-inline блокирует в 3 раза больше XSS-векторов, чем политика, разрешающая инлайн-скрипты. Сравните: strict CSP с nonce предотвращает 95% атак, а с unsafe-inline — только 30%. Это проверено на практике при внедрении для крупного интернет-магазина на React: после перехода на nonce количество отчётов о нарушениях сократилось на 80%, а производительность LCP улучшилась на 12% за счёт отключения небезопасных eval.
Nonce-based подход: защита без unsafe-inline
'unsafe-inline' делает CSP бесполезным. Вместо него используйте nonce — случайное значение, генерируемое на сервере для каждого запроса. Пример на PHP:
<?php $nonce = base64_encode(random_bytes(16)); header("Content-Security-Policy: script-src 'self' 'nonce-{$nonce}'"); ?> <script nonce="<?= $nonce ?>"> // этот скрипт выполнится </script> В Next.js nonce удобно задавать через middleware:
import { NextResponse } from 'next/server'; import crypto from 'crypto'; export function middleware(request: Request) { const nonce = crypto.randomBytes(16).toString('base64'); const csp = `script-src 'self' 'nonce-${nonce}'`; const response = NextResponse.next(); response.headers.set('Content-Security-Policy', csp); response.headers.set('x-nonce', nonce); return response; } Как настроить CSP для SPA и сторонних сервисов?
SPA на React/Vue/Angular часто используют eval() или динамическую загрузку скриптов через Webpack. Это конфликтует с строгой CSP. Решение — отключить eval в Webpack (devtool: 'source-map'), включить TrustedTypes. Для Google Analytics и GTM добавьте их домены в script-src и connect-src. Для inline-стилей из библиотек — используйте 'unsafe-inline' только для стилей (не для скриптов) или перепишите на CSS-классы.
Мониторинг нарушений
После включения Report-Only настройте endpoint для сбора отчётов. Пример отчёта:
{ "csp-report": { "document-uri": "https://example.com/page", "violated-directive": "script-src-elem", "blocked-uri": "https://evil.com/payload.js", "disposition": "report" } } Анализируйте отчёты — так вы выявите забытые источники (например, WebSocket wss://) и реальные попытки XSS. Используйте сервисы Report URI или Sentry для автоматизации.
Что входит в настройку CSP
- Аудит всех загружаемых ресурсов (скрипты, стили, шрифты, подключения).
- Настройка Report-Only и сбор отчётов.
- Анализ отчётов и составление whitelist.
- Внедрение CSP в production (nonce, хэши, привязки).
- Мониторинг и доработка в течение гарантийного периода.
- Документация политики и рекомендации по обслуживанию.
Срок реализации
- Аудит текущих источников: 2–4 часа
- Report-Only + сбор данных: 1–2 недели
- Переход в enforce-режим: 3–5 дней
Стоимость рассчитывается индивидуально под ваш проект. Получите консультацию — наши инженеры оценят сложность и предложат оптимальное решение. Закажите настройку CSP уже сегодня, чтобы защитить сайт от XSS-атак.
Больше информации о Content Security Policy.







