Подписывание и проверка подписи
Общая информация
Для обеспечения защищенного обмена данными при работе с платежной платформой Rocketpay используется криптографический протокол TLS (Transport Layer Security; протокол защиты транспортного уровня) версии не ниже 1.2, а для подтверждения авторства и целостности передаваемых данных дополнительно применяется цифровая подпись. Она формируется и проверяется по заданным алгоритмам с использованием одинакового секретного ключа, доступного на двух сторонах: мерчанта и Rocketpay.
Далее описаны алгоритмы подписывания данных и проверки их целостности, а также представлены примеры выполнения этих алгоритмов.
Подписывание запроса
Описание алгоритма
В качестве входных данных для подписывания выступают:
- Данные запроса, которые требуется подписать.
Как правило, это все параметры тела запроса за исключением подписи или JavaScript-объект configObj с параметрами без включения параметра
signature
. - Ключ, используемый для подписывания.
Для отладки и тестирования алгоритма подписывания могут использоваться произвольные ключи. Для рабочих запросов в платформу следует применять только актуальный секретный ключ, полученный от службы поддержки Rocketpay.
В качестве выходных данных подписывания в зависимости от реализации алгоритма могут выступать либо подпись, либо подписанный JavaScript-объект configObj — как правило, это итоговый объект с параметром signature
, включенным в его состав.
Далее в описании, примере и форме для тестирования представлен часто используемый и наиболее показательный вариант реализации алгоритма: с JavaScript-объектом configObj на входе (без параметра signature
) и на выходе (с параметром signature
).
Рис.: Как рассчитать подпись
- Убедитесь что входные данные удовлетворяют следующим требованиям:
- Структура данных для подписывания соответствует формату JavaScript-объектов.
- В составе данных для подписывания нет параметра
signature
(даже с пустым значением). - Известен ключ для подписывания.
- Преобразуйте данные в строку в формате UTF-8 и отсортируйте параметры по алфавиту. В рамках этого шага:
- Логические (булевы) значения кодируются следующим образом:
false
заменяется на0
, аtrue
— на1
.Но это относится только к булевым значениям: в строковых параметрах, даже если они содержат значения
false
илиtrue
, замены на0
или1
не используются! - Параметры с нулевыми, а также пустыми значениями остаются в строке, например запись
"payment_description":""
представляется в видеpayment_description:
. Замены пустых значений на пробелы илиnull
не применяются. - Кодировка всех строк приводится к формату UTF-8.
- Полученные строки упорядочиваются в алфавитном порядке и объединяются в одну строку с использованием в качестве разделителя точки с запятой (;).
- Логические (булевы) значения кодируются следующим образом:
- Рассчитайте двоичный код HMAC с использованием ключа и функции SHA-512. На этом шаге для полученной строки с параметрами вычисляется HMAC (Hash-based Message Authentication Code; код аутентификации сообщений с использованием хеш-функции) с использованием функции хеширования SHA‑512 (Secure Hash Algorithm; безопасный алгоритм хеширования) и применяемого ключа. И этот HMAC представляется в виде необработанных двоичных данных.
- Закодируйте двоичный код HMAC с применением алгоритма Base64. На этом шаге полученный двоичный код HMAC кодируется с использованием алгоритма Base64. Получаемая при этом строка является подписью к исходным данным.
- Добавьте подпись в данные. На этом шаге к исходным данным для подписывания добавляется параметр
signature
с полученной подписью в качестве его значения.
Пример для запроса на оплату через Payment Page
Допустим, что надо подписать запрос на открытие Payment Page при следующих условиях:
- Ключ для подписывания —
secret
- Предварительная версия объекта configObj, в котором еще нет значения параметра с подписью, выглядит так:
{ "project_id": 12345, "payment_id": "X03936", "payment_amount": 2035, "payment_currency": "USD", "payment_description": "Покупка наручных часов", "customer_id": "customer_386", "customer_first_name": "Иван", "customer_last_name": "Иванов", "customer_phone": 74991234567, "close_on_missclick": true, "signature": "<подпись, которую нужно создать>" }
Задача заключается в том, чтобы вычислить подпись, то есть определить значение параметра signature
. Для этого:
- Убедитесь, что в теле запроса нет параметра
signature
, даже с пустым значением. Если такой параметр есть, его нужно удалить:{ "project_id": 12345, "payment_id": "X03936", "payment_amount": 2035, "payment_currency": "USD", "payment_description": "Покупка наручных часов", "customer_id": "customer_386", "customer_first_name": "Иван", "customer_last_name": "Иванов", "customer_phone": 74991234567, "close_on_missclick": true, "signature": "<подпись, которую нужно создать>" }
- Преобразуйте оставшиеся параметры в строки UTF-8 согласно правилам алгоритма:
project_id:12345 payment_id:X03936 payment_amount:2035 payment_currency:USD payment_description:Покупка наручных часов customer_id:customer_386 customer_first_name:Иван customer_last_name:Иванов customer_phone:74991234567 close_on_missclick:1
- Упорядочите полученные строки по алфавиту:
close_on_missclick:1 customer_first_name:Иван customer_id:customer_173 customer_last_name:Иванов customer_phone:74991234567 payment_amount:2035 payment_currency:USD payment_description:Покупка наручных часов payment_id:X03936 project_id:12345
- Объедините упорядоченные строки в одну строку с использованием в качестве разделителя точки с запятой:
close_on_missclick:1;customer_first_name:Иван;customer_id:customer_386;customer_last_name:Иванов;customer_phone:74991234567;payment_amount:2035;payment_currency:USD;payment_description:Покупка наручных часов;payment_id:X03936;project_id:12345
- Вычислите HMAC полученной строки с использованием функции хеширования SHA-512 и используемого ключа, после чего закодируйте двоичный код HMAC с применением алгоритма Base64:
flchUC07OPucpr8rTFPBpIVfjDh+Vltvo0Gz1YBg/1lYpa3BY8i+QzOaa5gZznlhaQV4oSyEQvGnCqbU9qoThQ==
- Добавьте полученную подпись в объект configObj:
{ "project_id": 12345, "payment_id": "X03936", "payment_amount": 2035, "payment_currency": "USD", "payment_description": "Покупка наручных часов", "customer_id": "customer_386", "customer_first_name": "Иван", "customer_last_name": "Иванов", "customer_phone": 74991234567, "close_on_missclick": true, "signature": "flchUC07OPucpr8rTFPBpIVfjDh+Vltvo0Gz1YBg/1lYpa3BY8i+QzOaa5gZznlhaQV4oSyEQvGnCqbU9qoThQ==" }
Форма для тестирования
Проверка подписи оповещений
Описание алгоритма
В качестве входных данных для проверки целостности выступают:
- Подписанные данные, которые требуется проверить. Как правило, это тело оповещения или ответа в формате JSON с параметром
signature
в его составе. - Ключ, используемый для проверки. Это должен быть ровно тот же ключ, который был использован для подписывания проверяемых данных.
В качестве выходных данных при проверке целостности в зависимости от реализации алгоритма могут выступать расчетная подпись и информация о ее совпадении с проверяемой подписью, то есть информация о целостности проверяемых данных.
Далее в описании, примере и форме для тестирования представлен часто используемый и наиболее показательный вариант реализации алгоритма: с телом проверяемого сообщения (оповещения или ответа) в формате JSON на входе и с заключением о целостности этого сообщения на выходе.
В состав алгоритма в этом случае включаются следующие шаги:
Рис.: Шаги алгоритма проверки данных
- Проверка входных данных на соблюдение заданных требований:
- Структура проверяемых данных должна соответствовать формату JSON.
- В составе проверяемых данных должен присутствовать параметр
signature
с подписью. - Должен быть задан проверочный ключ.
- Извлечение подписи из проверяемых данных На этом шаге из проверяемых данных исключается параметр
signature
, а его значение фиксируется для последующего сличения с расчетной подписью. - Расчет подписи для проверяемых данных:
- Преобразование данных в строку UTF-8 с сортировкой параметров по алфавиту В рамках этого шага выполняются следующие действия:
- Логические (булевы) значения кодируются следующим образом:
false
заменяется на0
, аtrue
— на1
. Но это относится только к булевым значениям: в строковых параметрах, даже если они содержат значенияfalse
илиtrue
, замены на0
или1
не используются! - Каждый параметр преобразуется в строку, содержащую полный путь к параметру, название параметра и его значение:
<родительский_узел_1>:...:<родительский_узел_N>:<название_параметра>:<значение_параметра>
, где родительские узлы — это названия объектов и (или) массивов, в состав которых включена пара «название параметра — значение параметра». Родительские узлы располагаются в порядке их вложения, начиная с самого верхнего уровня. В качестве разделителя при этом используется двоеточие (:), между парами «название параметра — значение параметра» удаляются запятые, а у строковых значений параметров удаляются обрамляющие кавычки. - Параметры с нулевыми, а также пустыми значениями остаются в строке, например запись
"payment_description":""
представляется в видеpayment_description:
. Замены пустых значений на пробелы илиnull
не применяются. - Элементы массивов записываются отдельными строками, с указанием номера каждого элемента, начиная с нуля. Например, массив
["alpha", "beta", "gamma"]
представляется в виде трех строк:0:alpha
,1:beta
и2:gamma
. - Пустые массивы полностью игнорируются и не включаются в набор строк для создания подписи.
- Кодировка всех строк приводится к формату UTF-8.
- Полученные строки упорядочиваются в алфавитном порядке и объединяются в одну строку с использованием в качестве разделителя точки с запятой (;).
- Логические (булевы) значения кодируются следующим образом:
- Получение двоичного кода HMAC с использованием ключа и функции SHA‑512. На этом шаге для полученной строки с параметрами вычисляется HMAC (Hash-based Message Authentication Code; код аутентификации сообщений с использованием хеш-функции) с использованием функции хеширования SHA‑512 (Secure Hash Algorithm; безопасный алгоритм хеширования) и применяемого ключа. И этот HMAC представляется в виде необработанных двоичных данных.
- Кодирование двоичного кода HMAC с применением алгоритма Base64. На этом шаге полученный двоичный код HMAC кодируется с использованием алгоритма Base64. Получаемая при этом строка является подписью к исходным данным.
- Преобразование данных в строку UTF-8 с сортировкой параметров по алфавиту В рамках этого шага выполняются следующие действия:
- Сопоставление подписей. На этом шаге расчетная подпись сопоставляется с проверяемой. Если подписи совпадают, данные признаются целостными и достоверными. При несовпадении подписей данные не могут считаться достоверными и не должны использоваться в качестве рабочих.
Пример для оповещения
Допустим, что надо проверить подпись оповещения при следующих условиях:
- Ключ подписывания —
secret
- Тело полученного оповещения выглядит, как показано в примере.
Рис.: Тело оповещения
{ "customer": { "id": "1" }, "account": { "number": "123456******1234", "token": "f0bdb5741032c19cc8cb2bab92adeec44c5ad56614205feb40348ab92adeec4", "type": "visa", "id": 895819971, "card_holder": "JOHN DOE", "expiry_month": "12", "expiry_year": "2024" }, "project_id": 1124, "payment": { "id": "PAYMENT_585860", "type": "purchase", "status": "success", "date": "2023-05-26T06:43:19+0000", "method": "card", "sum": { "amount": 50000, "currency": "USD" }, "description": "PAYMENT_585860" }, "operation": { "sum_initial": { "amount": 50000, "currency": "USD" }, "sum_converted": { "amount": 50000, "currency": "USD" }, "code": "0", "message": "Success", "eci": "02", "provider": { "id": 13012, "payment_id": "16850833995740", "auth_code": "563253", "endpoint_id": 13012, "date": "2023-05-26T03:43:19+0000" }, "id": 5055919010134089, "type": "sale", "status": "success", "date": "2023-05-26T06:43:19+0000", "created_date": "2023-05-26T06:43:10+0000", "request_id": "123456789" }, "signature": "NtDutuRiksyHeBhhUs+nQxQ1FcMSueoACb4vENju0APgHgeZfRfMj46289v1vD4hJ1a8Yhg==" }
Чтобы проверить подпись:
- Удалите из тела оповещения параметр
signature
вместе с его значением.{ "customer": { "id": "1" }, "account": { "number": "123456******1234", "token": "f0bdb5741032c19cc8cb2bab92adeec44c5ad56614205feb40348ab92adeec4", "type": "visa", "id": 895819971, "card_holder": "JOHN DOE", "expiry_month": "12", "expiry_year": "2024" }, "project_id": 1124, "payment": { "id": "PAYMENT_585860", "type": "purchase", "status": "success", "date": "2023-05-26T06:43:19+0000", "method": "card", "sum": { "amount": 50000, "currency": "USD" }, "description": "PAYMENT_585860" }, "operation": { "sum_initial": { "amount": 50000, "currency": "USD" }, "sum_converted": { "amount": 50000, "currency": "USD" }, "code": "0", "message": "Success", "eci": "02", "provider": { "id": 13012, "payment_id": "16850833995740", "auth_code": "563253", "endpoint_id": 13012, "date": "2023-05-26T03:43:19+0000" }, "id": 5055919010134089, "type": "sale", "status": "success", "date": "2023-05-26T06:43:19+0000", "created_date": "2023-05-26T06:43:10+0000", "request_id": "123456789" }, "signature": "NtDutuRiksyHeBhhUs+nQxQ1FcMSueoACb4vENju0APgHgeZfRfMj46289v1vD4hJ1a8Yhg==" }
- Преобразуйте оставшиеся параметры в строки UTF-8 согласно алгоритму.
customer:id:1 account:number:123456******1234 account:token:f0bdb5741032c19cc8cb2bab92adeec44c5ad56614205feb40348ab92adeec4 account:type:visa account:id:895819971 account:card_holder:JOHN DOE account:expiry_month:12 account:expiry_year:2024 project_id:1124 payment:id:PAYMENT_585860 payment:type:purchase payment:status:success payment:date:2023-05-26T06:43:19+0000 payment:method:card payment:sum:amount:50000 payment:sum:currency:USD payment:description:PAYMENT_585860 operation:sum_initial:amount:50000 operation:sum_initial:currency:USD operation:sum_converted:amount:50000 operation:sum_converted:currency:USD operation:code:0 operation:message:Success operation:eci:02 operation:provider:id:13012 operation:provider:payment_id:16850833995740 operation:provider:auth_code:563253 operation:provider:endpoint_id:13012 operation:provider:date:2023-05-26T03:43:19+0000 operation:id:5055919010134089 operation:type:sale operation:status:success operation:date:2023-05-26T06:43:19+0000 operation:created_date:2023-05-26T06:43:10+0000 operation:request_id:123456789
- Упорядочите полученные строки по алфавиту.
account:card_holder:JOHN DOE account:expiry_month:12 account:expiry_year:2024 account:id:895819971 account:number:123456******1234 account:token:f0bdb5741032c19cc8cb2bab92adeec44c5ad56614205feb40348ab92adeec4 account:type:visa customer:id:1 operation:code:0 operation:created_date:2023-05-26T06:43:10+0000 operation:date:2023-05-26T06:43:19+0000 operation:eci:02 operation:id:5055919010134089 operation:message:Success operation:provider:auth_code:563253 operation:provider:date:2023-05-26T03:43:19+0000 operation:provider:endpoint_id:13012 operation:provider:id:13012 operation:provider:payment_id:16850833995740 operation:request_id:123456789 operation:status:success operation:sum_converted:amount:50000 operation:sum_converted:currency:USD operation:sum_initial:amount:50000 operation:sum_initial:currency:USD operation:type:sale payment:date:2023-05-26T06:43:19+0000 payment:description:PAYMENT_585860 payment:id:PAYMENT_585860 payment:method:card payment:status:success payment:sum:amount:50000 payment:sum:currency:USD payment:type:purchase project_id:1124
- Объедините упорядоченные строки в одну строку с использованием в качестве разделителя точки с запятой.
account:card_holder:JOHN DOE;account:expiry_month:12;account:expiry_year:2024;account:id:895819971;account:number:123456******1234;account:token:f0bdb5741032c19cc8cb2bab92adeec44c5ad56614205feb40348ab92adeec4;account:type:visa;customer:id:1;operation:code:0;operation:created_date:2023-05-26T06:43:10+0000;operation:date:2023-05-26T06:43:19+0000;operation:eci:02;operation:id:5055919010134089;operation:message:Success;operation:provider:auth_code:563253;operation:provider:date:2023-05-26T03:43:19+0000;operation:provider:endpoint_id:13012;operation:provider:id:13012;operation:provider:payment_id:16850833995740;operation:request_id:123456789;operation:status:success;operation:sum_converted:amount:50000;operation:sum_converted:currency:USD;operation:sum_initial:amount:50000;operation:sum_initial:currency:USD;operation:type:sale;payment:date:2023-05-26T06:43:19+0000;payment:description:PAYMENT_585860;payment:id:PAYMENT_585860;payment:method:card;payment:status:success;payment:sum:amount:50000;payment:sum:currency:USD;payment:type:purchase;project_id:1124
- Вычислите HMAC полученной строки с использованием функции хеширования SHA-512 и ключа подписывания, после чего закодируйте двоичный HMAC-код с применением алгоритма Base64.
kUJXSM6oRS1kHDxtd6veTg11pKFD2g02BduwDGRIdQskW4yCRD/odf1skZ9tmHGwTJi5k64tv7Og8Yu0/74oTQ==
- Сравните полученную подпись с проверяемой.
В данном случае подписи не совпадают, а это значит, что такое оповещение недостоверно или ошибочно и должно быть отброшено.
Форма для тестирования