Перейти к содержанию

Content-Security-Policy

Если ваш магазин отправляет заголовок Content-Security-Policy (или его аналог в <meta http-equiv>), браузер блокирует всё, что политика не разрешает. На этой странице перечислено, что именно нужно виджету Ziex Try-On. Страница описывает виджет в том виде, в каком он выпущен сегодня (фаза 1); раздел Что изменится дальше говорит о планах.

Если на вашей странице нет CSP, ничего из этого не нужно.

Что разрешить

Директива Что добавить Зачем
script-src https://api.ziex-tryon.com Виджет (tryon-embed.js) и лоадер (tryon-loader.js) отдаются с хоста API.
connect-src https://api.ziex-tryon.com Все запросы виджета (отправка примерки, статус, список категорий, сохранённая копия результата) идут на хост API.
img-src https://api.ziex-tryon.com https://media.ziex-tryon.com data: blob: и ваши собственные хосты картинок media.ziex-tryon.com отдаёт картинки результатов; data: нужен для превью фото покупателя; blob: — для миниатюр и полноразмерного просмотра в «Моих образах». Картинки товара загружаются через <img>, поэтому хосты, которые их отдают (ваш магазин или его CDN), должны быть разрешены здесь.
style-src 'unsafe-inline' Виджет кладёт элемент <style> в собственный shadow root и использует несколько inline-атрибутов style.

Замечания:

  • Виджет не использует frame-src, font-src, media-src, worker-src и object-src.
  • Картинки товара не запрашиваются через connect-src. Виджет загружает их как изображения, поэтому для них важна директива img-src. Если CDN отдаёт CORS-заголовки, виджет уменьшает картинку в браузере; без них он отправляет адрес картинки, и её забирает наш сервер.
  • Если в вашей политике нет script-src, connect-src или img-src, браузер использует default-src. Добавляйте хосты в ту директиву, которая у вас действительно есть.

Заголовок целиком

Магазин, который отдаёт всё со своего домена, а картинки товаров — с cdn.shop.example:

Content-Security-Policy: default-src 'self'; script-src 'self' https://api.ziex-tryon.com; connect-src 'self' https://api.ziex-tryon.com; img-src 'self' https://cdn.shop.example https://api.ziex-tryon.com https://media.ziex-tryon.com data: blob:; style-src 'self' 'unsafe-inline'

Та же политика с одной директивой на строку, чтобы её было удобнее читать (заголовок должен быть одной строкой):

default-src 'self';
script-src  'self' https://api.ziex-tryon.com;
connect-src 'self' https://api.ziex-tryon.com;
img-src     'self' https://cdn.shop.example https://api.ziex-tryon.com https://media.ziex-tryon.com data: blob:;
style-src   'self' 'unsafe-inline'

Добавляйте хосты Ziex Try-On в уже существующую политику, а не заменяйте её. Остальные директивы оставьте как есть.

Через тег <meta>

Если заголовки задать нельзя, для этих директив подойдёт тег <meta> в <head>:

<meta http-equiv="Content-Security-Policy"
      content="default-src 'self'; script-src 'self' https://api.ziex-tryon.com; connect-src 'self' https://api.ziex-tryon.com; img-src 'self' https://cdn.shop.example https://api.ziex-tryon.com https://media.ziex-tryon.com data: blob:; style-src 'self' 'unsafe-inline'">

Поместите его раньше первого <script>. Политика в <meta> не может содержать frame-ancestors, report-uri и sandbox; для них нужен настоящий заголовок.

Две вещи, которые блокируются при строгой политике

1. Inline-обработчик onerror превью товара. В окне показывается маленькое превью вещи. Если картинку не удалось загрузить, виджет прячет её inline-обработчиком onerror. При script-src без 'unsafe-inline' этот обработчик блокируется, и сломанное превью остаётся на экране значком битой картинки. Это косметика: на саму примерку она не влияет. Убедитесь, что адрес картинки товара верный, а её хост есть в img-src.

2. Inline-конфигурация от CMS. Обычный способ передать конфигурацию — inline-скрипт, который вызывает TryOn.init({ … }), например добавленный через wp_add_inline_script в WordPress. При строгом script-src inline-скрипт блокируется, если у него нет nonce или хеша. Используйте механизм nonce вашей CMS или фреймворка либо вынесите вызов init() в небольшой файл скрипта, который вы отдаёте сами и разрешаете через 'self'.

Nonce или хеш в style-src отключает 'unsafe-inline'

Браузеры игнорируют 'unsafe-inline' в директиве, где есть nonce или хеш. Если они есть в вашем style-src, элемент <style> виджета блокируется, и окно рисуется без стилей. Пока nonce не поддерживается (см. ниже), в style-src должен быть 'unsafe-inline' без nonce и хеша.

'strict-dynamic'

При 'strict-dynamic' браузер игнорирует имена хостов в script-src. Вместо этого задайте nonce собственным тегам <script>. Лоадер добавляет скрипт виджета из кода, что 'strict-dynamic' разрешает, если сам лоадер разрешён по nonce. Проверьте это в консоли, как описано ниже.

Как проверить

  1. Откройте страницу товара с инструментами разработчика на вкладке Console. Откройте окно и нажмите «Примерить» (достаточно тестового ключа). Браузер выведет строку для каждого заблокированного запроса, например Refused to connect to 'https://api.ziex-tryon.com/…' because it violates the following Content Security Policy directive: "connect-src …". Директива, названная в сообщении, и есть та, которую нужно исправить.
  2. На вкладке Network заблокированный запрос помечен как (blocked:csp).
  3. Сначала безопасно выкатите изменение через Content-Security-Policy-Report-Only: значение то же, но он ничего не блокирует, а только сообщает. Добавьте report-uri https://your-endpoint.example/csp (или report-to), чтобы собирать отчёты от настоящих посетителей, и переключитесь на блокирующий заголовок, когда отчёты станут чистыми.

Как выглядит каждый сбой:

Что заблокировано Что вы увидите
script-src Нет launcher и нет объекта TryOn: window.TryOn равен undefined.
connect-src Launcher нарисован (проверка, которая его прячет при исчерпанном лимите, при ошибке пропускает), но примерка заканчивается сообщением о потере соединения.
img-src Битые картинки: превью вещи, результат или миниатюры в «Моих образах».
style-src Окно появляется без стилей.

Что изменится дальше

В одном из следующих выпусков виджета необходимость 'unsafe-inline' в style-src исчезнет: виджет будет рисоваться без inline-стилей и сможет принимать nonce со страницы. Это ещё не выпущено. Пока этого нет, используйте директивы выше. Когда это появится, здесь будет сказано об этом, а перечисленные здесь директивы продолжат работать.

См. также: справочник по виджету, отложенная загрузка и подхват.