Content Security Policy и ваш CMP: как заставить CSP и согласие работать вместе
Два уровня защиты, которые должны согласовываться
Content Security Policy (CSP) сообщает браузеру, из каких источников странице разрешено загружать скрипты, стили, изображения, фреймы и сетевые запросы. Платформа управления согласием выполняет противоположную задачу: она решает, какие из этих скриптов можно запускать, исходя из выбора пользователя. Если настраивать их по отдельности, они сталкиваются. CMP не загружается, потому что CSP его блокирует, либо CSP ослабляют так сильно ради CMP и рекламных тегов, что она уже ничего не защищает.
В этом руководстве объясняется, какие директивы CSP обычно нужны CMP, как nonce взаимодействуют с внедрением скриптов и как вносить изменения, не ломая баннер.
Что CMP обычно требуется от CSP
Точные требования зависят от вендора, поэтому всегда начинайте с собственной документации вашего CMP. В общем случае проверьте такие директивы:
script-src— домен, с которого загружается скрипт CMP, плюс любые дополнительные файлы скриптов, которые он подгружает.connect-src— конечные точки, которые CMP вызывает черезfetchили XHR, например для конфигурации, списка вендоров, геолокации и записи согласий.style-src— домен таблицы стилей и, возможно, встроенные стили, если CMP внедряет элемент<style>или задаёт атрибуты style.img-src— логотипы, значки и любые пиксели без отслеживания, которые использует CMP.font-src— если баннер загружает собственные шрифты.frame-src— если CMP использует iframe, например для обмена согласием между доменами.
На сайтах с TCF помните, что CMP также создаёт на странице фрейм-локатор с именем __tcfapiLocator. Этот фрейм создаётся без удалённого источника, поэтому записи в frame-src ему обычно не нужно, но это стоит подтвердить при тестировании.
Проблема встроенной заглушки
Большинство CMP просят разместить в head страницы небольшой встроенный скрипт — заглушку, — чтобы другие скрипты могли ставить вызовы в очередь до загрузки основного CMP. Строгая CSP блокирует встроенные скрипты, если явно их не разрешить. Есть три варианта:
- Nonce. Генерируйте случайное значение для каждого ответа, добавляйте его в заголовок CSP как
'nonce-...'и в тег<script>заглушки. Это самый гибкий вариант для динамических страниц. - Хеш. Добавьте SHA-256-хеш точного содержимого заглушки в
script-src. Это хорошо работает для статических сайтов, но любое изменение заглушки, даже пробела, его ломает. - Размещение заглушки у себя как внешнего файла на вашем домене, покрываемого
'self'. Здесь нужна осторожность, чтобы она по-прежнему загружалась достаточно рано.
Избегайте 'unsafe-inline' как лёгкого пути. Он разрешает любые встроенные скрипты, что снимает большую часть защиты, которую даёт CSP.
Nonce и скрипты, внедряемые CMP
CMP, блокирующий скрипты до получения согласия, часто работает так: удерживает их и внедряет позже. При CSP на основе nonce эти внедряемые скрипты тоже должны быть разрешены. Есть два распространённых подхода:
- Передача nonce. CMP считывает nonce из собственного тега script и добавляет его к каждому внедряемому скрипту. Проверьте, поддерживает ли это ваш CMP.
'strict-dynamic'. Это ключевое слово сообщает поддерживающим браузерам, что скриптам, загруженным уже доверенным скриптом, можно доверять. Оно упрощает работу с менеджерами тегов и CMP, внедряющими скрипты, но означает и то, что любой доверенный вами скрипт может загружать другие, поэтому доверяйте осторожно.
Менеджеры тегов ставят тот же вопрос. Если вы загружаете рекламные и аналитические теги через менеджер тегов, следуйте его документации по nonce и убедитесь, что CMP и менеджер тегов используют согласованный подход.
Рекламные теги усложняют CSP
Программатик-реклама загружает скрипты и фреймы со множества доменов, а список меняется вместе с партнёрами по спросу. Издатели обычно выбирают одно из двух:
- Строгая CSP на страницах без программатик-рекламы и более широкая политика там, где она показывается.
- Политика, сосредоточенная на директивах, которыми остаётся посильно управлять, таких как
frame-ancestors,object-src 'none'иbase-uri, при более широких источниках скриптов.
В любом случае CMP должен находиться в явном списке разрешённых, а не покрываться только шаблоном-подстановкой, чтобы изменение CSP никогда не отключило баннер незаметно.
Внедряйте через режим Report-Only
Сначала используйте заголовок Content-Security-Policy-Report-Only. Браузер сообщает о нарушениях, ничего не блокируя, так что вы видите, что сломала бы новая политика.
- Разверните политику в режиме report-only с конечной точкой для отчётов.
- Загружайте страницы в чистых профилях браузера и пройдите весь сценарий согласия: первый визит, принять все, отклонить все, пользовательский выбор, отзыв.
- Изучите отчёты о нарушениях и консоль браузера на предмет заблокированных ресурсов CMP.
- Скорректируйте политику, затем переключитесь на принудительное применение.
- Оставьте отчёты включёнными и после включения применения, чтобы ловить регрессии.
Симптомы конфликта с CSP
- Баннер не появляется, а консоль показывает нарушение CSP для скрипта CMP.
- Баннер появляется, но без стилей, потому что
style-srcблокирует его CSS. - Выбор не сохраняется, потому что
connect-srcблокирует вызов записи согласия. - Реклама или аналитика не загружаются после согласия, потому что у внедряемых скриптов нет nonce.
__tcfapiне определена, потому что встроенная заглушка была заблокирована.
Главные выводы
- Проверьте
script-src,connect-src,style-src,img-srcиframe-srcдля вашего CMP. - Разрешайте встроенную заглушку через nonce или хеш, а не через
'unsafe-inline'. - Убедитесь, что скрипты, внедряемые после согласия, получают nonce или покрываются
'strict-dynamic'. - Протестируйте каждый путь согласия в режиме report-only до включения применения.
- Держите CMP в явном списке разрешённых, чтобы изменения CSP не могли его отключить.