Тема
Карточные данные и токены
Номер карты, срок действия и код проверки — это те самые данные, ради которых существует PCI DSS. Чем больше сервисов их видит, тем шире область аудита и тем дороже любая ошибка. Поэтому в системе действует простое правило: настоящую карту знают только PCI-шлюз и сервис токенизации, а все остальные работают с токенами — случайными идентификаторами, по которым карту можно запросить обратно.
Два разных токена
Шлюз меняет карту не на один идентификатор, а сразу на несколько, и путать их нельзя: у них разное время жизни и разное содержимое.
| Что это | Что внутри | Где лежит | Сколько живёт |
|---|---|---|---|
| Токен карты | Номер и срок действия | Основная база сервиса токенизации | Постоянно |
| Токен сессии | Номер, срок, код проверки, имя держателя | Redis | Около часа |
Токен карты постоянный. На одну и ту же карту сервис всегда возвращает один и тот же идентификатор: перед созданием записи он ищет существующую по хэшу карты. Благодаря этому карту можно узнать между платежами — на этом держатся рекуррентные списания, сохранённые на нашей форме карты и поиск всех операций по одной карте. Токенов карты на самом деле два: один считается по номеру со сроком действия, второй — только по номеру. Второй нужен там, где карту надо узнать независимо от перевыпуска с новым сроком.
Токен сессии временный. Это зашифрованная строка с полными данными карты, включая код проверки и имя держателя, положенная в Redis с ограниченным сроком жизни. Срок задаёт вызывающий, но сверху он ограничен настройкой самого сервиса, так что бесконечную сессию завести нельзя.
И карта, и сессия шифруются ключом AWS KMS: в хранилищах лежит только шифртекст, ключа там нет. Хэш, по которому ищется дубликат карты, тоже вычисляется ключом KMS, а не обычной хэш-функцией, — подобрать по нему номер перебором не выйдет.
Почему код проверки не хранится
Код проверки (CVV) нельзя хранить после проведения операции — это прямое требование платёжных систем, и именно оно объясняет, зачем понадобилась сессия. Банку код нужен ровно один раз, в момент авторизации, а значит достаточно подержать его несколько минут и забыть. Поэтому код живёт только внутри временной сессии и исчезает вместе с ней; в постоянной записи о карте его нет и быть не может.
Практическое следствие: если платёж завис и вы решили повторить его через час, сессии уже не существует. Для выплаты это не помеха — там достаточно номера, и сессию собирают заново из постоянного токена. А там, где банк требует код проверки, повторить платёж не выйдет: карту запрашивают у плательщика заново.
Токен обратим, и это не анонимизация
Внешняя документация для мерчанта говорит, что токен необратим. Для мерчанта это правда: обменять токен на карту он не может. Внутри системы всё наоборот — детокенизация штатная операция, без которой платёж не провести.
Данные обратно запрашивают в нескольких случаях. Ядро достаёт содержимое сессии перед тем, как отправить платёж в банк, и отдаёт его драйверу. Драйвер получает карту, когда банк требует реквизиты в своём формате. Выплаты и повторы зависших операций восстанавливают карту по постоянному токену. Бэкофис показывает полный номер, когда сотрудник разбирает инцидент, — но только тем, у кого есть отдельное право доступа, и каждый такой просмотр записывается в журнал действий. Наконец, есть режим, когда нужен не номер, а только его вид: сервис отдаёт маскированную строку, в которой видны первые и последние цифры.
Отсюда главное правило чтения кода: токен равносилен карте. Он не обезличивает плательщика и не выводит данные из области PCI, он лишь сужает круг тех, кто видит номер. Токен в выгрузке, в тикете или в сообщении в чате — это утечка, а не безобидный идентификатор.
Как сервис понимает, что пришёл свой
Сервис токенизации не смотрит наружу: к нему обращаются только наши сервисы, и каждый запрос подписан. Подпись вычисляется ключом AWS KMS, а проверяется тем же ключом на стороне сервиса — значит, подписать запрос может лишь тот, кому выдан доступ к ключу. В теле обязателен штамп времени, и если он расходится с текущим больше чем на несколько секунд, запрос отклоняется: перехваченный запрос нельзя отправить повторно.
Проверяется только это. Сервис не разбирает, кто и зачем спрашивает карту, и не знает ничего про транзакции и статусы. Ограничение доступа к ключу — и есть вся модель доверия, поэтому обращение к токенизации из нового сервиса решается не кодом, а выдачей доступа.
Что это значит для разработчика
- Не пишите в логи номер карты и код проверки. PCI-шлюз маскирует их в своих логах сам, но как только вы достали карту детокенизацией, ответственность ваша: любой отладочный вывод рискует уехать в общее хранилище логов.
- Не передавайте карту туда, где её раньше не было. Антифрод, аналитика, уведомления, очереди, тела ошибок, сторонние SDK — всё это работает с токеном и маскированным номером, и так и должно остаться.
- Не складывайте карточные данные в свои таблицы и кэши, даже временно. Единственное место, где им положено лежать, уже существует.
- Новый сценарий, в котором появляется настоящая карта, живёт в PCI-контуре — в шлюзе для карточных данных, а не в ядре и не в обычном merchant API. Почему так — в Почему шлюзов несколько.
- Детокенизация — не бесплатная операция: это поход в соседний сервис и в KMS. Запрашивайте карту там, где она нужна, и не носите её по коду дальше.
Куда дальше
- Платёж картой server-to-server — где в потоке происходит обмен карты на токены.
- Сервис токенизации — зона ответственности, входы и хранилища.
- Выплаты и рекуррентные платежи — сценарии, где карта достаётся обратно по сохранённому токену.