Политика безопасности содержимого
Политика безопасности содержимого (CSP) — это стандарт веб-безопасности, который помогает предотвращать атаки с внедрением содержимого, ограничивая источники, из которых оно может загружаться. Она играет важную роль в комплексной стратегии безопасности.
Инструкции по настройке в проекте Django см. в документации «Использование CSP». Руководство по CSP для HTTP см. в руководстве MDN по CSP.
Обзор
Спецификация Content-Security-Policy определяет два взаимодополняющих заголовка:
-
Content-Security-Policy: обеспечивает соблюдение политики CSP, блокируя содержимое, нарушающее заданные директивы. -
Content-Security-Policy-Report-Only: сообщает о нарушениях CSP, не блокируя содержимое, что позволяет проводить тестирование без вмешательства в работу сайта.
Каждая политика состоит из одной или нескольких директив и их значений, которые вместе указывают браузеру, как обрабатывать определённые типы содержимого.
Когда включён ContentSecurityPolicyMiddleware, Django автоматически формирует и добавляет к каждому ответу соответствующие заголовки на основе настроенных параметров, если они ещё не заданы на другом уровне.
Параметры
ContentSecurityPolicyMiddleware настраивается с помощью следующих параметров:
-
SECURE_CSP: задаёт применяемую политику безопасности содержимого. -
SECURE_CSP_REPORT_ONLY: задаёт политику безопасности содержимого только для отчётов.
Эти параметры можно использовать отдельно или вместе
- Используйте только
SECURE_CSP, чтобы применять политику, которая уже прошла тестирование и проверку. - Используйте отдельно
SECURE_CSP_REPORT_ONLY, чтобы оценить новую политику, не нарушая работу сайта. В этом режиме нарушения не блокируются, а только регистрируются. Это удобно для тестирования и мониторинга, но не обеспечивает защиту от активных угроз. - Используйте оба параметра, чтобы сохранять действующую базовую политику и одновременно экспериментировать с изменениями. Даже для хорошо отлаженных политик сбор отчётов помогает выявлять регрессии, неожиданные изменения поведения или возможное вмешательство в рабочей среде.
Отчёты о нарушениях политики
При нарушении CSP браузеры обычно записывают подробную информацию в консоль разработчика, обеспечивая оперативную обратную связь во время разработки. Чтобы также получать эти отчёты программно, политика должна содержать директиву для отправки отчётов, например report-uri, которая задаёт адрес для отправки данных о нарушениях.
Django поддерживает настройку этих директив через параметры SECURE_CSP_REPORT_ONLY, однако браузер будет отправлять отчёты, только если политика явно содержит допустимую директиву для отправки отчётов.
Django не предоставляет встроенных средств для получения, хранения или обработки отчётов о нарушениях. Чтобы собирать и анализировать их, необходимо реализовать собственную конечную точку для отчётов или интегрировать стороннюю службу мониторинга.
Константы CSP
Django предоставляет предопределённые константы для распространённых ключевых слов выражений источников CSP, таких как 'self', 'none' и 'unsafe-inline'. Эти константы предназначены для использования в значениях директив, заданных в параметрах.
Они доступны через перечисление CSP; рекомендуется использовать их вместо обычных строк. Это помогает избежать распространённых ошибок, таких как опечатки, неправильное заключение в кавычки или несогласованное форматирование, и обеспечивает соответствие спецификации CSP.
-
class CSP[исходный код] -
Перечисление со стандартными константами для распространённых выражений источников CSP.
-
NONE -
Представляет
'none'. Блокирует загрузку ресурсов для заданной директивы.
-
REPORT_SAMPLE -
Представляет
'report-sample'. Указывает браузеру включать в отчёты фрагмент кода, вызвавшего нарушение. Обратите внимание, что это может привести к раскрытию конфиденциальных данных.
-
SELF -
Представляет
'self'. Разрешает загрузку ресурсов с того же источника (с той же схемой, узлом и портом).
-
STRICT_DYNAMIC -
Представляет
'strict-dynamic'. Разрешает выполнение скриптов, загруженных доверенным скриптом (например, скриптом с допустимым nonce или хешем), без необходимости использовать'unsafe-inline'.
-
UNSAFE_EVAL -
Представляет
'unsafe-eval'. Разрешает использованиеeval()и подобных функций JavaScript. Настоятельно не рекомендуется.
-
UNSAFE_HASHES -
Представляет
'unsafe-hashes'. Разрешает встроенные обработчики событий и некоторые URIjavascript:, если их содержимое соответствует хешу правила политики. Требуется CSP уровня 3 или выше.
-
UNSAFE_INLINE -
Представляет
'unsafe-inline'. Разрешает выполнение встроенных скриптов, стилей и URL-адресовjavascript:. В целом не рекомендуется, особенно для скриптов.
-
WASM_UNSAFE_EVAL -
Представляет
'wasm-unsafe-eval'. Разрешает компиляцию и выполнение кода WebAssembly без включения'unsafe-eval'для скриптов.
-
NONCE -
Специальное для Django значение-заполнитель (
"<CSP_NONCE_SENTINEL>"), используемое в директивахscript-srcилиstyle-srcдля включения CSP на основе nonce. Во время выполнения эта строка заменяетсяContentSecurityPolicyMiddlewareна безопасный случайный nonce, генерируемый для каждого запроса. Подробное объяснение см. в разделе Использование nonce.
-
Декораторы
Django предоставляет декораторы для управления заголовками политики безопасности содержимого отдельно для каждого представления. С их помощью можно переопределять или отключать применяемую политику либо политику только для отчётов для отдельных представлений, обеспечивая точную настройку в случаях, когда глобальных параметров недостаточно. При применении этих переопределений базовая CSP полностью заменяется: правила не объединяются с существующими. Их можно использовать вместе с константами, определёнными в CSP.
Предупреждение
Ослабление или отключение политики CSP на любой странице может поставить под угрозу безопасность всего сайта. Из-за политики «одного источника» злоумышленник может воспользоваться уязвимостью на одной странице, чтобы получить доступ к другим частям сайта.
-
csp_override(config)(view)[исходный код] -
Переопределяет заголовок
Content-Security-Policyдля декорированного представления, используя директивы в том же формате, что и параметрSECURE_CSP.Аргумент
configдолжен быть отображением с нужными директивами CSP. Еслиconfig— пустое отображение ({}), в ответ, возвращаемый этим представлением, не будет добавлен заголовок для обеспечения CSP, что фактически отключит CSP для этого представления.Примеры:
from django.http import HttpResponse from django.utils.csp import CSP from django.views.decorators.csp import csp_override @csp_override( { "default-src": [CSP.SELF], "img-src": [CSP.SELF, "data:"], } ) def my_view(request): return HttpResponse("Custom Content-Security-Policy header applied") @csp_override({}) def my_other_view(request): return HttpResponse("No Content-Security-Policy header added")
-
csp_report_only_override(config)(view)[исходный код] -
Переопределяет заголовок
Content-Security-Policy-Report-Onlyдля декорированного представления, используя директивы в том же формате, что и параметрSECURE_CSP_REPORT_ONLY.Как и в случае с
csp_override(), аргументconfigдолжен быть отображением с нужными директивами CSP. Еслиconfig— пустое отображение ({}), в ответ, возвращаемый этим представлением, не будет добавлен заголовок CSP только для отчётов, что фактически отключит CSP только для отчётов для этого представления.Примеры:
from django.http import HttpResponse from django.utils.csp import CSP from django.views.decorators.csp import csp_report_only_override @csp_report_only_override( { "default-src": [CSP.SELF], "img-src": [CSP.SELF, "data:"], "report-uri": "https://mysite.com/csp-report/", } ) def my_view(request): return HttpResponse("Custom Content-Security-Policy-Report-Only header applied") @csp_report_only_override({}) def my_other_view(request): return HttpResponse("No Content-Security-Policy-Report-Only header added")
В примерах выше предполагаются представления на основе функций. Информацию о представлениях на основе классов см. в руководстве по декорированию представлений на основе классов.
Использование nonce
Nonce CSP («число, используемое один раз») — это уникальное случайное значение, генерируемое для каждого HTTP-ответа. Django поддерживает nonce как безопасный способ разрешить выполнение определённых встроенных элементов <script> или <style> без использования 'unsafe-inline'.
Чтобы включить nonce, добавьте специальный заполнитель NONCE в соответствующую директиву или директивы ваших параметров CSP, например script-src или style-src. Если он присутствует, ContentSecurityPolicyMiddleware сгенерирует nonce и добавит соответствующее выражение источника nonce-<value> в заголовок CSP.
Чтобы использовать этот nonce в шаблонах, необходимо включить контекстный процессор csp(). Он добавляет в контекст шаблона переменную csp_nonce, позволяя встроенным элементам указывать соответствующий атрибут nonce={{ csp_nonce }} во встроенных скриптах или стилях.
Браузер выполнит только те встроенные элементы, которые содержат атрибут nonce=<value> со значением, совпадающим с указанным в заголовке Content-Security-Policy (или Content-Security-Policy-Report-Only). Этот механизм позволяет точно контролировать, какой встроенный код может выполняться.
Если шаблон содержит {{ csp_nonce }}, но политика не включает NONCE, в HTML будет атрибут nonce, но в заголовке не будет необходимого выражения источника. В этом случае браузер заблокирует встроенный скрипт или стиль (либо сообщит о нём, если настроен режим только для отчётов).
Генерация nonce и кэширование
Генерация nonce в Django выполняется лениво: промежуточный слой генерирует nonce, только если во время рендеринга шаблона используется {{ csp_nonce }}. Это позволяет избежать ненужной работы для страниц, которым nonce не требуется.
Однако, поскольку nonce должен быть уникальным для каждого запроса, при использовании полноэкранного кэширования (например, промежуточного слоя кэширования Django или кэширования CDN) требуется особая осторожность. При выдаче кэшированных ответов с ранее сгенерированными nonce они могут повторно использоваться для разных пользователей и запросов. Такие ответы могут продолжать работать (поскольку nonce в заголовке CSP и HTML совпадают), однако повторное использование лишает nonce смысла и ослабляет защиту.
Чтобы политики на основе nonce оставались эффективными:
- Не кэшируйте целые ответы, содержащие
{{ csp_nonce }}. - Если кэширование необходимо, используйте стратегию, которая добавляет новый nonce при каждом запросе, либо рассмотрите возможность переработать приложение так, чтобы полностью отказаться от встроенных скриптов и стилей.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/6.0/ref/csp/