Content Security Policy — это заголовок HTTP, который я считаю одним из самых недооценённых инструментов защиты в 2026 году. За 10 лет практики я видел, как сайты с отличным кодом ломались из-за отсутствия одной строчки в конфиге nginx.
Что такое CSP и почему без него сайт уязвим
Content Security Policy — это механизм безопасности браузера, который говорит ему, откуда можно загружать ресурсы: скрипты, стили, шрифты, изображения, фреймы. Грубо говоря, вы составляете белый список источников, и всё остальное браузер просто блокирует. XSS-атака? Инжект стороннего скрипта? Без разрешения в CSP это просто не сработает.
У меня был клиент — интернет-магазин на Bitrix, примерно 3000 уникальных в день. Однажды кто-то через уязвимость в форме обратной связи внедрил скрипт, который тихонько собирал данные карт покупателей и отправлял их на сторонний домен. Сайт работал нормально, никаких ошибок. Обнаружили случайно, через месяц, когда банк начал блокировать транзакции. Если бы стоял правильный CSP — скрипт бы не выполнился. Вот цена этой "необязательной" настройки.
По данным отчёта Google за 2025 год, XSS остаётся в топ-3 уязвимостей веб-приложений. И это несмотря на то, что CSP существует с 2012 года. Просто разработчики либо не знают про него, либо боятся сломать что-то в продакшне. Страх понятный, но решаемый — об этом расскажу ниже.
Важно понимать: CSP не замена SSL-сертификату и не замена firewall. Это отдельный слой защиты. Если интересно, как строить комплексную защиту, у меня есть подробный материал про настройку Firewall для сайта — рекомендую читать в связке с этой статьёй.
Как работает CSP: директивы и значения
CSP передаётся через HTTP-заголовок Content-Security-Policy или через мета-тег в HTML. Я всегда рекомендую заголовок — он надёжнее, потому что мета-тег не защищает от некоторых типов атак и его легче обойти.
Директивы — это правила для разных типов ресурсов. Вот основные, которые я использую в 90% проектов:
- default-src — fallback для всех типов ресурсов, которые не указаны явно
- script-src — откуда можно загружать JavaScript
- style-src — откуда можно загружать CSS
- img-src — источники изображений
- font-src — шрифты (Google Fonts, локальные)
- connect-src — AJAX, WebSocket, fetch-запросы
- frame-src — iframes (YouTube, карты, виджеты)
- object-src — плагины, Flash (да, кто-то ещё использует)
- base-uri — ограничивает значения тега base
- form-action — куда можно отправлять формы
Значения для директив могут быть разными. 'self' — только с текущего домена. 'none' — вообще ничего. Конкретный URL или домен — только оттуда. 'unsafe-inline' — разрешить инлайн-скрипты и стили (плохая идея, но иногда вынужденная мера). 'unsafe-eval' — разрешить eval() в JavaScript. 'nonce-ЗНАЧЕНИЕ' — разрешить конкретный инлайн-блок по одноразовому токену.
'unsafe-inline' в script-src — вы фактически отключаете защиту от XSS. CSP при этом ещё работает для других директив, но основной смысл теряется. Используйте nonce или hash вместо unsafe-inline везде, где это возможно.Настройка CSP в nginx: базовый и продвинутый варианты
На большинстве своих проектов я работаю с nginx, поэтому начну с него. Заголовок добавляется в блок server или location.
Вот базовая конфигурация, с которой я обычно начинаю на новом проекте. Она довольно строгая, но рабочая для простых сайтов без сторонних зависимостей:
server {
listen 443 ssl http2;
server_name example.ru;
# Базовый CSP
add_header Content-Security-Policy "
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self';
frame-src 'none';
object-src 'none';
base-uri 'self';
form-action 'self';
upgrade-insecure-requests;
" always;
# Другие security headers
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}
Но на деле большинство сайтов используют сторонние ресурсы: Google Analytics, Яндекс.Метрику, Google Fonts, YouTube-видео, виджеты обратного звонка, карты. Для реального проекта конфигурация выглядит сложнее. Вот пример для типичного корпоративного сайта на Bitrix с Метрикой и Google Analytics:
add_header Content-Security-Policy "
default-src 'self';
script-src 'self'
'nonce-RANDOM_NONCE_HERE'
https://mc.yandex.ru
https://www.google-analytics.com
https://www.googletagmanager.com
https://api-maps.yandex.ru
https://suggest-maps.yandex.ru;
style-src 'self'
'unsafe-inline'
https://fonts.googleapis.com;
img-src 'self'
data:
blob:
https://mc.yandex.ru
https://www.google-analytics.com
https://www.googletagmanager.com
https://*.maps.yandex.net
https://*.tile.openstreetmap.org;
font-src 'self'
https://fonts.gstatic.com;
connect-src 'self'
https://mc.yandex.ru
https://www.google-analytics.com
https://api-maps.yandex.ru;
frame-src
https://www.youtube.com
https://www.google.com
https://yandex.ru;
object-src 'none';
base-uri 'self';
form-action 'self';
upgrade-insecure-requests;
report-uri /csp-report;
" always;
Обратите внимание на report-uri /csp-report. Это endpoint, куда браузер будет отправлять JSON-отчёты о нарушениях CSP. Очень полезно при отладке и мониторинге. Про настройку мониторинга в целом я писал отдельно — читайте здесь, там есть хорошие инструменты.
Report-Only режим: как внедрять CSP без риска сломать сайт
Вот главный лайфхак, который я использую всегда, когда добавляю CSP на работающий сайт. Существует заголовок Content-Security-Policy-Report-Only. Он работает точно так же, как обычный CSP, но не блокирует ресурсы — только отправляет отчёты о нарушениях.
Схема такая: сначала включаю Report-Only на 2–4 недели, смотрю отчёты, понимаю, что нужно добавить в белый список, и только потом переключаю на боевой CSP. Это позволяет не сломать ничего в продакшне.
# Шаг 1: только мониторинг, ничего не блокируем
add_header Content-Security-Policy-Report-Only "
default-src 'self';
script-src 'self';
style-src 'self';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self';
frame-src 'none';
object-src 'none';
report-uri /csp-report;
" always;
Для приёма отчётов нужен простой PHP-скрипт. Вот минималистичный вариант, который я использую:
После недели работы в Report-Only режиме у меня обычно набирается список из 20–50 источников, которые нужно добавить в белый список. Это нормально — современные сайты очень зависимы от внешних сервисов. Главное — понимать, что именно добавляешь и зачем.
'unsafe-inline' для скриптов, используйте nonce. Это случайный токен, который генерируется на каждый запрос и добавляется в тег script. Браузер выполнит только те скрипты, у которых nonce совпадает с указанным в CSP. Это безопасно, потому что атакующий не знает nonce заранее.CSP для WordPress, Bitrix и Laravel: особенности каждой CMS
WordPress
WordPress — это отдельная боль с точки зрения CSP. Огромное количество плагинов добавляют инлайн-скрипты и стили прямо в HTML, часто без возможности настройки. Редактор Gutenberg сам по себе требует разрешений, которые делают CSP мягче.
Честно говоря, на WordPress я чаще всего иду на компромисс: разрешаю 'unsafe-inline' для style-src (стили), но для script-src стараюсь держать строгий список. Плагин WP Content Security Policy или Headers Security Advanced & HSTS WP помогают управлять заголовками из админки, но я предпочитаю добавлять их через nginx — надёжнее.
Если вы занимаетесь оптимизацией WordPress, то наверняка уже сталкивались с тем, что ускорение WordPress часто требует подключения CDN и внешних ресурсов — всё это нужно прописывать в CSP явно.
Bitrix
На Bitrix ситуация лучше, потому что платформа более предсказуема. Но есть нюансы: компонент карт, виджет онлайн-консультанта из Bitrix24, модуль оплаты — все они тянут внешние ресурсы. Плюс сам Bitrix активно использует inline-скрипты в шаблонах.
На одном из проектов — крупный B2B-портал на Bitrix — я потратил три дня на составление корректного CSP. Особенно мучился с модулем оплаты через CloudPayments: он грузит скрипты с нескольких CDN-доменов, которые ещё и меняются. В итоге пришлось добавить https://*.cloudpayments.ru и https://*.cloudstatic.ru. Если занимаетесь поддержкой Bitrix-проектов — обратите на это внимание.
Если хотите заказать профессиональную настройку безопасности для вашего Bitrix-сайта, посмотрите на услугу поддержки Битрикс — там в том числе настраиваем security headers.
Laravel
Laravel — самое удобное окружение для работы с CSP. Есть отличный пакет spatie/laravel-csp, который позволяет генерировать заголовки программно, с поддержкой nonce прямо в шаблонах Blade.
addDirective(Directive::DEFAULT, Keyword::SELF)
->addDirective(Directive::SCRIPT, [
Keyword::SELF,
Keyword::NONCE,
'https://www.googletagmanager.com',
'https://mc.yandex.ru',
])
->addDirective(Directive::STYLE, [
Keyword::SELF,
Keyword::UNSAFE_INLINE,
'https://fonts.googleapis.com',
])
->addDirective(Directive::FONT, [
Keyword::SELF,
'https://fonts.gstatic.com',
])
->addDirective(Directive::IMG, [
Keyword::SELF,
'data:',
'https:',
])
->addDirective(Directive::OBJECT, Keyword::NONE)
->addDirective(Directive::BASE, Keyword::SELF);
}
}
В Blade-шаблонах можно использовать директиву @cspNonce прямо в теге script — пакет сам подставит nonce и добавит его в заголовок. Это очень элегантно и безопасно.
CSP и аналитика: Google Analytics, Яндекс.Метрика, пиксели
Это самая частая причина, по которой люди боятся включать CSP. Аналитика ломается, пиксели не срабатывают, маркетологи в панике. Но это решаемо.
Для Google Analytics 4 (gtag.js) нужно добавить:
script-src:https://www.googletagmanager.com,https://www.google-analytics.comimg-src:https://www.google-analytics.com,https://www.googletagmanager.comconnect-src:https://www.google-analytics.com,https://analytics.google.com,https://region1.analytics.google.com
Для Яндекс.Метрики:
script-src:https://mc.yandex.ruimg-src:https://mc.yandex.ruconnect-src:https://mc.yandex.ru
Facebook Pixel добавляет ещё несколько доменов: https://connect.facebook.net, https://www.facebook.com. ВКонтакте-пиксель — https://vk.com.
По опыту — если вы подключаете GTM (Google Tag Manager), то через него могут загружаться любые скрипты, и вы теряете контроль над CSP. Это принципиальная проблема: GTM по своей природе конфликтует со строгим CSP. Решение — либо жёстко контролировать, что загружается через GTM, либо выносить критические теги напрямую в код.
Дополнительные security headers, которые работают в связке с CSP
CSP — мощный инструмент, но он работает лучше в связке с другими заголовками безопасности. Я всегда настраиваю их вместе.
Strict-Transport-Security (HSTS) — заставляет браузер всегда использовать HTTPS для вашего домена. Без этого атакующий может провести downgrade-атаку и перехватить трафик. Подробнее про переход на HTTPS я писал в чек-листе по HTTPS.
X-Frame-Options — защита от clickjacking. Хотя frame-ancestors в CSP делает то же самое, X-Frame-Options стоит оставить для совместимости со старыми браузерами.
X-Content-Type-Options: nosniff — запрещает браузеру угадывать MIME-тип файла. Без этого атакующий может загрузить HTML-файл под видом картинки и выполнить скрипт.
Permissions-Policy (бывший Feature-Policy) — ограничивает доступ к API браузера: камера, микрофон, геолокация, платёжные данные. Для большинства сайтов я использую такую строку:
add_header Permissions-Policy "
camera=(),
microphone=(),
geolocation=(self),
payment=(),
usb=(),
magnetometer=(),
gyroscope=(),
accelerometer=()
" always;
Referrer-Policy — контролирует, какой Referer передаётся при переходе на другой сайт. Я обычно использую strict-origin-when-cross-origin: передаём только домен (без пути) при переходе на другой сайт, и полный URL при переходе внутри сайта.
Проверить все заголовки можно на сервисе securityheaders.com. Он выставляет оценку от F до A+. Цель — минимум A. На проектах, которые я настраиваю, обычно A или A+.
Типичные ошибки при настройке CSP и как их избежать
За годы практики я собрал список граблей, на которые наступают все, кто впервые настраивает CSP.
Ошибка 1: Разрешить всё через wildcard. Встречаю конфиги вида script-src *. Это бессмысленно — вы разрешаете скрипты откуда угодно, CSP не работает. Wildcard можно использовать для img-src или font-src, но для script-src это катастрофа.
Ошибка 2: Забыть про data: URI. Некоторые библиотеки (например, старые версии Bootstrap) используют data: URI для шрифтов или изображений. Если не добавить data: в font-src или img-src — сломается вёрстка.
Ошибка 3: Не тестировать в разных браузерах. Chrome и Firefox реализуют CSP немного по-разному. То, что работает в Chrome, может блокироваться в Firefox. Тестируйте в обоих. Safari отдельная история — там свои нюансы с Service Workers и CSP.
Ошибка 4: Игнорировать inline event handlers. Если в вашем HTML есть onclick="..." или onload="..." — они блокируются строгим CSP. Нужно либо выносить код в отдельные JS-файлы, либо использовать 'unsafe-hashes' с хешем конкретного обработчика. Лучше — выносить в файлы.
Ошибка 5: Не обновлять CSP при добавлении новых интеграций. Подключили новый виджет чата, добавили платёжную систему, поставили новый плагин — и сайт тихо сломался в каком-то браузере. Всегда проверяйте консоль после добавления новых сервисов. Хорошая практика — включать report-uri перманентно, не только при первоначальной настройке.
Если вы хотите, чтобы всё это настроили профессионально и без риска что-то сломать — посмотрите на услугу доработки сайта. Настройка security headers входит в базовый аудит безопасности.
Проверка CSP и постоянный мониторинг
После настройки CSP работа не заканчивается. Нужно регулярно проверять, что ничего не сломалось и нет новых нарушений.
Инструменты для проверки, которые я использую постоянно:
- securityheaders.com — общая оценка всех security headers
- csp-evaluator.withgoogle.com — анализ CSP от Google, показывает потенциальные слабые места
- report-uri.com — коммерческий сервис для сбора и анализа CSP-отчётов с красивым дашбордом
- Консоль браузера (F12) — самый быстрый способ увидеть нарушения прямо здесь и сейчас
Я рекомендую настроить мониторинг нарушений CSP так же, как вы мониторите ошибки приложения. Если вдруг пошёл поток новых нарушений с незнакомых доменов — это сигнал тревоги. Возможно, кто-то пытается инжектировать скрипты, или один из ваших подрядчиков тихо добавил сторонний трекер без согласования.
Раз в квартал я делаю ревью CSP на своих проектах: проверяю, все ли домены в белом списке ещё актуальны, не появились ли новые зависимости, нет ли избыточных разрешений. Это занимает час, но даёт уверенность, что политика не превратилась в решето за счёт накопленных исключений.
Кстати, если говорить о комплексной безопасности — обязательно почитайте про защиту сайта от взлома. CSP — важная часть, но там много других аспектов, которые работают в связке.
Итого: CSP в 2026 году — это не опциональная фича для параноиков, а базовый гигиенический минимум для любого сайта, который работает с данными пользователей. Настройка занимает от нескольких часов до нескольких дней в зависимости от сложности проекта. Начните с Report-Only режима, соберите данные, постепенно ужесточайте политику. Сломать продакшн при таком подходе практически невозможно. А вот защиту от XSS и data-утечек вы получите реальную.
Хотите защитить сайт с помощью CSP?
Наши специалисты настроят Content Security Policy под ваш проект и обеспечат надёжную защиту от XSS-атак и других угроз.