<!-- Canonical: https://docs.shopstory.live/docs/operations/csp-headers -->

# Content Security Policy

Код ShopStory Web SDK выполняется в контексте origin сайта ритейлера. Разрешайте в CSP только те ресурсы ShopStory, которые использует согласованная интеграция.

Не создавайте вторую CSP рядом с существующей: браузер применит обе политики одновременно. Добавьте нужные источники в действующие директивы сайта.

## Базовые источники

| Directive | Источник | Когда нужен |
| --- | --- | --- |
| `script-src` | `https://app.shopstory.live` | Загрузка Web SDK |
| `connect-src` | `https://app.shopstory.live` | Public API и запросы Web SDK во время работы |
| `connect-src` | `wss://app.shopstory.live` | Live-соединение, если оно используется сценарием |
| `frame-src` | `https://app.shopstory.live` | Фрейм ShopStory, если он включён |
| `img-src` | `https://app.shopstory.live` | Изображения ShopStory; отдельно добавьте точные origins изображений товарного фида |
| `media-src` | выдаются для проекта | Список origins для видео зависит от маршрута доставки |
| `worker-src` | `blob:` | Только если проверка в браузере подтверждает работу Web Worker через blob URL |

Домены изображений товара и видео могут отличаться по проектам. ShopStory указывает итоговый список origins в интеграционном пакете. Не добавляйте `https:` или `*` вместо этого списка.

Устаревший `watch.shopstory.live` не является базовым origin текущего Web SDK.

## Пример политики

Пример рассчитан на страницу, где собственные скрипты и файлы загружаются с того же origin. Добавьте origins для видео и товарных изображений из интеграционного пакета. Остальные источники сайта должны остаться в политике.

merchant-site.conf

```nginx
add_header Content-Security-Policy "
  default-src 'self';
  script-src 'self' https://app.shopstory.live;
  connect-src 'self' https://app.shopstory.live wss://app.shopstory.live;
  frame-src 'self' https://app.shopstory.live;
  img-src 'self' data: https://app.shopstory.live;
  media-src 'self' blob: https://<assigned-media-origin>;
  font-src 'self';
  style-src 'self' 'unsafe-inline';
  object-src 'none';
  base-uri 'self';
  form-action 'self';
  frame-ancestors 'self';
" always;
```

`<assigned-media-origin>` — служебная заглушка. Перед выпуском в production замените её значением из интеграционного пакета.

## Inline-стили

Web SDK добавляет CSS в документ сайта. Разрешите `'unsafe-inline'` только в `style-src`. Если правила сайта запрещают это значение, остановите подключение и согласуйте с ShopStory другой способ поставки стилей. Для текущего публичного bundle ShopStory не заявляет контракт с nonce или hash.

Не добавляйте из-за ShopStory:

- `'unsafe-eval'` в `script-src`;
- `'unsafe-inline'` в `script-src`;
- wildcard `*`;
- `data:` или `blob:` в `script-src`;
- произвольный `https:` в `connect-src`, `frame-src` или `media-src`.

## Проверка через Report-Only

Сначала включите политику без блокировки:

merchant-site-report-only.conf

```nginx
add_header Content-Security-Policy-Report-Only "
  default-src 'self';
  script-src 'self' https://app.shopstory.live;
  connect-src 'self' https://app.shopstory.live wss://app.shopstory.live;
  frame-src 'self' https://app.shopstory.live;
  img-src 'self' data: https://app.shopstory.live;
  media-src 'self' blob: https://<assigned-media-origin>;
  font-src 'self';
  style-src 'self' 'unsafe-inline';
  object-src 'none';
  base-uri 'self';
" always;
```

Проверьте реальные сценарии:

1. Каталог и открытие live.
2. Воспроизведение VOD и seek.
3. Mini-player на карточке товара.
4. Live-widget.
5. Открытие товара и добавление в корзину.
6. Mobile WebView, если он входит в проект.

В отчётах проверьте `effective-directive`, `blocked-uri` и route страницы. Перед сохранением CSP reports удаляйте query string и пользовательские данные.

После проверки перенесите политику в `Content-Security-Policy`. Не оставляйте Report-Only единственной политикой.

## Security headers сайта

Следующий блок — общий baseline для сайта, а не обязательная конфигурация ShopStory. Сохраните действующие headers и проверьте, какие возможности использует сам сайт.

Добавьте следующие headers:

```nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-XSS-Protection "0" always;
```

Включайте HSTS `includeSubDomains` и preload только при гарантированном HTTPS во всём соответствующем namespace. `X-XSS-Protection: 0` отключает устаревший browser filter. От XSS защищают корректное escaping и CSP.

`Permissions-Policy` остаётся в зоне ответственности ритейлера. Не отключайте `geolocation`, если она нужна выбору магазина, доставке или другой функции сайта. Ограничения `camera`, `microphone` и остальных возможностей согласуйте с действующей политикой продукта.

Если в Nginx внутри `location` задан собственный `add_header`, родительские headers могут перестать наследоваться. Проверьте каждый тип ответа: HTML, JS, YAML/JSON, ошибки и Swagger.

## Проверка

check-csp.sh

```bash
curl -sSI https://shop.example/live/ \
  | grep -Ei 'content-security-policy|strict-transport|content-type-options|referrer-policy'
```

В DevTools проверьте Console и Network, затем повторите тест с отключённым cache. Полученный header подтверждает только доставку политики. На production-сайте воспроизведите видео и выполните commerce actions.

Распределение ответственности: [Безопасность](<https://docs.shopstory.live/docs/operations/security>).
