Content Security Policy (CSP) — механизм безопасности браузера, предназначенный для предотвращения атак, связанных с внедрением вредоносного кода в веб-приложение. Основная задача CSP — ограничить источники загрузки ресурсов и выполнение потенциально опасного содержимого.
CSP особенно эффективен против:
Политика безопасности задаётся сервером через HTTP-заголовок:
Content-Security-Policy: default-src 'self';
или через HTML-метатег:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
Предпочтительным вариантом считается HTTP-заголовок, поскольку метатег обрабатывается только после загрузки HTML-документа.
Браузер анализирует политику безопасности и сравнивает её с каждой попыткой:
Если действие нарушает правила CSP, браузер блокирует его выполнение.
Пример:
Content-Security-Policy: script-src 'self'
Разрешено:
<script src="/app.js"></script>
Запрещено:
<script src="https://evil.com/hack.js"></script>
Политика состоит из директив.
Общий формат:
Content-Security-Policy: директива значение; директива значение;
Пример:
Content-Security-Policy:
default-src 'self';
script-src 'self' cdn.example.com;
img-src *;
default-src определяет источник по умолчанию для всех
типов ресурсов, если специализированная директива отсутствует.
Пример:
Content-Security-Policy: default-src 'self';
Разрешены только ресурсы текущего домена.
'self'Текущий origin:
default-src 'self'
*Любой источник:
img-src *
Используется редко, поскольку снижает безопасность.
script-src https://cdn.example.com
script-src https://*.example.com
img-src https:
Разрешены изображения только по HTTPS.
'none'Полный запрет:
object-src 'none'
data:Разрешение data URI:
img-src data:
blob:Разрешение Blob URL:
worker-src blob:
Контролирует JavaScript.
script-src 'self'
Контролирует CSS.
style-src 'self'
Источники изображений.
img-src 'self' https://images.example.com
Источники шрифтов.
font-src 'self'
Исходящие соединения:
connect-src api.example.com
Аудио и видео:
media-src media.example.com
Flash, plugins, embed.
Современные приложения обычно полностью запрещают:
object-src 'none'
Разрешённые iframe:
frame-src youtube.com
Устаревающая директива для iframe и worker.
Контролирует Web Workers:
worker-src 'self'
Источники web manifest:
manifest-src 'self'
Ограничивает <base>:
base-uri 'none'
Разрешённые URL отправки форм:
form-action 'self'
Защита от clickjacking.
Определяет, кто может встроить страницу в iframe.
frame-ancestors 'none'
Разрешить только собственный сайт:
frame-ancestors 'self'
Изоляция документа:
sandbox allow-scripts
Одной из главных целей CSP является блокировка inline JavaScript.
Запрещается:
<script>
alert('XSS');
</script>
Также запрещаются inline-обработчики:
<button oncl ick="run()">
Причина — XSS-уязвимости часто используют именно inline-код.
nonce — случайный одноразовый токен.
HTTP-заголовок:
Content-Security-Policy: script-src 'nonce-abc123'
HTML:
<script nonce="abc123">
console.log('safe');
</script>
Если nonce совпадает — выполнение разрешается.
Nonce должен:
Разрешение возможно через SHA-хеш содержимого скрипта.
Политика:
script-src 'sha256-xxyyzz'
Браузер вычисляет hash содержимого inline-скрипта и сравнивает его с CSP.
Преимущество:
Недостаток:
script-src 'unsafe-inline'
Разрешает inline JavaScript.
Практически полностью ослабляет защиту CSP.
Использование крайне нежелательно.
Разрешает:
script-src 'unsafe-eval'
Опасно с точки зрения XSS.
Позволяет доверять скриптам, загруженным доверенным скриптом.
Пример:
script-src 'nonce-random' 'strict-dynamic'
Современный подход для крупных SPA-приложений.
Дополнительный механизм защиты от DOM XSS.
Пример:
require-trusted-types-for 'script'
Trusted Types ограничивают опасные DOM API:
Уязвимый код:
element.innerHTML = userInput;
Атакующий может передать:
<script src="https://evil.com/xss.js"></script>
Скрипт выполнится.
Политика:
Content-Security-Policy: script-src 'self'
Внешний скрипт будет заблокирован.
Даже при наличии XSS последствия становятся значительно меньше.
Режим тестирования политики.
Заголовок:
Content-Security-Policy-Report-Only:
default-src 'self';
Политика не блокирует ресурсы, а только сообщает о нарушениях.
Полезно при постепенном внедрении CSP.
Устаревающий механизм:
report-uri /csp-report
Современный вариант:
report-to csp-endpoint
Пример:
Reporting-Endpoints:
csp-endpoint="https://example.com/csp-report"
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-random123';
style-src 'self';
img-src 'self' dat a:;
connect-src 'self' api.example.com;
object-src 'none';
base-uri 'none';
frame-ancestors 'none';
React уменьшает риск XSS благодаря экранированию JSX.
Однако опасность появляется при использовании:
dangerouslySetInnerHTML
CSP помогает ограничить последствия подобных ошибок.
Для React-приложений часто используются:
script-src 'self' 'nonce-...'
Angular имеет встроенную защиту от XSS.
Дополнительную безопасность обеспечивают:
Angular CLI может автоматически генерировать nonce.
Vue также экранирует шаблоны.
Опасность возникает при:
v-html
CSP предотвращает выполнение внедрённого JavaScript.
Некоторые сценарии требуют:
script-src 'wasm-unsafe-eval'
Без этого WebAssembly может блокироваться CSP.
Если приложение использует CDN:
script-src 'self' https://cdn.jsdelivr.net
Важно явно перечислять доверенные домены.
Пример:
style-src 'self' https://fonts.googleapis.com;
font-src https://fonts.gstatic.com;
connect-src wss://api.example.com
Разрешение iframe:
frame-src https://www.youtube.com
worker-src 'self'
Базовые директивы:
Добавлены:
Добавлены:
Плохо:
script-src *
script-src 'unsafe-inline'
script-src 'unsafe-eval'
Следует явно запрещать:
object-src 'none'
Уязвимость к clickjacking.
Report Only:
Content-Security-Policy-Report-Only:
default-src 'self'
Сбор нарушений.
Исправление inline-кода.
Добавление nonce/hash.
Переход в blocking mode.
Пример через Helmet:
import helmet from 'helmet';
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
objectSrc: ["'none'"],
},
})
);
add_header Content-Security-Policy "
default-src 'self';
script-src 'self';
object-src 'none';
";
Header set Content-Security-Policy "
default-src 'self';
"
CSP часто используется вместе с SRI.
Пример:
<script
src="https://cdn.example.com/app.js"
integrity="sha384-abc"
crossorigin="anonymous">
</script>
SRI проверяет целостность файла.
SPA-приложения активно используют:
Для них особенно важны:
Сторонние скрипты:
Каждый внешний домен увеличивает поверхность атаки.
Рекомендуется:
Браузеры выводят ошибки CSP в DevTools.
Пример сообщения:
Refused to load the script because it violates the following Content Security Policy directive...
Полезные инструменты:
Инструмент от Google для анализа политики CSP.
Проверяет:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-random';
style-src 'self';
img-src 'self' dat a:;
connect-src 'self';
font-src 'self';
object-src 'none';
base-uri 'none';
frame-ancestors 'none';
form-action 'self';
upgrade-insecure-requests;
Автоматически заменяет HTTP на HTTPS:
upgrade-insecure-requests
Блокирует небезопасный HTTP-контент внутри HTTPS-страницы:
block-all-mixed-content
CSP и CORS решают разные задачи.
Определяет:
Определяет:
Same-Origin Policy ограничивает доступ JavaScript между origin.
CSP дополнительно ограничивает загрузку и выполнение ресурсов.
Некоторые неправильные настройки могут позволить обход CSP.
Примеры:
Хорошо:
script-src 'nonce-random'
Плохо:
script-src 'unsafe-inline'
object-src 'none'
default-src https:
Каждый новый origin увеличивает риск.
Это позволяет избежать поломки приложения.
CSP наиболее эффективен вместе с: