Как работает CSP (Content Security Policy) и как защититься от XSS
XSS (Cross-Site Scripting) остаётся одной из самых распространённых уязвимостей веб-приложений.
Даже если backend хорошо защищён, достаточно одной ошибки во frontend или шаблонизаторе, чтобы злоумышленник смог выполнить произвольный JavaScript в браузере пользователя.
Одним из самых эффективных механизмов защиты от XSS является CSP — Content Security Policy.
В этой статье разберёмся, как работает CSP, какие проблемы он решает и как правильно внедрять его в production.
Что такое CSP
Content Security Policy — это HTTP-заголовок, который говорит браузеру:
- какие скрипты разрешено выполнять
- откуда можно загружать ресурсы
- какие inline-скрипты запрещены
- каким источникам доверяет приложение
Проще говоря, CSP ограничивает выполнение потенциально опасного контента.
Пример заголовка:
Content-Security-Policy: default-src 'self'; script-src 'self'Это означает:
- ресурсы разрешены только с текущего домена
- JavaScript можно выполнять только со своего origin
Почему XSS настолько опасен
При XSS злоумышленник может выполнить JavaScript в браузере пользователя.
Это позволяет:
- красть cookies
- воровать access token
- подменять интерфейс
- отправлять запросы от имени пользователя
- внедрять phishing UI
Особенно опасен stored XSS, когда вредоносный код сохраняется в базе данных и показывается всем пользователям.
Как CSP помогает против XSS
Главная идея CSP — браузер перестаёт доверять любому JavaScript по умолчанию.
Например, без CSP браузер выполнит такой код:
<script>alert('XSS')</script>Но при строгой политике inline-скрипты будут заблокированы.
Даже если злоумышленнику удалось внедрить JavaScript в HTML, браузер просто не даст его выполнить.
Самые важные директивы CSP
default-src — базовая политика для всех ресурсов. Разрешает загрузку только со своего домена:
default-src 'self'script-src — управляет выполнением JavaScript. Это ключевая директива против XSS:
script-src 'self' https://cdn.example.comЗдесь разрешены локальные скрипты и скрипты с CDN.
style-src — определяет разрешённые CSS-источники. Это важно, потому что через CSS тоже возможны некоторые атаки.
img-src — ограничивает загрузку изображений. Полезно против tracking pixel, data exfiltration и вредоносных внешних ресурсов.
connect-src — управляет AJAX/fetch/WebSocket соединениями:
connect-src 'self' https://api.example.comframe-ancestors — защищает от clickjacking. Позволяет определить, кто может встраивать сайт через iframe.
Почему unsafe-inline — плохая идея
Очень часто можно увидеть:
script-src 'self' 'unsafe-inline'Это почти полностью ломает смысл CSP.
Потому что unsafe-inline снова разрешает выполнение inline JavaScript.
Например:
<button onclick="evil()">или:
<script>alert(1)</script>По возможности unsafe-inline нужно избегать.
Nonce и hash-based CSP
Nonce — это случайный одноразовый идентификатор для доверенных скриптов.
Пример:
Content-Security-Policy: script-src 'self' 'nonce-abcd1234'И в HTML:
<script nonce="abcd1234">Браузер выполнит только скрипты с правильным nonce. Это один из самых безопасных способов работы с CSP.
Вместо nonce можно использовать hash содержимого скрипта:
script-src 'sha256-abc123...'Тогда браузер разрешит только конкретный JavaScript с известным hash. Этот подход часто используют для небольших inline-скриптов.
Почему CSP сложно внедрять
На старых проектах CSP часто ломает frontend.
Причины:
- inline JavaScript
- inline CSS
- сторонние виджеты
- старые библиотеки
- динамическая генерация script-tag
После включения строгой политики часть приложения может перестать работать.
Поэтому CSP обычно внедряют постепенно.
Report-Only режим
Для безопасного внедрения существует режим:
Content-Security-Policy-Report-OnlyВ этом случае браузер:
- не блокирует нарушения
- но отправляет отчёты о проблемах
Это позволяет увидеть:
- какие скрипты ломаются
- какие ресурсы нарушают политику
- что нужно исправить перед включением CSP
В production это очень полезно.
Как CSP связан с современным frontend
Современные SPA и frontend-framework часто активно используют:
- динамический JavaScript
- hydration
- third-party аналитику
- внешние CDN
Из-за этого политика CSP становится сложнее.
Особенно много проблем возникает с:
- Google Tag Manager
- скрипты аналитики
- inline hydration data
- легаси код React/Vue
Поэтому внедрение CSP обычно требует аудита фронтэндовой части приложения.
Какие ошибки встречаются чаще всего
Типичные проблемы:
- использование unsafe-inline
- слишком широкие wildcard-правила
- разрешение script-src *
- отсутствие frame-ancestors
- забытый Report-Only режим
Например:
script-src *Практически бесполезен с точки зрения безопасности.
Как проверять CSP
Самый простой способ — DevTools браузера.
В консоли браузер показывает:
- CSP violations
- blocked resources
- ошибки политики
Также удобно использовать:
curl -I https://example.comЧтобы проверить наличие заголовка:
Content-Security-PolicyГде CSP особенно важен
CSP особенно полезен для:
- admin panel
- SaaS-сервисов
- личных кабинетов
- fintech-приложений
- корпоративных dashboard
- CMS
То есть везде, где XSS может привести к компрометации аккаунтов.
Итоги
Content Security Policy — один из самых эффективных механизмов защиты браузерных приложений от XSS.
CSP ограничивает выполнение JavaScript и позволяет браузеру доверять только заранее разрешённым источникам.
Наиболее важные практики:
- использовать script-src
- избегать unsafe-inline
- применять nonce или hash
- внедрять CSP через Report-Only
- постепенно ужесточать политику
При правильной настройке CSP значительно снижает риск эксплуатации XSS даже в больших production-приложениях.
Настроить мониторинг за 30 секунд
Надежные оповещения о даунтаймах. Без ложных срабатываний