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

# Безопасность интеграции

ShopStory предоставляет публичный каталог, runtime плеера и события взаимодействия с товаром. Ритейлер отвечает за пользовательскую сессию, актуальный остаток, корзину, checkout и персональные данные.

## Модель ответственности

| Область | ShopStory | Ритейлер |
| --- | --- | --- |
| Каталог эфиров и runtime плеера | Публичный контракт и работа сервиса | Размещение SDK и работа интерфейса |
| `applicationId` | Выдача и привязка окружения | Раздельная конфигурация тестовой и production-среды |
| Товарный фид | Импорт согласованных полей | Качество, права на данные и стабильные идентификаторы |
| Остаток | Показ полученного снимка или согласованный custom flow | Источник актуальных данных, выбор магазина или региона и финальная проверка |
| Корзина | Вызов Web callback или передача типизированного mobile action | Сессия, CSRF, авторизация и подтверждение изменения |
| Mobile SDK | Встроенный плеер и проверка данных на границе SDK | Нативные routes, commerce actions и состояние lifecycle |
| Персональные данные | Обрабатывает только данные, предусмотренные согласованной интеграцией | Не передаёт в ShopStory лишние пользовательские данные |

## `applicationId` и учётные данные

`applicationId` — публичный идентификатор маршрутизации. Он виден в браузере и не предоставляет авторизацию.

- Не используйте его как доказательство личности пользователя или сервера.
- Не передавайте через Public API секреты, персональные данные и административные команды.
- Учётные данные merchant-системы хранятся и используются только на доверенной серверной стороне.
- Не добавляйте токены в параметры URL.
- Очищайте URL и headers перед записью в логи, аналитику и crash reports.

Публичный контракт API не задаёт Bearer-схему. Подробнее: [Идентификация приложения](<https://docs.shopstory.live/docs/guide/authentication>).

## Входные и выходные данные

Валидируйте названия товаров, URL, параметры API и payload мобильного действия перед использованием.

- Для каждого поля проверяйте тип, допустимые значения и максимальную длину.
- Оставляйте product IDs строками; не теряйте ведущие нули и точность.
- Кодируйте пользовательский ввод через `URLSearchParams`.
- Выводите текст через безопасные DOM API или escaping шаблонизатора.
- Не вставляйте данные API через `innerHTML`.
- Для внешнего URL разрешайте только схему `https` и хосты из exact allowlist.
- Сначала проверяйте HTTP status, затем `status` JSON-конверта. Только после этого используйте `body`.

Не показывайте пользователю stack trace, детали SQL/HTTP upstream-системы и внутренние идентификаторы инфраструктуры.

## Корзина и актуальный остаток

Перед изменением корзины endpoint ритейлера проверяет:

1. HTTP-метод и content type.
2. Действующую пользовательскую сессию.
3. Штатную CSRF-защиту платформы и допустимый origin.
4. Product key, quantity и вариант товара.
5. Текущий остаток для выбранного магазина, региона или способа получения.
6. Фактическое изменение корзины до ответа об успехе.

CORS не заменяет CSRF-защиту. Наличие session cookie само по себе не разрешает изменение данных.

Не повторяйте запрос на изменение корзины автоматически без idempotency-защиты. Web callback получает `true` только после подтверждённого изменения в merchant-системе.

Mobile SDK передаёт приложению типизированное действие. Способ обработки результата указан в handoff поставленного пакета. Состояние плеера и событие аналитики не подтверждают изменение корзины: [Добавление товара в корзину](<https://docs.shopstory.live/docs/guide/add-to-cart>).

## Интеграция в браузере

ShopStory заранее регистрирует production origins клиента. CORS ограничивает вызовы из браузера. Запрос вне браузера по-прежнему возможен.

На сайте ритейлера:

- загрузите SDK только по `https` с согласованного URL;
- добавьте необходимые origins в действующую CSP;
- не отключайте CSP целиком ради виджета;
- не добавляйте `unsafe-eval` или wildcard без подтверждённой необходимости;
- задайте `X-Content-Type-Options: nosniff` и актуальную `Referrer-Policy`;
- для устаревшего `X-XSS-Protection` используйте `0`, чтобы не включать legacy-фильтр браузера.

Точный порядок настройки: [Content Security Policy](<https://docs.shopstory.live/docs/operations/csp-headers>).

## Mobile SDK

Mobile SDK управляет встроенным плеером и проверяет данные на границе web/native. Приложение принимает типизированные действия поставленного пакета и не создаёт отдельный message transport поверх SDK.

- SDK принимает контент плеера только с согласованных `https` origins и проверяет navigation и сообщения до передачи действия приложению.
- Приложение сопоставляет `feedProductId` со своим каталогом и не строит native route из URL или произвольного payload плеера.
- SDK-owned player удаляется вместе с handlers и delegates при teardown.
- Ошибка или отключение SDK не должны блокировать PDP, navigation, корзину и checkout приложения.

В integration handoff ShopStory передаёт назначенной команде координаты пакета, его точную версию и клиентские routes. Разрешённый player origin задаётся конфигурацией ShopStory: SDK получает непрозрачный HTTPS player URL и проверяет его exact origin. Host app не настраивает отдельный WebView allowlist. Публичный контракт и правила приёмки описаны в разделе [Mobile SDK](<https://docs.shopstory.live/docs/guide/mobile-sdk>).

## Модерация чата и мобильный выпуск

Если сайт или приложение показывает сообщения зрителей, включите чат в согласование поставки и приёмку. WebView внутри SDK не отменяет требования к пользовательскому контенту (UGC) в итоговом приложении.

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

### Ответственность и подготовка

- **ShopStory** отвечает за механизмы плеера и сервиса: фильтрацию, жалобы, персональные блокировки, действия модератора, проверку его полномочий и сохранение решений. Исправления этих механизмов остаются ответственностью ShopStory.
- **Команда ритейлера** согласует правила и модель идентификации зрителя, обеспечивает доступность сценариев на сайте или в приложении и принимает интеграцию вместе с ShopStory. Submission приложения остаётся ответственностью его издателя.
- **Назначенный оператор** рассматривает обращения, применяет правила и передаёт сложные случаи ответственному. До запуска фиксируются его права, доступный пользователю контакт, часы работы, время реакции и порядок эскалации.

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

### Работа оператора

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

Жалоба сама по себе не удаляет сообщение и не блокирует автора. Персональная блокировка скрывает автора только для выбравшего её зрителя; ограничение модератора действует в согласованной области. Перед запуском ShopStory передаёт инструкцию по интерфейсу выбранной версии, а оператор проходит тестовую жалобу от поступления до закрытия.

### Матрица готовности чата

| Механизм | Ожидаемый результат | Проверка |
| --- | --- | --- |
| Правила и принятие условий | [Правила чата](<https://shopstory.live/chatrules>) доступны до первой отправки. Зритель принимает условия; принятая редакция сохраняется. | До принятия отправка недоступна, после — работает. Подтверждается нужная редакция; порядок повторного принятия при изменении правил согласован. |
| Фильтрация до публикации | Недопустимое сообщение не показывается другим зрителям. Автор получает понятное объяснение отказа. | Допустимый текст появляется, запрещённый не виден в live, истории и при просмотре записи. |
| Недоступность фильтра | Без решения сообщение не публикуется. Автор видит состояние проверки или ошибку; видео продолжает работать. | Задержка и сбой проверки не пропускают сообщение. Восстановление проверки и повтор отправки не создают дубли. |
| Жалоба на сообщение или автора | Оба действия доступны в чате. Обращение сохраняется с нужным контекстом, поступает оператору; зритель видит подтверждение приёма либо ошибку. | Проверены оба вида жалоб, сбой связи и повтор без потери или дубля. Оператор рассматривает обращение и сохраняет результат в согласованное время. |
| Персональная блокировка и разблокировка | Зритель скрывает старые и новые сообщения автора для себя в согласованной области и может отменить это действие. | Блокировка сохраняется после повторного входа и при просмотре записи, не меняет чат другого зрителя. Разблокировка не возвращает удалённые модератором сообщения. |
| Полномочия модератора | Уполномоченный оператор удаляет сообщение, ограничивает отправку нарушителем и снимает ограничение в своём проекте. Сервис проверяет права при каждом действии. | Действия разрешены нужной роли и недоступны пользователю без прав. Удаление, запрет отправки и его снятие дают ожидаемый результат; действия записаны в журнал. |
| Сохранение решений | Жалобы, ограничения и статус удалённых сообщений сохраняются на стороне сервиса. Live, история и запись применяют действующие ограничения видимости. | Повторный вход и восстановление сервиса в тестовой среде не отменяют решения. Удалённое сообщение не появляется вновь при загрузке истории или записи. |

### Приёмка выбранной версии

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

Проверьте правила, контакт, жалобу, блокировку и разблокировку в конечном интерфейсе на целевых устройствах, включая VoiceOver и TalkBack для соответствующих мобильных платформ. Возврат из этих интерфейсов не должен нарушать просмотр. Измерьте задержку и ошибки на согласованной нагрузке: отдельный успешный тест фильтра не доказывает пропускную способность всего чата.

Перед выпуском сверяйте требования [Apple к UGC](<https://developer.apple.com/app-store/review/guidelines/#user-generated-content>) и [Google Play к UGC](<https://support.google.com/googleplay/android-developer/answer/9876937?hl=en>). Документация и checklist не гарантируют одобрение итогового приложения магазином.

## Кэш и повторы

- Разделяйте записи кэша по приложению и всем параметрам ответа.
- Не помещайте ответы с авторизацией, персонализацией или изменением корзины в общий кэш.
- Не считайте stale каталог подтверждением текущего остатка.
- Повторяйте автоматически только безопасные read-only запросы.
- Соблюдайте `Retry-After`, ограничивайте общую продолжительность запросов и добавляйте jitter.

Подробнее: [Кэширование](<https://docs.shopstory.live/docs/operations/caching>) и [Rate limiting](<https://docs.shopstory.live/docs/operations/rate-limits>).

## Логи и диагностика

Для диагностики записывайте endpoint без полного query string, HTTP status, business status, duration и собственный correlation ID.

Не записывайте:

- cookies и CSRF-токены;
- `Authorization`;
- тело запроса на изменение корзины;
- персональные данные покупателя;
- полный payload мобильного действия без удаления чувствительных полей;
- внутренний ответ merchant API.

Задайте срок хранения диагностических данных и ограничьте доступ к ним.

## Проверка перед запуском в production

- Тестовая и production-среда используют разные назначенные конфигурации.
- В URL и frontend bundle нет учётных данных.
- Product IDs обрабатываются как строки.
- Клиент проверяет HTTP status и JSON-конверт ответа API.
- CSP проверена сначала в Report-Only.
- Endpoint корзины защищён сессией, CSRF и server-side validation.
- Интерфейс корзины сообщает об успехе только после подтверждения merchant API.
- Для mobile action состояние плеера и аналитическое событие не подтверждают изменение корзины.
- WebView ограничен trusted origin и main frame.
- Логи не содержат учётных данных и персональных данных.
- Интеграция корректно обрабатывает timeout, `429`, `5xx` и деградированный режим.

## Сообщить об уязвимости

Не публикуйте детали в открытом issue. Отправьте описание, влияние, безопасные шаги воспроизведения и контакт для ответа на [security@shopstory.live](<mailto:security@shopstory.live>). Не прикладывайте реальные учётные данные и персональные данные. Передавать чувствительные данные можно только по заранее согласованному безопасному каналу.

Публичного SLA по сроку ответа нет.

Справочные материалы: [OWASP API Security Top 10](<https://owasp.org/www-project-api-security/>) и [OWASP Mobile Application Security](<https://mas.owasp.org/>).
