Кратко

  • Первый открытый проект W3C по Content Security Policy от 29 ноября 2011 года предложил сайту объявлять допустимые источники ресурсов, а браузеру — проверять реальные запросы на загрузку.
  • Рекомендация второго уровня от 15 декабря 2016 года описала обязательную политику, режим одних только отчётов и точечные разрешения для встроенных скриптов с помощью nonce и хеша. Список писал сайт; дверь охранял браузер.

Сайт устроил приём и потерял книгу приглашений. Один скрипт пришёл от знакомого поставщика. Второй привёл старый виджет, о котором никто уже не мог рассказать. Следом выстроились изображения, шрифты и соединения с удалёнными службами. Среди них чужой код пытался пройти с видом давнего знакомого. Нанять охранника было просто. Составить для него правдивый список гостей оказалось труднее.

Первый открытый рабочий проект W3C по Content Security Policy от 29 ноября 2011 года предложил разделить обязанности. Документ описывал декларативную политику, с помощью которой веб-приложение ограничивает источники загружаемых ресурсов и снижает риск внедрения содержимого, включая межсайтовые скрипты. Сайт называл допустимые источники. Браузер сверял с правилом конкретный запрос в тот момент, когда странице понадобился ресурс.

Список был подробнее одного штампа «надёжно». Проект различал default-src и правила для скриптов, изображений, стилей, шрифтов, фреймов, медиафайлов и соединений. Фотографии можно было брать из нескольких мест, а исполняемый код — из более узкого круга. Картина на стене и человек за пультом сценического света не должны получать одинаковый ключ. Разным ресурсам полагались разные условия входа.

Новая дверь заставляла сайт взглянуть на собственное хозяйство. Издатель знал, каких поставщиков хотел использовать; браузер видел адреса, которые страница запрашивала на деле. Политика связывала эти две картины. Написать script-src можно быстро. Разобраться, зависит ли старая акция от забытого компонента, куда сложнее. Если забыть в списке законный платёжный модуль, охранник остановит его столь же решительно, как нежелательный скрипт. Такая поломка показывает состояние гостевой книги хозяина.

Рекомендация W3C Content Security Policy Level 2 от 15 декабря 2016 года предусмотрела репетицию. Заголовок ответа Content-Security-Policy-Report-Only велел браузеру следить за нарушениями предполагаемой политики и отправлять отчёты, продолжая загружать ресурсы. В документе показано, как по этим наблюдениям доработать правило, а затем перейти к заголовку Content-Security-Policy, который уже действует. Сначала охранник стоит с блокнотом, затем натягивает канат у входа.

Блокнот мог раскрыть забытые зависимости: шрифт из неожиданного места, счётчик на старой странице, соединение, запущенное компонентом без ответственного. Браузер сообщал, какой запрос увидел. Команда решала, относится ли он к нужной функции, следует ли убрать ресурс или изменить страницу либо правило. Режим отчётов показывал расхождение между аккуратной схемой сайта на доске и тем сайтом, который действительно работает.

Имело значение и место размещения правила. Документ 2016 года предпочитал заголовок HTTP-ответа, который браузер получает в самом начале. Политику разрешалось поместить и в ранний HTML-элемент meta, но она не действовала на ресурсы, загруженные до него, и не поддерживала режим одних отчётов. Табличка с правилами, которую вешают в фойе после прихода половины публики, для входного контроля подходит плохо.

Встроенные прямо в страницу скрипты были самым трудным типом гостя. Некоторые действительно нужны сайту. Широкое разрешение на любой встроенный код впускало бы вместе с ними и внедрённый код. Второй уровень описал nonce и хеши для выбора конкретных блоков. Сервер мог создать случайное значение для ответа и поставить соответствующий пропуск в политику и выбранные элементы. Хеш подходил к точному содержимому скрипта. Сайт выдавал именные приглашения, а не открывал дверь каждому, кто принёс бумажку с надписью JavaScript.

Дверей было несколько. img-src касалась изображений, connect-src — определённых соединений, base-uri — базового адреса относительных ссылок, form-action — назначения форм, frame-ancestors — страниц, которым разрешено показывать сайт во фрейме. Каждая директива отвечала за своё действие. Сайт выбирал допустимое, браузер проверял запрос при его выполнении.

История публикаций CSP Level 2, которую ведёт W3C, показывает проекты, предшествовавшие Рекомендации декабря 2016 года. Эти даты относятся к текстам стандарта. Главный итог развития заметен в повседневной работе: сайт формулирует намерение, браузер проверяет загрузку, а отчёты показывают, насколько настоящая страница отличается от плана. Охраннику выдали инструкцию; хозяину пришлось узнать собственных гостей.

Читатель не изучает script-src перед тем, как открыть статью или оплатить покупку. Он видит работающую страницу — либо ошибку, если имя нужного компонента забыли. Список действует за кулисами. Браузер может не пустить код без приглашения. Но для этого сайт должен наконец сказать, кого сам приглашал. Иногда технический прогресс начинается с довольно неудобной переклички.