Content Security Policy (CSP) — Примеры

Пример 1 — От «запретить всё» к политике для одной страницы

Страница загружает свой бандл, свою таблицу стилей, иконки из data URI и обращается к своему API. Её никогда не встраивают в другой сайт. Текущая политика команды — заголовок ниже, в котором не назван ни один источник. Замените её на стартовую политику, которая запрещает всё и открывает только то, что использует эта страница, — заголовком ответа, а не тегом meta.

Content-Security-Policy: default-src *

Решение

Content-Security-Policy:
  default-src 'none';
  script-src 'self' 'nonce-<random per response>';
  style-src 'self';
  img-src 'self' data:;
  connect-src 'self';
  frame-ancestors 'none';
  base-uri 'self';

default-src 'none' означает, что источник, о котором никто не подумал, запрещён, а не разрешён, то есть политика отказывает безопасно. Каждая строка затем отвечает на один вопрос: какой код может выполняться, откуда могут приходить изображения, куда можно отправлять данные и кто может встроить страницу во фрейм. Обычная ошибка — написать подстановочный знак и планировать ужесточить его позже; подстановочный знак возвращает всю уязвимость обратно, а список источников так и не проверяется.

Пример 2 — Встроенный скрипт, который блокирует политика

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

Content-Security-Policy: script-src 'self' 'unsafe-inline'

<script>document.documentElement.className = 'dark';</script>

Решение

Content-Security-Policy: script-src 'self' 'nonce-<random per response>'

Выполняется: <script nonce="<same value>">document.documentElement.className='dark';</script>
Отклонено:   <script>document.documentElement.className='dark';</script>
             -> отказ: нет действительного nonce; консоль сообщает о нарушении CSP

Nonce на каждый ответ позволяет браузеру отличить ваш встроенный скрипт от внедрённого, потому что атакующий не может угадать значение для этого ответа. Именно это делает строгую политику возможной на странице, которой действительно нужен встроенный код. Обычная ошибка — оставить 'unsafe-inline' на месте и полагать, что остальная политика по-прежнему защищает страницу; когда он присутствует в script-src, это не так.