Перед приёмом настоящих платежей
Checkout kit проводит шаги оплаты для разных провайдеров и разных видов приложений. Он полезен, когда приложению нужны повторы, проверка банком (3DS), перенаправления, восстановление после перезагрузки или единый интерфейс для нескольких провайдеров. Начните с core, одного пакета провайдера и runtime для своего приложения. React и UI — по желанию.
Если нужна только готовая платёжная страница одного провайдера без особой логики, может хватить решения самого провайдера.
Про версии. Пакеты npm @checkout-kit/core@0.2.0, @checkout-kit/runtime-browser@0.2.0 и @checkout-kit/provider-adyen@0.2.0 включают описанные здесь защитные настройки и телеметрию. См. установку из npm. Старый комплект архивов GitHub 0.2.0 содержит более ранние пакеты без этих изменений.
Что делает библиотека и что должны сделать вы
| Область | Что делает checkout kit | Что должно сделать ваше приложение |
|---|---|---|
| Шаги оплаты | Создание, подтверждение, доп. шаги, обработка, отмена и восстановление. | Решить, когда списываются деньги. Не допускать на сервере конфликтующих платежей по одному заказу. |
| Ввод платёжных данных | Адаптеры SDK, раннеры для полей карты провайдера, необязательные UI-компоненты. | Использовать поля или SDK провайдера. Общая форма карты увеличивает ваши обязанности по PCI. |
| Повторы | Сохраняет ключ попытки после прерванного запроса; связывает каждый шаг с его платежом. | Хранить записи идемпотентности в базе, атомарно, для каждой пары покупатель-заказ-операция. |
| Результат оплаты | Читает состояние с вашего сервера и превращает его в результат. | Проверять уведомления провайдера и сверять платежи, даже если браузер закрыт. |
| Адреса в браузере | Проверка HTTPS, правила для origin, защищённая загрузка скриптов SDK. | Указать адреса провайдера и CSP для своего аккаунта и окружения. |
| Эксплуатация | Безопасные метрики и готовые тесты контракта. | Мониторинг, выдача заказа после подтверждённой оплаты, разбор инцидентов, проверка в песочнице. |
Библиотека — это не:
- платёжный процессинг;
- эскроу-сервис;
- система защиты от мошенничества;
- сертификация PCI.
Адаптеры Stripe, Adyen и PayPal покрыты тестовыми данными и локальным симулятором. Это не значит, что их полностью проверили на настоящем тестовом аккаунте. Шесть общих пакетов протоколов — только примеры.
Безопасная настройка браузера
import { createBrowserRuntime } from '@checkout-kit/runtime-browser'
const runtime = createBrowserRuntime({
returnPath: '/checkout/return',
security: {
frameOrigins: ['https://fields.your-provider.example'],
scriptOrigins: [], // Import the official SDK in your host; no action may load a script.
imageOrigins: ['https://images.your-provider.example'],
deeplinkProtocols: ['yourbank:'], // Only when your actual bank integration needs this.
},
})Домены выше — только пример. Берите адреса из документации своего провайдера для своего аккаунта.
Как работают списки:
frameOrigins,scriptOrigins,imageOriginsиdeeplinkProtocolsперечисляют то, что разрешено. Пустой список запрещает всё этого вида.redirectOriginsпозволяет ограничить перенаправления точными origin. Если его не указать, разрешено любое перенаправление по HTTPS, потому что страницы 3DS разных банков находятся на множестве разных доменов.- Нет ни масок (
*), ни проверки «заканчивается на». Каждая запись — один точный origin. - Разрешая origin, вы разрешаете все пути на нём. Не разрешайте origin, куда пользователи могут загружать свои скрипты.
Что запрещено по умолчанию:
- адреса без HTTPS;
- логин и пароль внутри адреса;
- исполняемые схемы вроде
javascript:; - скрипты SDK, которые шаг пытается загрузить с адреса не из вашего списка;
- ссылки на приложения со своей схемой, которой нет в вашем списке.
Кроме того:
- адрес возврата должен принадлежать вашему сайту;
- сообщения из фреймов проверяются по origin, типу сообщения, id шага и отправителю;
- для полей провайдера адрес фрейма и origin сообщения должны совпадать;
- если проверка не прошла, шаг завершается с
aborted/runner_errorдо того, как что-либо будет открыто или показано; allowInsecureLocalhost: true— только для локальной разработки. Разрешает обычный HTTP только для адресовlocalhost.
Про скрипты: лучше подключать SDK провайдера как пакет. Если используете scriptUrl из шага, добавьте его точный origin в scriptOrigins и укажите хеш integrity, если у SDK есть фиксированные версии. Следуйте актуальным рекомендациям провайдера по CSP.
Фрейм с вашего же origin, у которого одновременно есть allow-scripts и allow-same-origin, ничего не изолирует: код внутри может добраться до вашей страницы. Все эти проверки в браузере дополняют проверки на сервере, но не заменяют их. Они не защитят сервер, который уже взломан.
Не пропускайте данные карты через своё приложение
- Stripe принимает токены PaymentMethod.
- Adyen принимает зашифрованный
state.dataиз Adyen Web или сохранённый способ оплаты. Данные карты в открытом виде (инструментcardилиnumber/cvcвнутри данных компонента) отклоняются, если не указатьallowRawCardData: true. Этот флаг не делает вас соответствующим PCI. Пример сервера всегда отклоняет данные карты в открытом виде. - Общий UI карты и адаптеры-примеры намеренно работают с полями карты. Используйте их, только когда вы определили, какие требования по соответствию применимы к вашему бизнесу, и проверили их выполнение.
Никогда не отправляйте в аналитику, логи, обращения в поддержку и хранилища:
- номер карты (PAN) и CVC;
- токены кошельков;
- клиентские секреты;
- параметры шагов;
- полные адреса возврата.
Низкоуровневые события движка содержат данные провайдера. Для метрик используйте безопасную телеметрию, а не сохраняйте сами события.
В хранилище для восстановления лежат только провайдер, id платежа, id шага, ключ попытки и время. Считайте эти данные недоверенными: сервер всё равно должен проверить, кому принадлежит платёж, не истёк ли он и относится ли шаг к этому платежу.
Если результат неясен — так и считайте
| Ситуация | Что делать дальше |
|---|---|
| Потерялся ответ на «создать» или «подтвердить» | Оставьте тот же ключ попытки. Прочитайте существующий платёж и сравните. |
| Сервер сообщает «в обработке» | Продолжайте проверять статус. Не создавайте второй платёж по этому заказу. |
Адрес возврата содержит success или SDK сообщил «готово» | Проверьте через API своего сервера, где пользователь авторизован. |
Покупатель отменил или вы вызвали reset() | Проверьте, не списал ли провайдер деньги. Локальный сброс не отменяет списание. |
| Явный отказ, и покупатель выбирает другой способ | Начните новую попытку по правилам вашего сервера для этого заказа. |
Никогда не повторяйте запрос, который двигает деньги, с новым ключом только потому, что истекло время ожидания. Память браузера не может согласовать несколько вкладок, устройств или серверных процессов. Ваш сервер должен гарантировать, что каждый заказ оплачивается только один раз, и хранить ключи и результаты в базе данных.
Чек-лист для сервера
- Авторизуйте покупателей. При каждом чтении, изменении и выдаче чека проверяйте, что заказ принадлежит этому покупателю.
- Берите цену, валюту, покупателя, аккаунт провайдера и адрес возврата из данных сервера, а не из браузера.
- Используйте HTTPS, защищённые cookie сессии, понятную политику CSRF и короткий список разрешённых CORS-источников.
- Проверяйте подлинность вебхуков по правилам SDK провайдера (часто нужно исходное тело запроса). Проверяйте аккаунт, заказ, сумму, валюту и состояние списания. Храните события в базе, пропускайте дубликаты и обрабатывайте события, пришедшие не по порядку.
- Выдавайте заказ один раз — по подтверждённому статусу на сервере. Экран «успешно» нужен только для показа и навигации.
- На настоящем тестовом аккаунте проверьте: отказы, перенаправления и 3DS, прерванные запросы, обработку, двойные нажатия, параллельные сессии, данные от другого заказа, неверные подписи и сбои провайдера. Запишите провайдера, версию SDK/API, режим списания и дату проверки.
Пример сервера хранит записи в памяти и использует демонстрационную cookie сессии. Замените и то и другое перед развёртыванием. Пример проверяет уведомления Adyen. Боевые уведомления Stripe и PayPal и надёжная выдача заказа — ваша задача, в примере их нет.
Перед публичным релизом
- Запустите описанные тесты, проверки установки пакетов, тесты навигации по сайту и
release:npm-check. - Устраните предупреждения безопасности в зависимостях поставляемых пакетов.
- Примените ожидающие changesets, выберите версию комплекта и запишите результат проверки на тестовом аккаунте.
Только после этого называйте интеграцию готовой к работе. Пакеты уже доступны в npm, но установка не проверяет ваш аккаунт провайдера. В Releasing описаны публикация следующих версий и OIDC.
Безопасность Stripe PaymentIntents · Безопасность интеграции Adyen Web · Политика безопасности