Работа с подписью к данным
Общая информация
Для обеспечения защищённого обмена данными при работе с платёжной платформой ecommpay используется криптографический протокол TLS (Transport Layer Security; протокол защиты транспортного уровня) версии не ниже 1.2, а для подтверждения авторства и целостности передаваемых данных дополнительно применяется цифровая подпись. Она формируется и проверяется по заданным алгоритмам с использованием одинакового секретного ключа, доступного на двух сторонах: мерчанта и ecommpay.
Независимо от интерфейса, используемого для работы с платформой, подпись обязательна к включению в состав всех программных запросов и оповещений (по запросам, выполняемым в рамках асинхронной схемы взаимодействия), а также выборочно применяется для ответов (по запросам, выполняемым в рамках синхронной схемы). Без подписи могут оставаться ответы с исключительно служебной информацией (например, об отклонении запроса из-за его некорректности) или с информацией общего характера, не раскрывающей специфику конкретного платежа или данные пользователя (например, в ответе со списком доступных банков). В остальных случаях подпись включается в состав ответов.
Для корректной работы перед отправкой в платформу любого запроса необходимо сформировать подпись и включить её в состав этого запроса, а при получении от платформы оповещений и ответов, содержащих подпись, следует проверять целостность данных путём сличения расчётных подписей с полученными. Для этого можно использовать как собственные программные решения, так и SDK от ecommpay (подробнее). Нарушения целостности данных могут быть вызваны разными причинами, но при обнаружении таких нарушений данные не могут и не должны считаться достоверными.
Далее описаны алгоритмы подписывания данных и проверки их целостности, а также представлены примеры выполнения этих алгоритмов и интерактивные формы для самостоятельной проверки корректной работы с подписью к разным данным.
Подписывание данных
Описание алгоритма
В качестве входных данных для подписывания выступают:
- Данные, которые требуется подписать.
Как правило, это все параметры запроса за исключением подписи или JavaScript-объект configObj с параметрами без включения параметра
signature
. - Ключ, используемый для подписывания.
Для отладки и тестирования алгоритма подписывания могут использоваться произвольные ключи. Для рабочих запросов в платформу следует применять только актуальный секретный ключ
В качестве выходных данных подписывания в зависимости от реализации алгоритма могут выступать либо подпись, либо подписанный JavaScript-объект configObj — как правило, это итоговый объект с параметром signature
, включённым в его состав.
Далее в описании, примере и форме для тестирования представлен часто используемый и наиболее показательный вариант реализации алгоритма: с JavaScript-объектом configObj на входе (без параметра signature
) и на выходе (с параметром signature
).
Пример для запроса на оплату через Payment Page
Допустим, что надо подписать запрос на открытие Payment Page при следующих условиях:
- Используемый ключ —
secret
- Предварительная версия объекта configObj, в котором еще нет значения параметра с подписью, выглядит так:
{ "project_id": 12345, "payment_id": "X03936", "payment_amount": 2035, "payment_currency": "USD", "payment_description": "Guyliner purchase", "customer_first_name": "Jack", "customer_id": "user007", "customer_last_name": "Sparrow", "customer_phone": "02081234567", "close_on_missclick": true, "signature": "<подпись, которую нужно создать>" }
Задача заключается в том, чтобы вычислить подпись, то есть определить значение параметра signature
. Для этого необходимо:
- Убедиться, что в теле запроса нет параметра
signature
, даже с пустым значением. Если такой параметр есть, его нужно удалить:{ "project_id": 12345, "payment_id": "X03936", "payment_amount": 2035, "payment_currency": "USD", "payment_description": "Guyliner purchase", "customer_first_name": "Jack", "customer_id": "user007", "customer_last_name": "Sparrow", "customer_phone": "02081234567", "close_on_missclick": true, "signature": "<подпись, которую нужно создать>" }
- Преобразовать оставшиеся параметры в строки UTF-8 согласно правилам алгоритма:
project_id:12345 payment_id:X03936 payment_amount:2035 payment_currency:USD payment_description:Guyliner purchase customer_first_name:Jack customer_id:user007 customer_last_name:Sparrow customer_phone:02081234567 close_on_missclick:1
- Отсортировать полученные строки в естественном порядке:
close_on_missclick:1 customer_first_name:Jack customer_id:user007 customer_last_name:Sparrow customer_phone:02081234567 payment_amount:2035 payment_currency:USD payment_description:Guyliner purchase payment_id:X03936 project_id:12345
- Объединить отсортированные строки в одну строку с использованием в качестве разделителя точки с запятой:
close_on_missclick:1;customer_first_name:Jack;customer_id:user007;customer_last_name:Sparrow;customer_phone:02081234567;payment_amount:2035;payment_currency:USD;payment_description:Guyliner purchase;payment_id:X03936;project_id:12345
- Вычислить HMAC полученной строки с использованием функции хеширования SHA-512 и используемого ключа, после чего кодировать двоичный код HMAC с применением алгоритма Base64:
SyA3cx/dmFrwjRcpbnwEK9zaklWKR9buIfTctQob/EHUTutFLpI0zWpSDFEWEwbZt/04i83395RCdEhtUMw83A==
- Добавить полученную подпись в объект configObj:
{ "project_id": 12345, "payment_id": "X03936", "payment_amount": 2035, "payment_currency": "USD", "payment_description": "Guyliner purchase", "customer_first_name": "Jack", "customer_id": "user007", "customer_last_name": "Sparrow", "customer_phone": "02081234567", "close_on_missclick": true, "signature": "SyA3cx/dmFrwjRcpbnwEK9zaklWKR9buIfTctQob/EHUTutFLpI0zWpSDFEWEwbZt/04i83395RCdEhtUMw83A==" }
Форма для тестирования
Для корректной работы с параметрами реальных запросов следует учитывать требования к кодированию вложенных объектов, представленные в статье Параметры вызова платёжной формы и в статьях с описанием возможностей платёжной формы. При указании вложенных объектов, не соответствующих таким требованиям, подпись в форме тестирования рассчитывается в соответствии с алгоритмом, но не может использоваться для реальных запросов, поскольку оказывается сформированной на некорректных входных данных.
Проверка данных
Описание алгоритма
В качестве входных данных для проверки целостности выступают:
- Подписанные данные, которые требуется проверить. Как правило, это тело оповещения или ответа в формате JSON с параметром
signature
в его составе. - Ключ, используемый для проверки. Это должен быть ровно тот ключ, который был использован для подписывания проверяемых данных.
В качестве выходных данных при проверке целостности в зависимости от реализации алгоритма могут выступать расчётная подпись и информация о её совпадении с проверяемой подписью, то есть информация о целостности проверяемых данных.
Далее в описании, примере и форме для тестирования представлен часто используемый и наиболее показательный вариант реализации алгоритма: с телом проверяемого сообщения (оповещения или ответа) в формате JSON на входе и с заключением о целостности этого сообщения на выходе.
В состав алгоритма в этом случае включаются следующие шаги:
Пример для оповещения
Допустим, что надо проверить подпись оповещения при следующих условиях:
- Используемый ключ —
secret
- Тело полученного оповещения выглядит так:
Для проверки подписи необходимо:
- Удалить из тела оповещения параметр
signature
вместе с его значением.{ "customer": { "id": "782572" }, "account": { "number": "424242******4242", "token": "c8175453f68ec7c8fb3f052b8d786c661261efebcb91155327a6c7b8f8e66359", "type": "visa", "card_holder": "TEST TEST", "expiry_month": "01", "expiry_year": "2025" }, "project_id": 28051, "payment": { "id": "5242723", "type": "purchase", "status": "success", "date": "2023-03-10T12:26:17+0000", "method": "card", "sum": { "amount": 5200, "currency": "EUR" }, "description": "" }, "operation": { "sum_initial": { "amount": 5200, "currency": "EUR" }, "sum_converted": { "amount": 5200, "currency": "EUR" }, "code": "0", "message": "Success", "provider": { "id": 6, "payment_id": "16784511766816", "auth_code": "563253", "endpoint_id": 6, "date": "2023-03-10T10:26:17+0000" }, "id": 5028800010128225, "type": "sale", "status": "success", "date": "2023-03-10T12:26:17+0000", "created_date": "2023-03-10T12:26:15+0000", "request_id": "1f6d3ac37444142f5bd27e7491faa360633fd5a2-fc98e73d475fa4cd6ee02fc6340c964f0267b3d8-05028801" }, "signature": "IszjSnH+UqFp88DF0giI/jUTDHOnfPxc83j2VD/jN4loB9wbHwiO5+KvHfdFE4nBPHhhxD6TXbOkGnRINFTTmg==" }
- Преобразовать оставшиеся параметры в строки UTF-8 согласно правилам алгоритма.
customer:id:782572 account:number:424242******4242 account:token:c8175453f68ec7c8fb3f052b8d786c661261efebcb91155327a6c7b8f8e66359 account:type:visa account:card_holder:TEST TEST account:expiry_month:01 account:expiry_year:2025 project_id:28051 payment:id:5242723 payment:type:purchase payment:status:success payment:date:2023-03-10T12:26:17+0000 payment:method:card payment:sum:amount:5200 payment:sum:currency:EUR payment:description: operation:sum_initial:amount:5200 operation:sum_initial:currency:EUR operation:sum_converted:amount:5200 operation:sum_converted:currency:EUR operation:code:0 operation:message:Success operation:provider:id:6 operation:provider:payment_id:16784511766816 operation:provider:auth_code:563253 operation:provider:endpoint_id:6 operation:provider:date:2023-03-10T10:26:17+0000 operation:id:5028800010128225 operation:type:sale operation:status:success operation:date:2023-03-10T12:26:17+0000 operation:created_date:2023-03-10T12:26:15+0000 operation:request_id:1f6d3ac37444142f5bd27e7491faa360633fd5a2-fc98e73d475fa4cd6ee02fc6340c964f0267b3d8-05028801
- Отсортировать полученные строки в естественном порядке.
account:card_holder:TEST TEST account:expiry_month:01 account:expiry_year:2025 account:number:424242******4242 account:token:c8175453f68ec7c8fb3f052b8d786c661261efebcb91155327a6c7b8f8e66359 account:type:visa customer:id:782572 operation:code:0 operation:created_date:2023-03-10T12:26:15+0000 operation:date:2023-03-10T12:26:17+0000 operation:id:5028800010128225 operation:message:Success operation:provider:auth_code:563253 operation:provider:date:2023-03-10T10:26:17+0000 operation:provider:endpoint_id:6 operation:provider:id:6 operation:provider:payment_id:16784511766816 operation:request_id:1f6d3ac37444142f5bd27e7491faa360633fd5a2-fc98e73d475fa4cd6ee02fc6340c964f0267b3d8-05028801 operation:status:success operation:sum_converted:amount:5200 operation:sum_converted:currency:EUR operation:sum_initial:amount:5200 operation:sum_initial:currency:EUR operation:type:sale payment:date:2023-03-10T12:26:17+0000 payment:description: payment:id:5242723 payment:method:card payment:status:success payment:sum:amount:5200 payment:sum:currency:EUR payment:type:purchase project_id:28051
- Объединить отсортированные строки в одну строку с использованием в качестве разделителя точки с запятой.
account:card_holder:TEST TEST;account:expiry_month:01;account:expiry_year:2025;account:number:424242******4242;account:token:c8175453f68ec7c8fb3f052b8d786c661261efebcb91155327a6c7b8f8e66359;account:type:visa;customer:id:782572;operation:code:0;operation:created_date:2023-03-10T12:26:15+0000;operation:date:2023-03-10T12:26:17+0000;operation:id:5028800010128225;operation:message:Success;operation:provider:auth_code:563253;operation:provider:date:2023-03-10T10:26:17+0000;operation:provider:endpoint_id:6;operation:provider:id:6;operation:provider:payment_id:16784511766816;operation:request_id:1f6d3ac37444142f5bd27e7491faa360633fd5a2-fc98e73d475fa4cd6ee02fc6340c964f0267b3d8-05028801;operation:status:success;operation:sum_converted:amount:5200;operation:sum_converted:currency:EUR;operation:sum_initial:amount:5200;operation:sum_initial:currency:EUR;operation:type:sale;payment:date:2023-03-10T12:26:17+0000;payment:description:;payment:id:5242723;payment:method:card;payment:status:success;payment:sum:amount:5200;payment:sum:currency:EUR;payment:type:purchase;project_id:28051
- Вычислить HMAC полученной строки с использованием функции хеширования SHA-512 и используемого ключа, после чего кодировать двоичный код HMAC с применением алгоритма Base64.
Y0qjN9dDnPTdddkVvXKS1pGp2z8ZpIl60P1CocND3YRxuBNx05ZMnhUaGFt90fPzgwsI/UpLw0q2RR/XTiDQBg==
- Сравнить полученную подпись с проверяемой.
В данном случае подписи не совпадают, а это значит, что такое оповещение недостоверно или ошибочно и должно быть отброшено.
Форма для тестирования