CSP: Политика безопасности контента
В этой статье мы объясним, что такое политика безопасности контента, и опишем как использовать CSP для защиты от некоторых распространённых атак.
Что такое CSP (Content Security Policy)
CSP — это механизм безопасности браузера, цель которого смягчение последствий XSS и некоторых других атак. Он работает ограничивая ресурсы (такие, как сценарии и изображения), которые может загружать страница, и ограничивая возможности обрамления страницы другими страницами.
Для включения CSP, ответ должен включать HTTP ответ с заголовком Content-Security-Policy со значением содержащим политику. Сама политика состоит из одной или нескольких директив, разделённых точкой с запятой.
Защита от XSS атак с помощью CSP
Следующая директива позволит загружать скрипты только из того же источника, что и сама страница:
script-src 'self'
Следующая директива разрешает загрузку скриптов только из определённого домена:
script-src https://scripts.normal-website.com
Следует соблюдать осторожность при разрешении сценариев из внешних доменов. Если у злоумышленника есть какой-либо способ контролировать контент, обслуживаемый из внешнего домена, он может провести атаку. Например, сетям доставки контента (CDN), которые не использую отдельные адреса для каждого клиента, такие как ajax.googleapis.com , нельзя доверять, поскольку третьи стороны могут получить контент на свои домены.
Помимо внесения в белый список определённых доменов, политика безопасности контента (CSP) также предоставляет два других способа указания доверенных ресурсов: одноразовые номера и хэши:
- Директива CSP может указывать одноразовый номер (случайное значение), и это же значение должно использоваться в теге, загружающем скрипт. Если значения не совпадают, скрипт не будет выполняться. Для эффективного контроля, одноразовый номер должен безопасно генерироваться при каждой загрузке страницы и не должен угадываться злоумышленником.
- Директива CSP может указывать хэш содержимого доверенного скрипта. Если хэш фактического скрипта не соответствует значению указанному в директиве, то он не будет выполняться. Если содержимое скрипта когда-нибудь изменится, вам конечно же, потребуется обновить хэш-значение, указанное в директиве.
CSP довольно часто блокирует такие ресурсы, как script . Однако многие CSP разрешают запросы изображений. Это означает, что вы можете использовать элементы img для выполнения запросов к внешним серверам, например для раскрытия токена CSRF.
Some browsers, such as Chrome, have built-in dangling markup mitigation that will block requests containing certain characters, such as raw, unencoded new lines or angle brackets.
Некоторые браузеры, такие как Chrome, имеют встроенное средство устранения висячей разметки, которое блокирует запросы, содержащие определённые символы, такие как необработанные, незакодированные новые строки или угловые скобки.
Некоторые политики более строгие и запрещают все формы внешних запросов. Однако всё ещё можно обойти эти ограничения, вызвав некоторое взаимодействие с пользователем. Для обхода этой формы политики, нужно внедрить HTML элемент, который при клике будет сохранять и отправлять всё, что содержится во внедрённом элементе, на внешний сервер.
Противодействие атакам с висячей разметкой с помощью CSP
Следующая директива позволит загружать изображения только из того же источника, что и сама страница:
img-src 'self'
Следующая директива позволяет загрузку изображений только из определённого домена:
img-src https://images.normal-website.com
Обратите внимание, что эти политики предотвратят некоторые эксплойты с висячей разметкой, потому что простой способ сбора данных без взаимодействия с пользователем — использование тега img . Однако это не защитит от других эксплойтов, таких, как внедрение тега ссылки с разорванным атрибутом href .
Обход CSP с внедрением политик
Вы можете столкнуться с веб-сайтом, отражающим ввод в фактическую политику, скорее всего, в директиве report-uri . Если сайт отражает параметр, которым вы можете управлять, вы можете ввести точку с запятой, чтобы добавить собственные директивы CSP. Обычно директива report-uri завершает список директив. Это означает, что вам нужно перезаписать существующие директивы, для использования этой уязвимости и обхода политики.
Обычно невозможно перезаписать существующую директиву script-src . Однако недавно в Chrome появилась директива script-src-elem , которая позволяет управлять элементами скрипта, но не событиями. Важно отметить, что эта новая директива позволяет перезаписывать существующие директивы script-src .
Защита от кликджекинга с помощью CSP
Следующая директива позволит размещать страницу в фрейм только другими страницами из того же источника:
frame-ancestors 'self'
Следующая директива полностью предотвратит размещение страницы в фрейме:
frame-ancestors 'none'
Использование политики безопасности контента для предотвращения кликджекинга более гибко, чем использование заголовка X-Frame-Options , поскольку вы можете указать несколько доменов и использовать подстановочные знаки. Например:
frame-ancestors 'self' https://normal-website.com https://*.robust-website.com
CSP также проверяет каждый фрейм в иерархии родительских фреймов, тогда как X-Frame-Options проверяет только фрейм верхнего уровня.
Рекомендуется использовать CSP для защиты от кликджекинга. Вы также можете комбинировать это с заголовком X-Frame-Options , для обеспечения защиты в старых браузерах, которые не поддерживают CSP, таких, как Internet Explorer.
Дополнительные материалы
- XSS: Межсайтовые сценарии
- SOP: Что такое Same-origin policy
- CSRF: Подделка межсайтовых запросов
- CSRF: Как предотвратить уязвимость
Подробная настройка Content Security Policy (CSP)
Content Security Policy (CSP) — это механизм безопасности веб-приложений, который используется для сокращения рисков, связанных с атаками, такими как внедрение скриптов (XSS) и выполнение нежелательного кода (инъекция). CSP позволяет веб-разработчикам указывать браузерам, из каких источников разрешено загружать ресурсы, такие как скрипты, стили, изображения, шрифты и другие элементы.
С помощью CSP можно определить набор допустимых источников для каждого типа ресурса, а браузеры будут блокировать попытки загрузки ресурсов из недопустимых источников. Например, вы можете настроить CSP таким образом, чтобы разрешить загрузку скриптов только из определенного домена или разрешить загрузку стилей только из локального файла.
Это помогает предотвратить атаки, основанные на выполнении вредоносного кода из внешних источников, а также уменьшает риски, связанные с подделкой источников, перехватом данных и другими видами атак. CSP является эффективным инструментом для укрепления безопасности веб-приложений и защиты пользователей от различных видов уязвимостей.
Что дальше?
Окей, мы разобрались с тем что такое CSP, но с чего начать, а самое главное как мы будем тестировать, работает этот механизм или нет?
Я попробую пошагово рассказать свой опыт настройки этого механизма, и что я для этого использовал.
Мое приложение использует стек:
- React.js
- Typescript
- Material UI
- Styled-components
Так же есть прямой доступ к конфигу webpack с конфигурацией сборки.
При локальной разработке у меня используется сервер на node.js «start»: «node scripts/start.js»
Но для нашего тестирования CSP нам потребуется настраивать заголовки на сервере, и самым популярным решением является поднять локально сервер на nginx вместо нашего скрипта.
Nginx Шаг 1
В зависимости от вашей os, команды по установке и запуску nginx могут немного отличаться. Так как я использую mac os, я устанавливал nginx через brew (https://brew.sh)
После того как мы установили nginx, у нас есть доступ к базовой конфигурации.
Для Mac Os nginx лежит по адресу /usr/local/etc/nginx либо /opt/homebrew/etc/nginx/nginx.conf базовый конфиг nginx.conf
Первое что я хотел сделать — чтобы nginx, для начала, просто отдавал мою статику.
Поэтому мой базовый конфиг для локальной работы выглядел так:
worker_processes 1; events < worker_connections 1024; >http < include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server < listen 3000; server_name localhost; location / < root html; index index.html index.htm; >error_page 403 404 500 502 503 504 /index.html; location = / < root html; >> include servers/*; >
В данном случае наш сервер должен отдавать статику по адресу http://localhost:3000/
Теперь можем запустить nginx командой sudo nginx
Если мы перейдем по адресу http://localhost:3000/ то должны увидеть что то вроде этого:

Nginx Шаг 2
Теперь нам нужно сбилдить нашу статику и положить ее в usr/local/var/www или /opt/homebrew/var/www
В моем проекте это делается командой yarn run build
На выходе получаем папку static , берем ее внутренности и перемещаем в usr/local/var/www
После этого перезапускаем nginx командой sudo nginx -s stop && sudo nginx
Теперь на http://localhost:3000 мы должны увидеть наше приложение
P.S Этот шаг нужно повторять каждый раз, когда вы обновляете код своего приложения, если хотите проверить результат
Nginx Шаг 3
Далее будет не лишним настроить протокол https , чтобы наш сайт открывался по https://localhost:3000
Для этого нам нужно сгенерировать ssl сертификат. В терминале переходим в папку, в которую сгенерируем 2 новых файла. Лично мне удобно открыть WebStorm со своим проектом, и использовать встроенный терминал.
Вводим в терминал команду openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
После выполнения команды жмем enter чтобы скипать шаги до шага Common name .
На этом моменте для Common name вводим 127.0.0.1
чтобы установить сертификат в корневом хранилище сертификатов вашей ОС или в браузере, чтобы он был надежным.
В корне проекта появиться два файла cert.pem key.pem
Далее нам нужно перенести эти два файла в папку /usr/local/etc/ca-certificates или /opt/homebrew/etc/ca-certificates
И в конфиге nginx добавить следующие поля ниже поля server_name
P.S Опять же путь до файлов может отличаться
ssl_certificate /usr/local/etc/ca-certificates/cert.pem; ssl_certificate_key /usr/local/etc/ca-certificates/key.pem;
Так же требуется добавить приписку ssl для поля listen
Получиться примерно так:
worker_processes 1; events < worker_connections 1024; >http < include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server < listen 3000 ssl; server_name localhost; ssl_certificate /usr/local/etc/ca-certificates/cert.pem; ssl_certificate_key /usr/local/etc/ca-certificates/key.pem; location / < root html; index index.html index.htm; >error_page 403 404 500 502 503 504 /index.html; location = / < root html; >> include servers/*; >
Перезапускаем nginx командой sudo nginx -s stop && sudo nginx
Теперь сайт должен открываться на https://localhost:3000
Nginx Шаг 4
По идее сейчас все готово для того чтобы внедрять политику CSP.
Для того чтобы ее настраивать нам нужно понимать как она работает.
А работает она с помощью заголовка Content-Security-Policy, мы будем описывать правила, которые браузер должен будет соблюдать, а если какое-либо действие пользователя будет не по правилам — браузер откажется это выполнять.
Настройка начинается с того, что сначала мы запрещаем все, а потом начинаем добавлять исключения.
Начнем с правила script-src оно определяет допустимые источники JavaScript.
В nginx добавляем заголовок со следующим значением:
add_header Content-Security-Policy «script-src ‘self’ ‘unsafe-inline'»;
В коде это выглядит так:
worker_processes 1; events < worker_connections 1024; >http < include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server < listen 3000 ssl; server_name localhost; ssl_certificate /usr/local/etc/ca-certificates/cert.pem; ssl_certificate_key /usr/local/etc/ca-certificates/key.pem; location / < add_header Content-Security-Policy "script-src 'self' 'unsafe-inline'"; root html; index index.html index.htm; >error_page 403 404 500 502 503 504 /index.html; location = / < root html; >> include servers/*; >
Перезапускаем nginx командой sudo nginx -s stop && sudo nginx
И перезагружаем наш сайт. Если у вас есть сторонние источники, например метрика, рекапча и тд, то вы увидите ошибку в консоли подобную этой и белую страницу

Это говорит нам о том, что у нас есть источник который не описан в политике csp, и поэтому браузер его не загружает, давайте добавим источник в список разрешенных.
add_header Content-Security-Policy «script-src ‘self’ ‘unsafe-inline’ https://www.google.com/recaptcha/»;
Перезапускаем nginx командой sudo nginx -s stop && sudo nginx
Обновляем страницу и видим что ошибка пропала. По такой же схеме, у вас может быть много ошибок, и далее вам нужно просто внести ресурсы в белый список.
Nginx Шаг 5
Казалось бы мы настроили первое правило script-src — но нет. В нашем правиле есть ключевое слово ‘unsafe-inline’ который означает что мы разрешаем использование всех встроенных скриптов. Использование этого ключевого слова считается небезопасным.
Давайте попробуем удалить это ключевое слово, и посмотреть что будет:

Высокая вероятность того что вы получите такую ошибку выше, и скорее всего подобных ошибок будет +- около 10, а то и больше, в зависимости от того сколько встроенных скриптов вы используете.
Так что же тут случилось, откуда тут вообще взялась эта ошибка?
Так как мы отказались от ключевого слово ‘unsafe-inline’ — то мы отказались и от использования встроенных скриптов. Теперь же нам нужно научиться “помечать” какие встроенные скрипты являются безопасными.
Хорошей практикой считается добавлять для наших встроенных скриптов атрибут nonce , и указывать в нем динамический хеш, тем самым валидируя скрипты. Этот динамический хеш будет генерироваться нашим сервером nginx. Таким образом, если встроенный скрипт не будет иметь хеш, или он будет не совпадать — то nginx откажется его подгружать, тем самым мы себя обезопасим от разных атак.
Настройка хеша, включает в себя изменение кода как со стороны frontend так и со стороны nginx.
Для начала начнем со стороны frontend. В целом, описанные ниже шаги можно применить на большинство фреймворков и библиотек, так как основные настройки делаются в корневом index.js и в webpack конфиге.
Настройка frontend приложения
Сама настройка заключается в том, что мы должны добавить атрибут nonce=»CSP_NONCE» ко всем встроенным скриптам. Само значение CSP_NONCE на самом деле может быть любым. Это значение нужно для того, чтобы бы в будущем наш nginx находил это значение в статических файлах js, html и заменял на динамический хеш.
Начнем с простого, зайдем в наш index.html файл, и добавим этот атрибут ко всем подключаемым скриптам, стилям и шрифтам. К примеру у меня есть следующие скрипт и шрифт, в которые я добавляю атрибут:
Добавляем в наш index.html следующую запись
На эту запись могут ориентироваться некоторые UI библиотеки, например Material UI
Так же добавляем в index.html следующий скрипт
Тут мы глобально задаем новую переменную webpack_nonce на которую будут ориентироваться некоторые скрипты и библиотеки.
Далее открываем наш конфиг для webpack, и находим массив с плагинами plugins: []
Как правило в этом месте описаны настройки для различных плагинов eslint, html.
Нам нужно установить плагин html-webpack-inject-attributes-plugin
Подключить его вверху конфига:
И добавить следующую запись последним элементов массива plugins
plugins: [ // . any plugins new HtmlWebpackInjectPlugin(< nonce: "**CSP_NONCE**", >), ]
Так как использую react, у меня есть скрипт scripts/build.js , который запускается командой yarn run build , этот файл используется для сборки приложения в production
У вас может быть точно такой же файл, либо какой то другой аналогичный скрипт. В него нужно добавить следующую запись:
process.env.INLINE_RUNTIME_CHUNK = "false";
Открываем наш корневой index.js, и в самый вверх добавляем запись:
// eslint-disable-next-line no-undef __webpack_nonce__ = window.__webpack_nonce__;
По идее все эти шаги должны привести к тому, что каждый ваш встроенный скрипт, стиль, включая динамические, будет иметь атрибут nonce :
Nginx Шаг 6
После того как мы добавили nonce ко всем встроенным скриптам и стилям, нужно расширить конфигурацию nginx, и добавить:
Два поля в раздел location :
sub_filter **CSP_NONCE** $request_id;
Поле sub_filter_once указывает следует ли искать каждую строку для замены один раз.
Поле sub_filter задает строку для замены и строку замены.
То есть мы находим строку **CSP_NONCE** в нашей статике, и заменяем ее на значение переменной $request_id
Из заголовка удаляем строку unsafe-inline которая разрешала нам использование всех встроенных скриптов, и добавляем ‘nonce-$request_id’ и ‘strict-dynamic’
‘strict-dynamic’ — указывает, что доверие, явно предоставляемое скрипту, присутствующему в разметке, путем сопровождения его одноразовым значением или хэшем, должно распространяться на все скрипты, загруженные этим корневым скриптом.
Теперь наш каждый встроенный скрипт будет помечен динамических хешем, тем самым подтверждая что это наш скрипт и его можно загружать.
worker_processes 1; events < worker_connections 1024; >http < include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server < listen 3000 ssl; server_name localhost; ssl_certificate /usr/local/etc/ca-certificates/cert.pem; ssl_certificate_key /usr/local/etc/ca-certificates/key.pem; location / < add_header Content-Security-Policy "script-src 'self' 'nonce-$request_id' 'strict-dynamic' https://www.google.com/recaptcha/"; sub_filter_once off; sub_filter **CSP_NONCE** $request_id; root html; index index.html index.htm; >error_page 403 404 500 502 503 504 /index.html; location = / < root html; >> include servers/*; >
После перезапуска nginx, у нас должны пропасть ошибки из консоли.
Nginx Шаг 7
Теперь продолжим добавлять различные директивы, например style-src со значением self
Перезапускаем nginx, обновляем страницу, и смотрим ошибки в консоли.
Скорее всего самые первые ошибки будут указывать на ресурсы, которых нет в white list.
Refused to load the stylesheet » because it violates the following Content Security Policy directive: «style-src ‘self'». Note that ‘style-src-elem’ was not explicitly set, so ‘style-src’ is used as a fallback.
Добавляем ресурс и nonce:
style-src “’self’ ‘nonce-$request_id’ https://*.example.com”
Так же для удобства, выносим каждую директиву в переменную, и получаем:
worker_processes 1; events < worker_connections 1024; >http < include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server < listen 3000 ssl; server_name localhost; ssl_certificate /opt/homebrew/etc/ca-certificates/cert.pem; ssl_certificate_key /opt/homebrew/etc/ca-certificates/key.pem; set $CSP_SCRIPT_SRC "'self' 'nonce-$request_id' 'strict-dynamic' https://www.google.com/recaptcha/"; set $CSP_STYLE_SRC "'self' 'nonce-$request_id' https://*.example.com"; location / < add_header Content-Security-Policy "script-src $CSP_SCRIPT_SRC; style-src $CSP_STYLE_SRC"; sub_filter_once off; sub_filter **CSP_NONCE** $request_id; root html; index index.html index.htm; >error_page 500 502 503 504 /index.html; location = / < root html; >> include servers/*; >
По такому принципу, вы можете добавить остальные директивы.
У вас получиться примерно так:
#user nobody; worker_processes 1; events < worker_connections 1024; >http < include mime.types; default_type application/octet-stream; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server < listen 3000 ssl; server_name localhost; # location of ssl certificate ssl_certificate /usr/local/etc/ca-certificates/cert.pem; # location of ssl key ssl_certificate_key /usr/local/etc/ca-certificates/key.pem; set $CSP_SCRIPT_SRC "'self' 'nonce-$request_id' 'strict-dynamic' https://www.google.com/recaptcha/"; set $CSP_STYLE_SRC "'self' 'nonce-$request_id' https://*.example.com"; set $CSP_CONNECT_SRC "'self' https://*.example.com"; set $CSP_FONT_SRC "'self' https://fonts.gstatic.com/"; set $CSP_IMG_SRC "'self'"; set $CSP_OBJECT_SRC "'self'"; set $CSP_BASE_URI "'self'"; set $CSP_FRAME_SRC "'self' https://www.google.com https://mc.yandex.ru"; set $CSP_MANIFEST_SRC "'self'"; set $CSP_MEDIA_SRC "'self'"; set $CSP_WORKER_SRC "'self'"; set $CSP_FRAME_ANCESTORS "'self'"; location / < add_header Content-Security-Policy "default-src 'none'; script-src $CSP_SCRIPT_SRC; style-src $CSP_STYLE_SRC; connect-src $CSP_CONNECT_SRC; font-src $CSP_FONT_SRC; img-src $CSP_IMG_SRC; object-src $CSP_OBJECT_SRC; base-uri $CSP_BASE_URI; frame-src $CSP_FRAME_SRC; manifest-src $CSP_MANIFEST_SRC; media-src $CSP_MEDIA_SRC; worker-src $CSP_WORKER_SRC; frame-ancestors $CSP_FRAME_ANCESTORS;"; sub_filter_once off; sub_filter **CSP_NONCE** $request_id; root html; index index.html index.htm; >error_page 403 404 500 502 503 504 /index.html; location = / < root html; >> include servers/*; >
В целом на этом моменте можно считать настройку CSP завершенной.
Как использовать Менеджер тегов с Content Security Policy
Оптимизируйте свои подборки Сохраняйте и классифицируйте контент в соответствии со своими настройками.
Content Security Policy (CSP) – это широко поддерживаемый стандарт веб-безопасности. Он позволяет разработчикам выбирать, какие ресурсы могут загружаться приложениями, и тем самым предотвращать определенные типы атак с внедрением кода. В этом руководстве объясняется, как использовать Google Менеджер тегов на сайте с CSP.
Примечание. Чтобы убедиться, что CSP работает должным образом, используйте директивы report-uri и/или report-to для получения отчетов о нарушениях.
Настройка тега-контейнера для работы с CSP
Чтобы использовать Google Менеджер тегов на странице с CSP, разрешите выполнение кода-контейнера Менеджера тегов, который является встроенным кодом JavaScript и внедряет скрипт gtm.js . Это можно сделать несколькими способами, например с помощью однократно используемого числа (nonce) или хеша. Рекомендуем использовать значение nonce – случайное число, которое сервер генерирует отдельно для каждого ответа. Укажите значение nonce в директиве CSP script-src :
Content-Security-Policy: script-src 'nonce-'; img-src www.googletagmanager.com
Затем используйте версию встроенного кода Google Менеджера тегов с поддержкой числа nonce и укажите то же значение для атрибута nonce во встроенном элементе скрипта.
Тогда число nonce будут содержать все скрипты, добавляемые Менеджером тегов на страницу.
Разрешить выполнение встроенного скрипта можно и другими способами, например добавив хеш встроенного скрипта в CSP. Подробная информация приведена в документации по CSP.
Если эти рекомендуемые способы не подходят, вы можете разрешить выполнение встроенного скрипта Менеджера тегов, добавив директиву ‘unsafe-inline’ в раздел script-src CSP.
Использовать директиву ‘unsafe-inline’ не рекомендуется, поэтому добавляя ее в CSP, необходимо оценивать риски для безопасности.
Чтобы воспользоваться этим способом, добавьте в CSP такие директивы:
script-src: 'unsafe-inline' https://www.googletagmanager.com img-src: www.googletagmanager.com
Примечание. Некоторые теги загружают контент из других источников или отправляют им запросы, поэтому для их правильной работы требуются дополнительные директивы CSP.
Пользовательские переменные JavaScript
Пользовательские переменные JavaScript будут иметь значение undefined , если в разделе script-src CSP не указана директива ‘unsafe-eval’ . Это связано с особенностями реализации таких переменных.
Чтобы избежать риска уязвимости, используйте директиву ‘unsafe-eval’, только когда это действительно необходимо.
script-src: 'unsafe-eval'
Примечание. Пользовательские шаблоны – это предпочтительная альтернатива пользовательским переменным JavaScript. С их помощью можно создавать пользовательские теги и переменные, для которых не требуется директива ‘unsafe-eval’ .
Режим предварительного просмотра
Чтобы использовать режим предварительного просмотра Google Менеджера тегов, необходимо включить в правила защиты контента следующие директивы:
script-src: https://tagmanager.google.com style-src: https://tagmanager.google.com https://fonts.googleapis.com img-src: https://ssl.gstatic.com https://www.gstatic.com font-src: https://fonts.gstatic.com data:
Примечание. Если для показа страницы используется незащищенное подключение, директива script-src должна включать незащищенный URL http://tagmanager.google.com .
Google Аналитика 4 (Google Аналитика)
Чтобы использовать тег Google Аналитики 4 (Google Аналитики), необходимо включить в CSP следующие директивы:
script-src: https://*.googletagmanager.com img-src: https://*.google-analytics.com https://*.googletagmanager.com connect-src: https://*.google-analytics.com https://*.analytics.google.com https://*.googletagmanager.com
Для развертывания Google Аналитики 4 (Google Аналитики) с использованием сигналов Google необходимо включить в CSP следующие директивы:
script-src: https://*.googletagmanager.com img-src: https://*.google-analytics.com https://*.analytics.google.com https://*.googletagmanager.com https://*.g.doubleclick.net https://*.google.com https://*.google. connect-src: https://*.google-analytics.com https://*.analytics.google.com https://*.googletagmanager.com https://*.g.doubleclick.net https://*.google.com https://*.google.
Примечание. Каждый домен Google верхнего уровня необходимо указывать отдельно, поскольку синтаксис CSP запрещает использование подстановочных знаков в правой части имени хоста. Полный список поддерживаемых доменов Google верхнего уровня приведен на странице https://www.google.com/supported_domains.
Universal Analytics (Google Аналитика)
Чтобы использовать тег Universal Analytics (Google Аналитики), необходимо включить в CSP следующие директивы:
script-src: https://www.google-analytics.com https://ssl.google-analytics.com img-src: https://www.google-analytics.com connect-src: https://www.google-analytics.com
Примечание. Если для показа страницы используется незащищенное подключение, директива script-src не должна включать https://ssl.google-analytics.com .
Конверсии Google Рекламы
Чтобы использовать тег конверсии Google Рекламы, необходимо включить в CSP следующие директивы:
Для защищенных подключений:
script-src: https://www.googleadservices.com https://www.google.com img-src: https://googleads.g.doubleclick.net https://www.google.com
Для незащищенных подключений:
script-src: www.googleadservices.com www.google.com img-src: googleads.g.doubleclick.net www.google.com
Ремаркетинг в Google Рекламе
Чтобы использовать тег ремаркетинга Google Рекламы, необходимо включить в CSP следующие директивы:
Для защищенных подключений:
script-src: https://www.googleadservices.com https://googleads.g.doubleclick.net https://www.google.com img-src: https://www.google.com frame-src: https://bid.g.doubleclick.net
Для незащищенных подключений:
script-src: www.googleadservices.com googleads.g.doubleclick.net www.google.com img-src: www.google.com frame-src: bid.g.doubleclick.net
Floodlight
Пользователи Floodlight могут включить CSP с помощью указанных ниже конфигураций. Вместо значения необходимо указать определенный идентификатор рекламодателя Floodlight или символ звездочки ( * ), обозначающий любой идентификатор.
Для всех пользователей:
img-src: https://.fls.doubleclick.net
Для пикселей отслеживания собственных скриптов в Менеджере тегов:
frame-src: https://.fls.doubleclick.net
Для тегов изображений:
img-src: https://ad.doubleclick.net
img-src: https://ade.googlesyndication.com
Отправить отзыв
Если не указано иное, контент на этой странице предоставляется по лицензии Creative Commons «С указанием авторства 4.0», а примеры кода – по лицензии Apache 2.0. Подробнее об этом написано в правилах сайта. Java – это зарегистрированный товарный знак корпорации Oracle и ее аффилированных лиц.
Последнее обновление: 2023-10-31 UTC.
Content Security Policy (CSP)
Content Security Policy (CSP) — это дополнительный уровень безопасности, позволяющий распознавать и устранять определённые типы атак, таких как Cross Site Scripting (XSS (en-US)) и атаки внедрения данных. Спектр применения этих атак включает, но не ограничивается кражей данных, подменой страниц и распространением зловредного ПО.
CSP разрабатывался с возможностью полной обратной совместимости (за исключением CSP version 2, в которой были намеренно определены некоторые противоречия блокирующие обратную совместимость; с деталями можно ознакомиться здесь, в пункте 1.1). Браузеры, которые не поддерживают CSP, все ещё могут работать с серверами, которые поддерживают CSP, и наоборот: браузеры, в которых поддержка CSP отсутствует, будут её игнорировать, продолжая работу в соответствии со стандартными правилами ограничения домена для загрузки контента. В случае, если сайт не предоставляет CSP-заголовки, браузеры, в свою очередь, будут использовать стандартные правила ограничения домена.
Для того чтобы включить CSP, необходимо настроить сервер так, чтобы в ответах он использовал HTTP-заголовок Content-Security-Policy (en-US) (в различных примерах и документации можно встретить вариант заголовка X-Content-Security-Policy . Он является устаревшим и определять его не нужно).
Угрозы
Межсайтовый скриптинг
Основная цель создания CSP заключается в устранении XSS-атак и сборе данных об их попытках. XSS-атаки используют доверие браузера к контенту, полученному с сервера. Зловредные скрипты исполняются в браузере жертвы, поскольку браузер доверяет источнику, даже когда скрипт поставляется не оттуда, откуда кажется.
CSP даёт возможность администраторам серверов снизить или полностью устранить вектора, по которым злоумышленники могут провести XSS, с помощью определения доменов, которые браузер клиента должен считать доверенными источниками исполняемых скриптов. В таком случае, браузер, совместимый с CSP, будет исполнять только те скрипты, которые были получены из списка разрешённых источников, и игнорировать прочие (в т.ч. встраиваемые скрипты и обработчики событий, указанные непосредственно в HTML-атрибутах).
В качестве крайней меры защиты, сайты, которые хотят запретить исполнение скриптов, могут настроить это поведение глобально, с помощью соответствующей опции.
Пакетный сниффинг
В дополнение к ограничению количества доверенных доменов, с которых разрешается получать контент, можно также ограничить список используемых протоколов; например (в идеале и это крайне желательно с точки зрения обеспечения безопасности), сервер может поставить ограничение на получение контента только по HTTPS. Завершённая стратегия защиты передачи данных должна включать в себя не только принуждение к использованию HTTPS, но также и пометку всех кук с помощью специального флага, а также перенаправление запросов с HTTP на HTTPS. Сайты также могут использовать Strict-Transport-Security HTTP-заголовок, чтобы обеспечить подключение к ним браузеров только по защищённому каналу**.**
Использование CSP
Настройка CSP включает в себя добавление на страницу HTTP-заголовка Content-Security-Policy (en-US) и его настройку в соответствии со списком доверенных источников, из которых пользователь может получать контент. Например, страница, на которой происходит загрузка и отображение изображений может разрешать их получение из любых источников, но ограничить отправку данных формы конкретным адресом. При правильной настройке, Content Security Policy поможет защитить страницу от атак межсайтового скриптинга. Данная статья описывает как правильно настроить необходимые заголовки и примеры, как это сделать.
Определение политики
Вы можете начать настройку Content-Security-Policy (en-US) с определения HTTP-заголовка и указания какую политику использовать:
Content-Security-Policy: policy
Где policy — это строка, содержащая директивы, описывающие вашу Content Security Policy.
Создание политики
Политика описывается с помощью специальных директив, каждая из которых отвечает за отдельный вид ресурсов или policy area. Политика обязательно должна содержать директиву default-src (en-US) , которая будет использоваться для тех ресурсов, для которых не будет описано отдельных правил (полный список вы можете найти в описании директивы default-src (en-US) ). Для того чтобы предотвратить исполнение встраиваемых скриптов и заблокировать использование eval() , необходимо определить директиву default-src (en-US) или script-src (en-US) . Также использование директивы default-src (en-US) или style-src (en-US) позволит ограничить использование встраиваемых стилей как в style -атрибутах, так и в тэгах .
Примеры: Распространённые случаи применения
В данном разделе приводятся наиболее распространённые сценарии использования CSP.
Пример 1
Вы хотите ограничить источники контента только исходным сервером (исключая поддомены)
Content-Security-Policy: default-src 'self'
Пример 2
Вы хотите разрешить получение контента с доверенного домена и всех его поддоменов (доверенный домен не обязательно должен совпадать с тем, на котором настраиваются CSP.)
Content-Security-Policy: default-src 'self' *.trusted.com
Пример 3
Вы хотите разрешить пользователям приложения вставлять в создаваемый ими контент картинки из любого источника, но при этом ограничить источники аудио- и видео-файлов списком доверенных провайдеров. Получение скриптов должно происходить только с конкретного сервера, содержащего доверенный код.
Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com
При такой настройке, весь контент доступен для получения только с исходного домена, со следующими исключениями:
- Изображения могут быть получены из любого источника (источник — «*»).
- Другие медиа-файлы доступны только с media1.com и media2.com (но не с их поддоменов).
- Исполняемый код доступен только с userscripts.example.com.
Пример 4
Вы хотите удостовериться, что весь получаемый контент для онлайн-банкинга идёт по SSL и атакующий не сможет обрабатывать запросы:
Content-Security-Policy: default-src https://onlinebanking.jumbobank.com
При данной настройке сервер будет позволять загрузку страниц только по HTTPS и только из одного источника — onlinebanking.jumbobank.com.
Пример 5
Для просмотра писем в почтовом клиенте вы хотите разрешить использование HTML внутри письма, а также позволить загрузку изображений из любых источников, но запретить использование любого JavaScript-кода и прочий потенциально опасный контент.
Content-Security-Policy: default-src 'self' *.mailsite.com; img-src *
Заметьте, что в настройке политики отсутствует директива script-src (en-US) ; при такой настройке CSP при загрузке скриптов будут использоваться настройки, определяемые директивой default-src (en-US) , следовательно все скрипты могут быть загружены только с исходного домена.
Тестирование настройки политики
Для облегчения развёртывания можно настроить развёртывание CSP в режиме report-only. Таким образом, политика не будет ограничивать загрузку, но будет сообщать обо всех нарушениях на указанный в заголовке URI. Кроме того, заголовок report-only может использоваться для тестирования новой политики без полноценного развёртывания.
Для определения вашей политики вы можете использовать заголовок Content-Security-Policy-Report-Only (en-US) следующим образом:
Content-Security-Policy-Report-Only: policy
В случае, если оба заголовка ( Content-Security-Policy-Report-Only (en-US) и Content-Security-Policy (en-US) ) были определены одновременно в одном ответе сервера, обе политики будут обработаны. Политики, описанные в заголовке Content-Security-Policy будут применены, в то время как политики, описанные в заголовке Content-Security-Policy-Report-Only , создадут отчёты, но применены не будут.
Настройка отправки отчётов
По умолчанию, отправка отчётов не производится. Для того чтобы включить отправку отчётов, необходимо в вашей политике определить директиву report-uri (en-US) и указать как минимум один URI, куда будут направляться отчёты:
Content-Security-Policy: default-src 'self'; report-uri http://reportcollector.example.com/collector.cgi
Кроме того, необходимо настроить свой сервер на получение этих отчётов; вы можете хранить и обрабатывать эти отчёты как считаете нужным.
Синтаксис отчёта о происшествиях
Объект отчёта в формате JSON содержит следующие поля:
URI ресурса, заблокированного в соответствии с настройками политики. Если заблокированный адрес отличается от адреса страницы, то он будет сокращён до схемы, хоста и порта.
Принимает значения «enforce» или «reporting» в зависимости от того, какой заголовок используется Content-Security-Policy-Report-Only (en-US) или Content-Security-Policy .
URI страницы, на которой произошло нарушение.
Директива, исполнение которой привело к нарушению.
Исходная политика, описываемая в заголовке Content-Security-Policy .
Реферер, который привёл к нарушению.
Первые 40 символов встроенного скрипта или стиля, спровоцировавшего нарушение.
The HTTP status code of the resource on which the global object was instantiated.
Директива, которая была нарушена.
Пример отчёта о происшествии
Возьмём страницу, расположенную по адресу http://example.com/signup.html . Для неё используется следующая политика, запрещающая загрузку всего кроме CSS-файлов с cdn.example.com .
Content-Security-Policy: default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports
HTML-код страницы signup.html выглядит следующим образом:
doctype html> html> head> title>Sign Uptitle> link rel="stylesheet" href="css/style.css" /> head> body> . Content . body> html>
Можете заметить ошибку? CSS разрешено загружать только с cdn.example.com , в то время как веб-сайт пытается загрузить его используя основной домен ( http://example.com ). Браузер поддерживающий CSP отправит отчёт о нарушении политики в POST-запросе к http://example.com/_/csp-reports в момент обращения к странице ( signup.html ):
Как видите, отчёт включает полный путь к ресурсу нарушающему политику в blocked-uri . Правда, это не всегда так. К примеру, когда signup.html попытается загрузить CSS с http://anothercdn.example.com/stylesheet.css , браузер не будет включать полный путь, а ограничится лишь доменом ( http://anothercdn.example.com ). Спецификация CSP поясняет это странное поведение. В целом, это делается для предотвращения утечек чувствительной информации о перекрёстных ресурсах
Совместимость с браузерами
BCD tables only load in the browser
Для некоторых версий Safari существует специфическая несовместимость реализации CSP. Если установить заголовок Content Security Policy без заголовка Same Origin, то браузер начнёт блокировать и создавать ложно-положительные отчёты о нарушении политики для всего контента, как с запрашиваемого источника, так и из внешних источников.
- Content-Security-Policy (en-US)
- Content-Security-Policy-Report-Only (en-US)
- Content Security in WebExtensions
- Display security and privacy policies In Firefox Developer Tools
Found a content problem with this page?
- Edit the page on GitHub.
- Report the content issue.
- View the source on GitHub.
This page was last modified on 7 авг. 2023 г. by MDN contributors.
Your blueprint for a better internet.