Как работает CSP (Content Security Policy) и как защититься от XSS

8 минут чтения
Средний рейтинг статьи — 4.6

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.com

frame-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-приложениях.

8 минут чтения
Средний рейтинг статьи — 4.6

Настроить мониторинг за 30 секунд

Надежные оповещения о даунтаймах. Без ложных срабатываний