Content Security Policy в WordPress — это дополнительный уровень защиты браузера, который ограничивает, откуда страница может загружать и выполнять скрипты, стили, iframe, изображения и другие ресурсы. Правильно настроенная CSP помогает уменьшить последствия внедрения вредоносного кода, но неправильно настроенная политика способна сразу сломать checkout, формы, аналитику, Elementor, видеовиджеты и внешние интеграции.
Поэтому CSP для WordPress лучше внедрять не как «один заголовок из генератора», а как контролируемый rollout: сначала увидеть реальное поведение сайта, затем ограничить источники и только после тестирования включать блокировку.
Что именно делает CSP
Спецификация Content Security Policy Level 3 определяет механизм, который позволяет сайту управлять ресурсами, разрешёнными для загрузки и выполнения. CSP полезна как defense-in-depth: она снижает возможности вредоносного кода после инъекции, но не заменяет валидацию данных, экранирование вывода, обновления и устранение самой уязвимости.
Для WordPress это особенно важно, потому что одна страница может собираться из ядра, темы, нескольких плагинов, inline-скриптов и внешних сервисов. Политика должна учитывать фактическую архитектуру конкретного сайта.
Почему нельзя сразу включать строгий Content-Security-Policy
Если поставить script-src 'self' на сайте, который использует Google Analytics, платежный виджет, Turnstile, карту, чат или CDN, браузер начнёт блокировать эти ресурсы. На первый взгляд страница может выглядеть нормально, а ошибка проявится только при отправке формы или оплате.
Поэтому безопаснее начинать с Content-Security-Policy-Report-Only. W3C прямо предусматривает этот режим для наблюдения за нарушениями без принудительной блокировки. Он позволяет собрать список реальных источников и увидеть, что сломалось бы при enforcement.
Report-Only — обязательный этап для рабочего сайта
В режиме Report-Only браузер оценивает политику и сообщает о нарушениях, но продолжает загружать ресурс. Это удобно для production, где нельзя экспериментировать ценой неработающего checkout.
Практический процесс выглядит так:
- собрать текущие внешние домены и inline-скрипты;
- добавить базовую Report-Only политику;
- пройти ключевые пользовательские сценарии;
- собрать нарушения из браузера и endpoint отчётов;
- отделить нужные источники от случайных и устаревших;
- ужесточить директивы;
- только после проверки переключить заголовок на enforcement.
Какие директивы встречаются чаще всего
У CSP много директив, но для WordPress обычно начинают с нескольких основных.
default-srcзадаёт fallback для типов ресурсов, у которых нет отдельной директивы;script-srcуправляет JavaScript;style-srcограничивает CSS;img-src— изображения;font-src— шрифты;connect-src— fetch, XHR, WebSocket и другие соединения;frame-src— загружаемые iframe;frame-ancestorsограничивает, кто может встраивать вашу страницу;object-srcобычно можно сильно ограничить на современных сайтах.
Нельзя копировать список доменов из другого проекта: даже два WordPress-сайта на одинаковой теме могут иметь разные аналитические и рекламные интеграции.
script-src — самый чувствительный участок
MDN отмечает, что script-src контролирует не только внешние файлы JavaScript, но и inline-скрипты и обработчики. Именно поэтому WordPress-проект часто сталкивается с проблемой 'unsafe-inline'.
Просто разрешить 'unsafe-inline' легко, но это заметно ослабляет смысл CSP. Более строгий вариант — использовать nonce или hashes для доверенных inline-блоков. Подробности описаны в MDN script-src.
Что такое nonce и почему он должен меняться
Nonce — случайное значение, которое сервер добавляет одновременно в CSP и в доверенный <script>. Браузер запускает скрипт только при совпадении значения.
Nonce должен быть непредсказуемым и уникальным для каждого ответа. Статическая строка, прописанная раз и навсегда в конфиге Nginx, не даёт нужной модели доверия. Именно поэтому nonce-подход в WordPress требует интеграции с генерацией HTML, а не только изменения заголовка веб-сервера.
Hashes подходят для стабильных inline-блоков
Для статического inline-скрипта можно разрешить конкретный SHA-256/384/512 hash. Но любое изменение пробелов или содержимого меняет hash. На WordPress, где плагины могут генерировать динамические inline-настройки, такой способ подходит не для каждого блока.
В итоге на реальном проекте часто используется комбинация: внешние источники с точным allowlist, nonce для динамических доверенных скриптов и hashes для действительно стабильных фрагментов.
Elementor, WooCommerce и плагины требуют инвентаризации
Конструкторы и плагины могут добавлять inline CSS/JS, JSON-конфигурацию, динамические загрузчики и запросы к внешним доменам. Поэтому CSP нужно тестировать на всех шаблонах, а не только на главной странице.
Для WooCommerce отдельно проверяются каталог, карточка товара, корзина, checkout, личный кабинет и платёжный сценарий. Даже если CSP не блокирует интерфейс магазина, она может мешать 3-D Secure iframe, токенизации карты или callback-скрипту платёжного провайдера.
Turnstile требует собственных разрешений
Если сайт использует Cloudflare Turnstile, Cloudflare указывает, что CSP должна разрешать его скрипты и iframe. В документации перечислены https://challenges.cloudflare.com для script-src и frame-src; также поддерживается nonce-based подход. Актуальные требования стоит брать из официальной документации Cloudflare, а не из старого примера в блоге.
Практическую установку Turnstile на формы WordPress я отдельно разбирал в статье Cloudflare Turnstile для WordPress.
Где задавать CSP: сервер, CDN или WordPress
Предпочтительный способ доставки политики — HTTP response header. Технически CSP можно добавить на уровне Nginx/Apache, CDN или PHP. Выбор зависит от того, нужна ли статическая политика или динамический nonce.
Статические директивы удобно контролировать на веб-сервере или reverse proxy. Если же nonce должен создаваться для каждого запроса и попадать в теги WordPress, появляется логика на уровне приложения.
Важно иметь один понятный источник политики. Когда часть CSP добавляет Nginx, часть security-плагин, а часть CDN, диагностика становится сложнее: браузер применяет несколько политик одновременно, и результат может оказаться строже, чем ожидалось.
Не начинайте с огромного allowlist
Бессмысленно разрешить https:, все wildcard-домены и 'unsafe-inline', а затем считать задачу выполненной. Такая политика может почти не ограничивать вредоносный сценарий.
Цель — минимальный набор действительно необходимых источников. Если сайт больше не использует старый чат или аналитический сервис, его домен не должен оставаться в CSP «на всякий случай».
Проверка после включения enforcement
- главная и ключевые лендинги открываются без CSP errors;
- Elementor/тема корректно выполняют интерактивные скрипты;
- формы отправляются;
- Turnstile/reCAPTCHA загружаются;
- аналитика и рекламные события отправляются;
- WooCommerce checkout проходит до успешной оплаты;
- личный кабинет и AJAX-функции работают;
- видео, карты, чаты и iframe не блокируются;
- административная часть не получает неожиданных ограничений;
- отчёты CSP продолжают контролироваться после релиза.
CSP не заменяет базовую безопасность WordPress
CSP полезна против части последствий content injection, но она не обновляет уязвимый плагин, не исправляет SQL injection, не делает пароль сильнее и не создаёт резервную копию. Нужен комплексный подход, который я описывал в материале Безопасность WordPress на практике.
Если сайт давно не обслуживался, сначала разумно устранить очевидные проблемы обновлений и доступа, а затем добавлять строгие browser-level ограничения.
Как внедрять CSP без хаоса
Я начинаю с аудита фактических ресурсов сайта и ключевых сценариев. Затем формирую Report-Only политику, убираю ненужные внешние зависимости и постепенно перевожу inline-код на безопасные механизмы там, где это технически оправдано.
После включения enforcement проверяю не только визуальную часть, но и реальные действия: отправку форм, оплату, авторизацию, AJAX, webhooks со стороны браузера и внешние виджеты. При необходимости такую работу можно включить в техническую поддержку WordPress.
Если нужна CSP для рабочего WordPress или WooCommerce без экспериментов на пользователях, пришлите ссылку и список критичных интеграций. Сначала проверю текущие источники и предложу безопасный план rollout через Report-Only.
Обсуждение
Вопросы и комментарии
Можно уточнить детали статьи или поделиться своим опытом. Первый комментарий проходит проверку.