Контент-безопасность сайта: настройка CSP, риски обхода и внедрение

CSP (Content Security Policy) — это заголовок ответа, который говорит браузеру, какие скрипты могут выполняться и с каких доменов можно загружать ресурсы. Внедрять нужно в три этапа: сначала 14 дней работать в режиме Report-Only и собирать источники нарушений, затем сузить белый список,

CSP部署:报告模式先跑两周再切强制CSP: report-only for two weeks, then enforce 一上来就enforce会把站内第三方脚本全打挂Enforcing on day one breaks every third-party script 1 Report-Only1 Report-Only 只收集违规 不拦截Collect violations, no block 跑14天 收集所有来源Run 14 days to collect sources 2 白名单收敛2 Whitelist tuning 按报告加域名 不violent-inlineAdd domains from reports sha256 hash 替代unsafe-inlinesha256 instead of unsafe-inline 3 Enforce3 Enforce 违规日志为0再切Switch when reports hit 0 保留report-uri 继续监控Keep report-uri watching 核心指令Core directives default-src 兜底 script-src 控脚本default-src fallback, script-src controls JS object-src ‘none’ frame-ancestors 防嵌套object-src none, frame-ancestors 红线Red lines 别开 * 通配符 等于没配Wildcard * equals no CSP unsafe-inline 留着等于被绕过unsafe-inline defeats the purpose 判定:报告模式跑满14天且违规数降到个位数,再切EnforceDecision: enforce after 14 days of near-zero reports 反直觉:CSP不是越严越安全,配错了比不配更危险Counterintuitive: misconfigured CSP is worse than none 先报告后强制,把违规源一个个收进白名单Report first, enforce later
Три этапа внедрения CSP: сбор в Report-Only, сужение белого списка, принудительный режим Enforce

Контент-безопасность сайта: настройка CSP, риски обхода и внедрение

Сначала вывод: CSP (Content Security Policy) — это заголовок ответа, который говорит браузеру, какие скрипты могут выполняться и с каких доменов можно загружать ресурсы. Внедрять нужно в три этапа: сначала 14 дней работать в режиме Report-Only и собирать источники нарушений, затем сузить белый список и только когда журнал нарушений сократится до единиц, переключаться на Enforce. Контринтуитивный вывод: неправильно настроенная CSP опаснее, чем её отсутствие — включённый unsafe-inline означает, что эта стена построена впустую.

1. Что именно блокирует CSP

CSP передаёт правила через HTTP-заголовок ответа, и браузер по ним решает, какие ресурсы можно загружать. Она защищает в основном от двух проблем: вредоносных скриптов, внедрённых через XSS, и неавторизованных сторонних доменов, встроенных в страницу.

Это не файрвол. CSP не защищает от SQL-инъекций и от взлома сервера — она управляет загрузкой ресурсов на стороне браузера. С HTTPS и HSTS она работает в связке; о настройке HTTPS читайте в статье Настройка HTTPS для собственного сайта.

Частая проблема собственных сайтов — слишком много сторонних скриптов: GA4, GTM, Hotjar, онлайн-чат, рекламные пиксели. С каждым новым скриптом в белый список CSP нужно добавлять домен, иначе браузер заблокирует скрипт. О работе со сторонними скриптами читайте в разделе Работа со сторонними скриптами на собственном сайте.

Часто упускают из виду, что CSP почти не влияет на SEO. Googlebot сам по себе не применяет ограничения на ресурсы помимо JS, и правильно настроенная CSP не влияет на индексацию. Бояться, что CSP помешает сканированию, излишне.

Директива Что управляет Рекомендуемое значение
default-src Резерв для всех ресурсов ‘self’
script-src Источники JS-скриптов ‘self’ + домены аналитики
style-src Источники CSS ‘self’ ‘unsafe-inline’
img-src Источники изображений ‘self’ data: + CDN
object-src Плагины ‘none’ (обязательно отключить)
frame-ancestors Кто может встраивать сайт ‘none’

2. Три этапа внедрения: отчёт, сужение, принуждение

Самая частая ошибка — сразу включить заголовок Content-Security-Policy. Так вы мгновенно заблокируете все скрипты, не попавшие в белый список: GA4, онлайн-чат, пиксели — всё отвалится, и бизнес сразу пожалуется.

Правильный подход — сначала использовать заголовок Content-Security-Policy-Report-Only. Браузер только сообщает о нарушениях, не блокирует их; вы собираете логи две недели и добавляете в белый список все реально используемые домены.

Пример сценария 1: добавляем CSP на сайт WordPress, сначала отправляем Report-Only.

Через два дня в отчёте появляются три домена: googletagmanager.com, hotjar.com, youtube.com.

Добавляем их по одному в script-src и frame-src. Через две недели в отчёте остаются единицы в день — переключаемся на принудительный режим.

Этап Заголовок ответа Действие Длительность
Первый шаг Content-Security-Policy-Report-Only Только отчёт, без блокировки 14 дней
Второй шаг То же, постепенно дополняем белый список Нарушений всё меньше Пока не останутся единицы
Третий шаг Content-Security-Policy Настоящая блокировка Долгосрочный
Весь процесс Добавляем report-to или report-uri Собираем отчёты о нарушениях Работает постоянно

Встроенные скрипты — главная ловушка. Темы WordPress и многие плагины пишут <script> прямо в страницу, а CSP по умолчанию блокирует встроенные скрипты. Есть два способа: вынести встроенный скрипт во внешний js-файл или разрешить конкретный фрагмент через хеш sha256, а не открывать unsafe-inline ради удобства.

style-src мягче, чем script-src. Редактор Гутенберга и многие темы выводят встроенные стили, поэтому временно оставить unsafe-inline в style-src не страшно.

А вот в script-src unsafe-inline открывать нельзя ни в коем случае — это главная линия защиты CSP от XSS. К строгости этих двух директив нужно подходить по-разному.

Три. Риски обхода: не дайте CSP стать пустой формальностью

Ошибка в настройке CSP равносильна её отсутствию. Три приведённых ниже варианта полностью обнуляют эту защиту.

Первый — открыть unsafe-inline. Это разрешает выполнение любого встроенного скрипта, включая вредоносный код, внедрённый через XSS, и главная линия защиты CSP рушится. Второй — открыть подстановочный знак *, то есть не ограничивать источники вообще. Третий — забыть про object-src, и тогда старые браузеры всё ещё смогут обойти защиту через Flash или плагины.

Пример второй: ради удобства в script-src прописали ‘unsafe-inline’.

Через два месяца на сайт внедрили встроенный фишинговый скрипт, и CSP его полностью пропустил.

Правильный подход — nonce: для каждого запроса генерируется одноразовое случайное число, и разрешаются только встроенные скрипты с этим числом.

Неправильный вариант Риск Альтернатива
script-src * Загрузится любой сторонний скрипт Перечислить домены белого списка по одному
script-src ‘unsafe-inline’ Внедрённый через XSS скрипт выполнится как обычно Вынести во внешний файл или использовать nonce/хеш
Не указан object-src Старые плагины можно использовать во вред object-src ‘none’
Не настроен frame-ancestors Страницу встраивают во вредоносный iframe frame-ancestors ‘none’

CSP и соответствие требованиям — разные вещи. Согласие на Cookie по GDPR — отдельный механизм, см.Соответствие GDPR для собственного сайта. CSP защищает от внедрения скриптов и не решает вопрос согласия на Cookie. О входе на уровне сервера и правах на файлы см.Усиление безопасности собственного сайта.

Как выбрать между nonce и хешем? Для фиксированных встроенных скриптов используйте хеш, для динамически генерируемых — nonce. Фиксированный фрагмент кода отслеживания в теме WordPress разрешается по хешу; блок скрипта, содержимое которого меняется при каждом запросе, — по nonce.

Место развёртывания тоже имеет значение. Заголовок ответа CSP лучше отдавать на уровне Nginx или CDN, а не через PHP-приложение. Вывод на уровне приложения теряется при сбое PHP, а на уровне CDN работает стабильно.

Место развёртывания Стабильность Когда подходит
Конфигурация Nginx Высокая, работает даже при падении приложения Собственный сервер
Правила CDN Высокая, действует по всему миру Используется Cloudflare и подобные
Вывод через PHP-приложение Низкая, теряется при сбое Временное тестирование

Конечную точку для приёма отчётов тоже нужно создать отдельно. Адрес, на который указывает report-uri, не должен блокироваться самим CSP, иначе отчёты не будут отправляться.

Для собственного сайта можно использовать готовый сервис сбора отчётов или настроить в Nginx отдельный log endpoint для приёма отчётов с записью в отдельный лог-файл, не попадающий в основной лог трафика.

Когда отчётов становится много, их нужно агрегировать. Ежедневно может приходить несколько сотен отчётов — просмотреть каждый по отдельности нереально. Группируйте по нарушенной директиве и заблокированному домену, особое внимание уделяйте новым доменам, появляющимся каждый день.

Есть распространённое заблуждение: кажется, что после включения CSP всё в порядке. На самом деле каждый новый сторонний скрипт, каждое обновление темы могут добавить новый источник нарушений.

Поэтому после перехода в Enforce нельзя отключать report-uri. Это единственный источник сигналов о том, что «новый скрипт забыли добавить в белый список».

Стоит упомянуть и поддержку браузеров. Современные браузеры (Chrome, Edge, Firefox, Safari за последние два года) полностью поддерживают CSP 3. Старый IE можно игнорировать — посетители B2B-сайтов им практически не пользуются.

Ещё одна деталь развёртывания: заголовок CSP нужно отдавать и по http, и по https. Если отдавать только по https, запросы на этапе обращения к origin по http останутся без защиты CSP.

После перехода в Enforce рекомендуется на некоторое время оставить параллельно заголовок Report-Only: он и блокирует, и отправляет отчёты — если что-то упустите, увидите это в отчётах.

CSP — не разовый проект. Каждый новый сторонний скрипт (чат поддержки, чат, видео, реклама) сначала нужно наблюдать в режиме отчётов, убедиться, что он появляется в нарушениях, затем добавить соответствующий домен в белый список и только потом переходить в production.

Добавьте проверку CSP в чек-лист перед запуском нового скрипта: добавляете скрипт — сразу добавляйте белый список. Не ждите, пока после запуска пользователи сообщат, что «виджет не отображается», чтобы вспомнить о CSP.

Критерий для оценки: если сторонний скрипт нельзя вынести во внешний файл и нельзя вычислить его хеш, стоит пересмотреть, нужен ли вообще этот сторонний сервис. Сервисы, зависящие от unsafe-inline, — это технический долг.

После развёртывания проверьте страницы через панель Security в консоли браузера. Просмотрите главную, страницу товара, страницу блога и страницу с формой — убедитесь, что нет красных предупреждений о нарушениях.

Для страниц, не прошедших проверку, найдите соответствующий домен в отчётах, добавьте его в белый список и понаблюдайте ещё день. Повторите этот цикл два-три раза — и всё стабилизируется.

CSP — это не разовая задача по безопасности, которая заканчивается после развёртывания. Она развивается вместе с вашей библиотекой сторонних скриптов. Каждый новый скрипт требует синхронного обновления белого списка — ни в коем случае не пропускайте ни одного нового домена сторонних скриптов.

Источник отчёта Значение Что делать
Нарушение script-src Новый скрипт не добавлен в белый список Добавить домен или вынести во внешний файл
Нарушение img-src Внешняя ссылка на изображение с нового домена Добавить CDN или изменить на относительный путь
Нарушение frame-src Встроен новый iframe Добавить домен видео или убрать
Нарушение base-uri На страницу внедрён тег base Немедленно проверить на XSS

FAQ: частые вопросы

Стоит ли сразу включать CSP в принудительном режиме?
Не надо. Сначала запустите Content-Security-Policy-Report-Only в режиме отчётов на 14 дней: браузер только сообщает о нарушениях, но не блокирует. Добавляйте в белый список реальные домены из отчётов по одному, а когда нарушений останутся единицы, переключитесь на принудительный режим Content-Security-Policy. Если сразу включить принудительный режим, вы положите GA4, онлайн-чат и рекламные пиксели.
Что делать, если CSP блокирует встроенные скрипты в теме WordPress?
Не идите по лёгкому пути и не включайте unsafe-inline. Есть два правильных решения: первое — вынести встроенные скрипты в отдельный js-файл и подключать через src; второе — для встроенных скриптов, которые нужно сохранить, вычислить хеш sha256 и пропустить именно этот хеш в script-src. unsafe-inline позволит выполняться и вредоносным скриптам, внедрённым через XSS, — считайте, что CSP настроен впустую.
Как связаны CSP, HTTPS и HSTS?
Они работают вместе, но не дублируют друг друга. HTTPS отвечает за шифрование передачи, HSTS заставляет браузер использовать только HTTPS, CSP определяет, какие скрипты и ресурсы может загружать браузер. Настроенный HTTPS — это обязательное условие, а CSP поверх HTTPS дополнительно защищает от XSS и несанкционированных сторонних скриптов. Ставить только CSP без HTTPS бессмысленно.
Почему в моих отчётах CSP одни нарушения?
Значит, белый список неполный. В каждом отчёте о нарушении указано, с какого домена пришёл заблокированный скрипт, — добавьте этот домен в соответствующую директиву (script-src, img-src, frame-src и т. д.). Сторонняя аналитика, чаты поддержки и встраиваемые видео — самые частые пропуски. В этом и смысл режима отчётов: сначала собрать всё чисто, потом включать принудительный режим.
Может ли CSP защитить от SQL-инъекций?
Нет. CSP работает на стороне браузера и управляет только загрузкой ресурсов — от SQL-инъекций на сервере он не защищает. С SQL-инъекциями борются подготовленными запросами к базе данных и фильтрацией ввода. CSP в основном защищает от XSS: вредоносный скрипт, внедрённый злоумышленником, блокируется и не выполняется, но сама инъекция уже произошла на сервере.
Нужно ли ещё оставлять report-uri?
Да. Даже после перехода в принудительный режим Enforce нужно оставить report-to или report-uri, чтобы продолжать собирать новые нарушения. Новые сторонние скрипты и встроенный код из обновлений темы сначала появятся в отчётах. Советую подключить отправку отчётов о нарушениях к сервису логов и раз в день просматривать подозрительные домены.

В заключение

Сложность CSP не в написании правил, а в терпеливом прогоне режима отчётов. Две недели наблюдения в обмен на управляемость скриптов в течение нескольких лет — выгодная сделка.

Три шага к внедрению: сначала запустить Report-Only на 14 дней; по отчётам добавлять реальные домены в белый список по одному и заменить unsafe-inline хешами; когда нарушений останутся единицы, переключиться на принудительный режим и оставить report для постоянного мониторинга.

Фраза, которую стоит запомнить: уровень безопасности CSP зависит от того, насколько чистый белый список, — если оставить unsafe-inline и подстановочные знаки, эта стена ничего не стоит.

crater
crater Эксперт Crater

Официальный аккаунт организации · crater Crater

环形山 (Crater) — компания, которая помогает выходить на зарубежные рынки: разработка сайтов на WordPress, Google SEO и комплексный рост в GEO. Мы работаем с умными устройствами, промышленным оборудованием, SaaS и новой энергетикой.

Возможности продуктаБелая книга по методологииОтраслевые отчёты
965篇分享
78статей в базе знаний