# Работа с подписью к данным {#ru_platform_signature} статья о порядке создания и проверки подписи, используемой в программных запросах, ответах и оповещениях для обеспечения защищённого обмена данными при взаимодействии с платёжной платформой **На уровень выше:**[Платформа](ru_platform_about.md) ## Общая информация {#ru_platform_signature_overview} Для обеспечения защищённого обмена данными при работе с платёжной платформой Ecommpay используется криптографический протокол TLS \(Transport Layer Security; протокол защиты транспортного уровня\) версии не ниже 1.2, а для подтверждения авторства и целостности передаваемых данных дополнительно применяется цифровая подпись. Цифровая подпись формируется и проверяется по заданным алгоритмам с использованием одинакового секретного ключа, доступного на двух сторонах: мерчанта и Ecommpay. Независимо от интерфейса, используемого при работе с платформой, подпись обязательна к включению в состав всех программных запросов, отправляемых от веб-сервиса к платёжной платформе, а также всех оповещений и ряда ответов, отправляемых от платёжной платформы к веб-сервису. Поэтому перед отправкой любого запроса в платформу необходимо сформировать подпись и включить её в состав этого запроса, а при получении ответов и оповещений от платформы следует проверять целостность данных путём сличения расчётных подписей с полученными.Для этого можно использовать как собственные программные решения, так и SDK от Ecommpay \([подробнее](ru_sdk_overview.md)\). Алгоритмы подписывания данных и проверки их целостности, а также примеры выполнения этих алгоритмов и интерактивные формы для самостоятельной проверки корректной работы с подписью к разным данным при использовании программных интерфейсов Ecommpay, представлены далее. ## Подписывание данных {#ru_platform_signature_generation} ### Описание алгоритма {#section_imf_5kd_x4b .section} *В качестве входных данных* для подписывания выступают: 1. *Данные*, которые требуется подписать. Как правило, это заполненное тело запроса, все параметры запроса за исключением подписи или JavaScript-объект configObj с параметрами без включения параметра `signature`. 2. *Ключ*, используемый для подписывания. **Прим.:** Для работы с Data API должны использоваться ключи, получаемые через интерфейс Dashboard в связке с токенами. \(Подробнее в разделе [Порядок доступа к данным](ru_dbl_api_interaction.md).\) Для отладки и тестирования могут использоваться произвольные ключи, а для рабочих запросов в платформу — только актуальный секретный ключ. *В качестве выходных данных* подписывания в зависимости от реализации алгоритма могут выступать либо *подпись*, либо *подписанные данные* — как правило, это итоговый объект или итоговое тело запроса в формате JSON с параметром `signature`, включённым в его состав. Далее в описании, примерах и формах для тестирования представлен наиболее показательный вариант реализации алгоритма, актуальный при работе с интерфейсами Payment Page API, Gate API и Data API. *В состав алгоритма* в этом случае *включаются следующие шаги*: 1. *Проверка входных данных* на соблюдение заданных требований: 1. Структура данных для подписывания должна соответствовать формату JSON. При работе с Payment Page также можно использовать JavaScript-объекты. 2. В составе данных для подписывания не должен присутствовать параметр `signature` \(даже с пустым значением\). 3. Должен быть задан ключ. 2. *Приведение структуры проверяемых данных к требуемой глубине вложенности.* В зависимости от интерфейса платёжной платформы, к которому должен отправляться запрос, на этом шаге могут выполняться разные действия: - При работе через Payment Page отдельные параметры, представленные вложенными объектами, кодируются в строки с применением алгоритма Base64 или преобразования URL-encoding — в соответствии с требованиями, представленными в статье [Спецификация Payment Page API](ru_PP_Parameters.md). - При работе через Gate API ограничений по вложенности не применяется и действий по преобразованию или исключению данных не требуется. - При работе через Data API значения всех параметров, расположенных на четвёртом и более глубоких уровнях вложенности, заменяются пустыми строками. 3. *Преобразование данных в строку UTF-8 с сортировкой параметров в естественном порядке*. В рамках этого шага выполняются следующие действия: 1. Логические \(булевы\) значения кодируются следующим образом: `false` заменяется на `0`, а `true` — на `1`. Но это относится только к булевым значениям — в строковых параметрах, даже если они содержат значения `false` или `true`, замены на `0` или `1` не используются\(например, в параметре `recurring: "{type: \"U\",register: true}"` замена `true` на `1` не требуется\). 2. Каждый параметр преобразуется в строку, содержащую полный путь к параметру, название параметра и его значение: ``` <родительский_узел_1>:...:<родительский_узел_N>:<название_параметра>:<значение_параметра> ``` где *родительские узлы* — это названия объектов и \(или\) массивов, в состав которых включена пара «название параметра — значение параметра». Родительские узлы располагаются в порядке их вложения, начиная с самого верхнего уровня. В качестве разделителя при этом используется двоеточие \(:\), между парами «название параметра — значение параметра» удаляются запятые, а у строковых значений параметров удаляются обрамляющие кавычки. 3. Параметры с нулевыми, а также пустыми значениями остаются в строке, например запись `"payment_description":""` представляется в виде `payment_description:`. Замены пустых значений на пробелы или `null` не применяются. 4. Элементы массивов записываются отдельными строками, с указанием номера каждого элемента, начиная с нуля. Например, массив `["alpha", "beta", "gamma"]` представляется в виде трёх строк: `0:alpha`, `1:beta` и `2:gamma`. 5. Пустые массивы полностью игнорируются и не включаются в набор строк для создания подписи. 6. Кодировка всех строк приводится к формату UTF-8. 7. Полученные строки упорядочиваются в естественном порядке и объединяются в одну строку с использованием в качестве разделителя точки с запятой \(;\). 4. *Получение двоичного кода HMAC с использованием ключа и функции SHA-512.* На этом шаге для полученной строки с параметрами вычисляется HMAC \(Hash-based Message Authentication Code; код аутентификации сообщений с использованием хеш-функции\) с использованием функции хеширования SHA‑512 \(Secure Hash Algorithm; безопасный алгоритм хеширования\) и применяемого ключа. И этот HMAC представляется в виде необработанных двоичных данных. 5. *Кодирование двоичного кода HMAC с применением алгоритма Base64*. На этом шаге полученный двоичный код HMAC кодируется с использованием алгоритма Base64. Получаемая при этом строка является подписью к исходным данным. 6. *Добавление подписи к данным*. На этом шаге к исходным данным для подписывания добавляется параметр `signature` с полученной подписью в качестве его значения. ### Пример для запроса на оплату через Payment Page {#section_osk_5kd_x4b .section} Допустим, что надо подписать запрос на открытие Payment Page при следующих условиях: - Используемый ключ — `secret` - Предварительная версия объекта configObj, в котором еще нет значения параметра с подписью, выглядит так: ``` {#codeblock_azp_jjb_f1c} { "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`. Для этого необходимо: 1. Убедиться, что в теле запроса нет параметра `signature`, даже с пустым значением. Если такой параметр есть, его нужно удалить: ``` {#codeblock_ljm_2x3_1fc} { "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": "<*подпись, которую нужно создать*\>" ** } ``` 2. Преобразовать оставшиеся параметры в строки UTF-8 согласно правилам алгоритма: ``` {#codeblock_e5n_d1b_f1c} 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 ``` 3. Отсортировать полученные строки в естественном порядке: ``` {#codeblock_zkw_d1b_f1c} 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 ``` 4. Объединить отсортированные строки в одну строку с использованием в качестве разделителя точки с запятой: ``` {#codeblock_wng_21b_f1c} 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 ``` 5. Вычислить HMAC полученной строки с использованием функции хеширования SHA-512 и используемого ключа, после чего кодировать двоичный код HMAC с применением алгоритма Base64: ``` {#codeblock_uq4_21b_f1c} SyA3cx/dmFrwjRcpbnwEK9zaklWKR9buIfTctQob/EHUTutFLpI0zWpSDFEWEwbZt/04i83395RCdEhtUMw83A== ``` 6. Добавить полученную подпись в объект configObj: ``` {#codeblock_cmw_21b_f1c} { "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==" ** } ``` ### Форма тестирования для Payment Page {#section_sjm_2x3_1fc .section} Далее представлена интерактивная форма для самостоятельной проверки корректной работы с подписью при отправке запросов на открытие Payment Page. **Прим.:** Для корректной работы с параметрами реальных запросов следует учитывать требования к кодированию вложенных объектов, представленные в статье [Спецификация Payment Page API](ru_PP_Parameters.md) и в статьях с описанием возможностей платёжной формы. При указании вложенных объектов, не соответствующих таким требованиям, подпись в форме тестирования рассчитывается в соответствии с алгоритмом, но не может использоваться для реальных запросов, поскольку оказывается сформированной на некорректных входных данных. ### Пример для запроса на оплату через Gate {#section_jqp_1ld_x4b .section} Допустим, что надо подписать запрос в Gate при следующих условиях: - Используемый ключ — `secret` - Предварительная версия тела запроса, в котором еще нет значения параметра с подписью, выглядит так: ``` {#codeblock_rzk_gx3_1fc .language-python} { "general": { "project_id": 3254, "payment_id": "id_38202316", **"signature": "<*подпись, которую нужно создать*\>"** }, "customer": { "id": "585741", "email": "johndoe@mycompany.com", "first_name": "John", "last_name": "Doe", "address": "Downing str., 23", "identify": { "doc_number": "54122312544" }, "ip_address": "111.222.333.444" }, "payment": { "amount": 10800, "currency": "USD", "description": "Computer keyboards" }, "receipt_data": { "positions": [ { "quantity": "10", "amount": "108", "description": "Computer keyboard" } ] }, "return_url": { "success": "https://paymentpage.mycompany.com/complete-redirect?id=success", "decline": "https://paymentpage.mycompany.com/complete-redirect?id=decline" } } ``` Задача заключается в том, чтобы вычислить подпись, то есть рассчитать значение параметра `signature` и добавить его в запрос. Для этого необходимо: 1. Убедиться, что в теле запроса нет параметра `signature`, даже с пустым значением. Если такой параметр есть, его нужно удалить. ``` {#codeblock_tzk_gx3_1fc .language-python} { "general": { "project_id": 3254, "payment_id": "id_38202316", **"signature": "<*подпись, которую нужно создать*\>"** }, "customer": { "id": "585741", "email": "johndoe@mycompany.com", "first_name": "John", "last_name": "Doe", "address": "Downing str., 23", "identify": { "doc_number": "54122312544" }, "ip_address": "111.222.333.444" }, "payment": { "amount": 10800, "currency": "USD", "description": "Computer keyboards" }, "receipt_data": { "positions": [ { "quantity": "10", "amount": "108", "description": "Computer keyboard" } ] }, "return_url": { "success": "https://paymentpage.mycompany.com/complete-redirect?id=success", "decline": "https://paymentpage.mycompany.com/complete-redirect?id=decline" } } ``` 2. Преобразовать оставшиеся параметры в строки UTF-8 согласно правилам алгоритма: ``` {#codeblock_vzk_gx3_1fc .language-json} general:project_id:3254 general:payment_id:id_38202316 customer:id:585741 customer:email:johndoe@mycompany.com customer:first_name:John customer:last_name:Doe customer:address:Downing str., 23 customer:identify:doc_number:54122312544 customer:ip_address:111.222.333.444 payment:amount:10800 payment:currency:USD payment:description:Computer keyboards receipt_data:positions:0:quantity:10 receipt_data:positions:0:amount:108 receipt_data:positions:0:description:Computer keyboard return_url:success:https://paymentpage.mycompany.com/complete-redirect?id=success return_url:decline:https://paymentpage.mycompany.com/complete-redirect?id=decline ``` 3. Отсортировать полученные строки в естественном порядке: ``` {#codeblock_xzk_gx3_1fc .language-lua} customer:address:Downing str., 23 customer:email:johndoe@mycompany.com customer:first_name:John customer:id:585741 customer:identify:doc_number:54122312544 customer:ip_address:111.222.333.444 customer:last_name:Doe general:payment_id:id_38202316 general:project_id:3254 payment:amount:10800 payment:currency:USD payment:description:Computer keyboards receipt_data:positions:0:amount:108 receipt_data:positions:0:description:Computer keyboard receipt_data:positions:0:quantity:10 return_url:decline:https://paymentpage.mycompany.com/complete-redirect?id=decline return_url:success:https://paymentpage.mycompany.com/complete-redirect?id=success ``` 4. Объединить отсортированные строки в одну строку с использованием в качестве разделителя точки с запятой: ``` {#codeblock_zzk_gx3_1fc} customer:address:Downing str., 23;customer:email:johndoe@mycompany.com;customer:first_name:John;customer:id:585741;customer:identify:doc_number:54122312544;customer:ip_address:111.222.333.444;customer:last_name:Doe;general:payment_id:id_38202316;general:project_id:3254;payment:amount:10800;payment:currency:USD;payment:description:Computer keyboards;receipt_data:positions:0:amount:108;receipt_data:positions:0:description:Computer keyboard;receipt_data:positions:0:quantity:10;return_url:decline:https://paymentpage.mycompany.com/complete-redirect?id=decline;return_url:success:https://paymentpage.mycompany.com/complete-redirect?id=success ``` 5. Вычислить HMAC полученной строки с использованием функции хеширования SHA-512 и используемого ключа, после чего кодировать двоичный код HMAC с применением алгоритма Base64: ``` {#codeblock_b1l_gx3_1fc} VLLZzVNGevQNhr1b4TEhbC4qqHD17Kyn/M6FPNN93ttyk/amJgD/R6dayTKVvW6/QCRdq4hOf8R2w/xbUa8f2w== ``` 6. Добавить полученную подпись в тело запроса: ``` {#codeblock_d1l_gx3_1fc} { "general": { "project_id": 3254, "payment_id": "id_38202316", ** "signature": "VLLZzVNGevQNhr1b4TEhbC4qqHD17Kyn/M6FPNN93ttyk/amJgD/R6dayTKVvW6/QCRdq4hOf8R2w/xbUa8f2w=="** }, "customer": { "id": "585741", "email": "johndoe@mycompany.com", "first_name": "John", "last_name": "Doe", "address": "Downing str., 23", "identify": { "doc_number": "54122312544" }, "ip_address": "111.222.333.444" }, "payment": { "amount": 10800, "currency": "USD", "description": "Computer keyboards" }, "receipt_data": { "positions": [ { "quantity": "10", "amount": "108", "description": "Computer keyboard" } ] }, "return_url": { "success": "https://paymentpage.mycompany.com/complete-redirect?id=success", "decline": "https://paymentpage.mycompany.com/complete-redirect?id=decline" } } ``` ### Форма тестирования для Gate API {#section_f1l_gx3_1fc .section} Далее представлена интерактивная форма для самостоятельной проверки корректной работы с подписью при отправке запросов к Gate API. ### Пример для запроса на получение данных через Data API {#section_omc_dld_x4b .section} Допустим, что надо подписать запрос в Dashboard при следующих условиях: - Используемый ключ — `secret` - Предварительная версия тела запроса, в котором еще нет значения параметра с подписью, выглядит так: ``` { "token": "WKiarERJ5pcceNerpM9R5TNnyPTQMl", "interval": { "from": "2020-01-01 14:53:55", "to": "2020-01-30 13:53:59" }, "project_id": [ 183 ], "limit": 3, "offset": 0, "tz": "Asia/Singapore", **"signature": "<*подпись, которую нужно создать*\>"** } ``` Задача заключается в том, чтобы вычислить подпись, то есть рассчитать значение параметра `signature` и добавить его в запрос. Для этого необходимо: 1. Убедиться, что в теле запроса нет параметра `signature`, даже с пустым значением. Если такой параметр есть, его нужно удалить. ``` { "token": "WKiarERJ5pcceNerpM9R5TNnyPTQMl", "interval": { "from": "2020-01-01 14:53:55", "to": "2020-01-30 13:53:59" }, "project_id": [ 183 ], "limit": 3, "offset": 0, "tz": "Asia/Singapore", **"signature": "<*подпись, которую нужно создать*\>"** } ``` 2. Преобразовать оставшиеся параметры в строки UTF-8 согласно правилам алгоритма: ``` token:WKiarERJ5pcceNerpM9R5TNnyPTQMl interval:from:2020-01-01 14:53:55 interval:to:2020-01-30 13:53:59 project_id:0:183 limit:3 offset:0 tz:Asia/Singapore ``` 3. Отсортировать полученные строки в естественном порядке: ``` interval:from:2020-01-01 14:53:55 interval:to:2020-01-30 13:53:59 limit:3 offset:0 project_id:0:183 token:WKiarERJ5pcceNerpM9R5TNnyPTQMl tz:Asia/Singapore ``` 4. Объединить отсортированные строки в одну строку с использованием в качестве разделителя точки с запятой: ``` interval:from:2020-01-01 14:53:55;interval:to:2020-01-30 13:53:59;limit:3;offset:0;project_id:0:183;token:WKiarERJ5pcceNerpM9R5TNnyPTQMl;tz:Asia/Singapore ``` 5. Вычислить HMAC полученной строки с использованием функции хеширования SHA-512 и используемого ключа, после чего кодировать двоичный код HMAC с применением алгоритма Base64: ``` Ini3aKje6aZskajTuRS761YOzVqierlVRafZdxIz48wmVnL7yxgy9vDsp7T2/LGPGHJ/DHoKOgP7VqObJALrUA== ``` 6. Добавить полученную подпись в тело запроса: ``` { "token": "WKiarERJ5pcceNerpM9R5TNnyPTQMl", "interval": { "from": "2020-01-01 14:53:55", "to": "2020-01-30 13:53:59" }, "project_id": [ 183 ], "limit": 3, "offset": 0, "tz": "Asia/Singapore", **"signature": "Ini3aKje6aZskajTuRS761YOzVqierlVRafZdxIz48wmVnL7yxgy9vDsp7T2/LGPGHJ/DHoKOgP7VqObJALrUA=="** } ``` ### Форма тестирования для Data API {#section_tnw_qdf_52c .section} Далее представлена интерактивная форма для самостоятельной проверки корректной работы с подписью при отправке запросов к Data API. **Прим.:** При работе с запросами, отправляемыми к платформе через Data API, и ответами на такие запросы необходимо учитывать, что расчётная подпись составляется с ограничением на 3 уровня вложенности и данные на более глубоких уровнях вложенности не принимаются в расчёт. ## Проверка данных {#ru_platform_signature_verification} ### Описание алгоритма {#section_skf_smd_x4b .section} *В качестве входных данных* для проверки целостности выступают: 1. *Подписанные данные*, которые требуется проверить. Как правило, это тело оповещения или ответа в формате JSON с параметром `signature` в его составе. 2. *Ключ*, используемый для проверки. Это должен быть ровно тот ключ, который был использован для подписывания проверяемых данных. *В качестве выходных данных* при проверке целостности в зависимости от реализации алгоритма могут выступать *расчётная подпись* и информация о её совпадении с проверяемой подписью, то есть *информация о целостности проверяемых данных*. Далее в описании, примерах и формах для тестирования представлен часто используемый и наиболее показательный вариант реализации алгоритма: с телом проверяемого сообщения \(оповещения или ответа\) в формате JSON на входе и с заключением о целостности этого сообщения на выходе. *В состав алгоритма* в этом случае *включаются следующие шаги*: 1. *Проверка входных данных на соблюдение заданных требований*: 1. Структура проверяемых данных должна соответствовать формату JSON. 2. В составе проверяемых данных должен присутствовать параметр `signature` с подписью. 3. Должен быть задан проверочный ключ. 2. *Извлечение подписи из проверяемых данных.* На этом шаге из проверяемых данных исключается параметр `signature`, а его значение фиксируется для последующего сличения с расчётной подписью. 3. При работе с ответами, получаемыми от платформы через Data API, на этом шаге значения всех параметров, расположенных на четвёртом и более глубоких уровнях вложенности, заменяются пустыми строками \(например, в ответе с информацией о выполнении операций за заданный период для объекта `"sum_initial": {"amount": 2000, "currency": "EUR"}` необходимо исключить значение и учитывать при расчёте подписи запись вида `"sum_initial": ""`\). При работе с ответами и оповещениями, получаемыми через другие интерфейсы платформы, ограничений по вложенности не применяется и действий по исключению данных не требуется. 4. *Формирование расчётной подписи для проверяемых данных:* 1. *Преобразование данных в строку UTF-8 с сортировкой параметров в естественном порядке.* В рамках этого шага выполняются следующие действия: 1. Логические \(булевы\) значения кодируются следующим образом: `false` заменяется на `0`, а `true` — на `1`. Но это относится только к булевым значениям — в строковых параметрах, даже если они содержат значения `false` или `true`, замены на `0` или `1` не используются\(например, в параметре `recurring: "{type: \"U\",register: true}"` замена `true` на `1` не требуется\). 2. Каждый параметр преобразуется в строку, содержащую полный путь к параметру, название параметра и его значение: `<родительский_узел_1>:...:<родительский_узел_N>:<название_параметра>:<значение_параметра>`, где *родительские узлы* — это названия объектов и \(или\) массивов, в состав которых включена пара «название параметра — значение параметра». Родительские узлы располагаются в порядке их вложения, начиная с самого верхнего уровня. В качестве разделителя при этом используется двоеточие \(:\), между парами «название параметра — значение параметра» удаляются запятые, а у строковых значений параметров удаляются обрамляющие кавычки. 3. Параметры с нулевыми, а также пустыми значениями остаются в строке, например запись `"payment_description":""` представляется в виде `payment_description:`. Замены пустых значений на пробелы или `null` не применяются. 4. Элементы массивов записываются отдельными строками, с указанием номера каждого элемента, начиная с нуля. Например, массив `["alpha", "beta", "gamma"]` представляется в виде трёх строк: `0:alpha`, `1:beta` и `2:gamma`. 5. Пустые массивы полностью игнорируются и не включаются в набор строк для создания подписи. 6. Кодировка всех строк приводится к формату UTF-8. 7. Полученные строки упорядочиваются в естественном порядке и объединяются в одну строку с использованием в качестве разделителя точки с запятой \(;\). 2. *Получение двоичного кода HMAC с использованием ключа и функции SHA‑512.* На этом шаге для полученной строки с параметрами вычисляется HMAC \(Hash-based Message Authentication Code; код аутентификации сообщений с использованием хеш-функции\) с использованием функции хеширования SHA‑512 \(Secure Hash Algorithm; безопасный алгоритм хеширования\) и применяемого ключа. И этот HMAC представляется в виде необработанных двоичных данных. 3. *Кодирование двоичного кода HMAC с применением алгоритма Base64*. На этом шаге полученный двоичный код HMAC кодируется с использованием алгоритма Base64. Получаемая при этом строка является подписью к исходным данным. 5. *Сопоставление подписей.* На этом шаге расчётная подпись сопоставляется с проверяемой. Если подписи совпадают, данные признаются целостными и достоверными. При несовпадении подписей данные не могут считаться достоверными и не должны использоваться в качестве рабочих. ### Пример для оповещения {#section_tk2_fnd_x4b .section} Допустим, что надо проверить подпись оповещения при следующих условиях: - Используемый ключ — `secret` - Тело полученного оповещения выглядит так: ``` {#codeblock_nyj_zlp_31c .language-json} { "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==" } ``` Для проверки подписи необходимо: 1. Удалить из тела оповещения параметр `signature` вместе с его значением: ``` {#codeblock_vpc_1mp_31c .language-json} { "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=="** } ``` 2. Преобразовать оставшиеся параметры в строки UTF-8 согласно правилам алгоритма: ``` {#codeblock_lwv_1mp_31c .language-json} 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 ``` 3. Отсортировать полученные строки в естественном порядке: ``` {#codeblock_pmt_lkp_31c .language-json} 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 ``` 4. Объединить отсортированные строки в одну строку с использованием в качестве разделителя точки с запятой: ``` {#codeblock_fjv_bmp_31c} 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 ``` 5. Вычислить HMAC полученной строки с использованием функции хеширования SHA-512 и используемого ключа, после чего кодировать двоичный код HMAC с применением алгоритма Base64: ``` {#codeblock_nzc_cmp_31c} Y0qjN9dDnPTdddkVvXKS1pGp2z8ZpIl60P1CocND3YRxuBNx05ZMnhUaGFt90fPzgwsI/UpLw0q2RR/XTiDQBg== ``` 6. Сравнить полученную подпись с проверяемой. В данном случае подписи не совпадают, а это значит, что такое оповещение недостоверно или ошибочно и должно быть отброшено. ### Форма тестирования для оповещений {#section_dzg_lx3_1fc .section} Далее представлена интерактивная форма для самостоятельной проверки корректной работы с подписанными данными. ### Пример для ответа через Gate API {#section_ag3_ghs_y4b .section} Допустим, что надо проверить подпись ответа при следующих условиях: - Используемый ключ — `secret` - Тело полученного ответа выглядит так: ```language-json { "project_id": 200, "payment": { "id": "abc12345", "type": "purchase", "status": "success", "date": "2025-04-23T10:54:37+0000", "method": "card", "sum": { "amount": 45000, "currency": "EUR" }, "description": "" }, "account": { "number": "425000******0000", "token": "13n121******4991", "type": "visa", "card_holder": "****************", "expiry_month": "**", "expiry_year": "****" }, "customer": { "id": "customer_007" }, "operations": [ { "id": 9529253065607, "type": "auth", "status": "success", "date": "2025-04-23T10:54:27+0000", "created_date": "2025-04-23T10:53:48+0000", "request_id": "a7B9kLmQwP2X8rTg-uV3n6Zc1RbEyHd", "sum_initial": { "amount": 45000, "currency": "EUR" }, "sum_converted": { "amount": 45000, "currency": "EUR" }, "code": "0", "message": "Success", "eci": "05", "provider": { "id": 3651, "payment_id": "00000000123456", "auth_code": "070707", "endpoint_id": 0000, "date": "2025-04-23T10:54:26+0000" } } ], "signature": "EksxDdDygDQ30JKsfK6QSvubpNRSj3wtLI5FzWDJuNY0nEhLXt65Y77dtKMJRcd39NegA7YK1eojA2EB1hIbnQ==" } ``` Для проверки подписи необходимо: 1. Удалить из тела ответа параметр `signature` вместе с его значением: ```language-json { "project_id": 200, "payment": { "id": "abc12345", "type": "purchase", "status": "success", "date": "2025-04-23T10:54:37+0000", "method": "card", "sum": { "amount": 45000, "currency": "EUR" }, "description": "" }, "account": { "number": "425000******0000", "token": "13n121******4991", "type": "visa", "card_holder": "****************", "expiry_month": "**", "expiry_year": "****" }, "customer": { "id": "customer_007" }, "operations": [ { "id": 9529253065607, "type": "auth", "status": "success", "date": "2025-04-23T10:54:27+0000", "created_date": "2025-04-23T10:53:48+0000", "request_id": "a7B9kLmQwP2X8rTg-uV3n6Zc1RbEyHd", "sum_initial": { "amount": 45000, "currency": "EUR" }, "sum_converted": { "amount": 45000, "currency": "EUR" }, "code": "0", "message": "Success", "eci": "05", "provider": { "id": 3651, "payment_id": "00000000123456", "auth_code": "070707", "endpoint_id": 0000, "date": "2025-04-23T10:54:26+0000" } } ], **"signature": "EksxDdDygDQ30JKsfK6QSvubpNRSj3wtLI5FzWDJuNY0nEhLXt65Y77dtKMJRcd39NegA7YK1eojA2EB1hIbnQ=="** } ``` 2. Преобразовать оставшиеся параметры в строки UTF-8 согласно правилам алгоритма: ```language-json project_id:200 payment:id:abc12345 payment:type:purchase payment:status:success payment:date:2025-04-23T10:54:37+0000 payment:method:card payment:sum:amount:45000 payment:sum:currency:EUR payment:description: account:number:425000******0000 account:token:13n121******4991 account:type:visa account:card_holder:**************** account:expiry_month:** account:expiry_year:**** customer:id:customer_007 operations:0:id:9529253065607 operations:0:type:auth operations:0:status:success operations:0:date:2025-04-23T10:54:27+0000 operations:0:created_date:2025-04-23T10:53:48+0000 operations:0:request_id:a7B9kLmQwP2X8rTg-uV3n6Zc1RbEyHd operations:0:sum_initial:amount:45000 operations:0:sum_initial:currency:EUR operations:0:sum_converted:amount:45000 operations:0:sum_converted:currency:EUR operations:0:code:0 operations:0:message:Success operations:0:eci:05 operations:0:provider:id:3651 operations:0:provider:payment_id:00000000123456 operations:0:provider:auth_code:070707 operations:0:provider:endpoint_id:0 operations:0:provider:date:2025-04-23T10:54:26+0000 ``` 3. Отсортировать полученные строки в естественном порядке: ```language-json account:card_holder:**************** account:expiry_month:** account:expiry_year:**** account:number:425000******0000 account:token:13n121******4991 account:type:visa customer:id:customer_007 operations:0:code:0 operations:0:created_date:2025-04-23T10:53:48+0000 operations:0:date:2025-04-23T10:54:27+0000 operations:0:eci:05 operations:0:id:9529253065607 operations:0:message:Success operations:0:provider:auth_code:070707 operations:0:provider:date:2025-04-23T10:54:26+0000 operations:0:provider:endpoint_id:0 operations:0:provider:id:3651 operations:0:provider:payment_id:00000000123456 operations:0:request_id:a7B9kLmQwP2X8rTg-uV3n6Zc1RbEyHd operations:0:status:success operations:0:sum_converted:amount:45000 operations:0:sum_converted:currency:EUR operations:0:sum_initial:amount:45000 operations:0:sum_initial:currency:EUR operations:0:type:auth payment:date:2025-04-23T10:54:37+0000 payment:description: payment:id:abc12345 payment:method:card payment:status:success payment:sum:amount:45000 payment:sum:currency:EUR payment:type:purchase project_id:200 ``` 4. Объединить отсортированные строки в одну строку с использованием в качестве разделителя точки с запятой: ``` account:card_holder:****************;account:expiry_month:**;account:expiry_year:****;account:number:425000******0000;account:token:13n121******4991;account:type:visa;customer:id:customer_007;operations:0:code:0;operations:0:created_date:2025-04-23T10:53:48+0000;operations:0:date:2025-04-23T10:54:27+0000;operations:0:eci:05;operations:0:id:9529253065607;operations:0:message:Success;operations:0:provider:auth_code:070707;operations:0:provider:date:2025-04-23T10:54:26+0000;operations:0:provider:endpoint_id:0;operations:0:provider:id:3651;operations:0:provider:payment_id:00000000123456;operations:0:request_id:a7B9kLmQwP2X8rTg-uV3n6Zc1RbEyHd;operations:0:status:success;operations:0:sum_converted:amount:45000;operations:0:sum_converted:currency:EUR;operations:0:sum_initial:amount:45000;operations:0:sum_initial:currency:EUR;operations:0:type:auth;payment:date:2025-04-23T10:54:37+0000;payment:description:;payment:id:abc12345;payment:method:card;payment:status:success;payment:sum:amount:45000;payment:sum:currency:EUR;payment:type:purchase;project_id:200 ``` 5. Вычислить HMAC полученной строки с использованием функции хеширования SHA-512 и используемого ключа, после чего кодировать двоичный код HMAC с применением алгоритма Base64: ``` qUVvwChGUOSWRXwKQI6ZIkKvvWJsvx2luS8cYvN+M7iRiBAKkGE+WwfgAztgGU+vZNMr2bd4Lnn0J0KkhwYS1A== ``` 6. Сравнить полученную подпись с проверяемой. В данном случае подписи не совпадают, а это значит, что такой ответ недостоверен или ошибочен и должен быть отброшен. ### Форма тестирования для ответов через Gate API {#section_dml_53y_y2c .section} Далее представлена интерактивная форма для самостоятельной проверки корректной работы с подписанными данными. ### Пример для ответа через Data API {#section_tnl_nx3_1fc .section} Допустим, что надо проверить подпись ответа при следующих условиях: - Используемый ключ — `secret` - Тело полученного ответа выглядит так: ``` {#codeblock_wnl_nx3_1fc .language-json} { "operations": [ { "project_id": "183", "operation_id": "9048253065548", "payment_id": "EP834a-40521580376090593", "operation_type": "cancel", "operation_status": "success", "account_number": "431422******0056", "customer_ip": "192.0.0.255", "payment_method_name": "visa", "payment_method_type": "visa", "payment_description": null, "operation_created_at": "2020-01-30T12:29:03+03:00", "operation_completed_at": "2020-01-30T12:29:04+03:00", "provider_date": null, "shipment_date": "", "mid": "3416123", "sum_initial": { "amount": 2000, "currency": "EUR" }, "sum_converted": { "amount": 2000, "currency": "EUR" }, "provider_name": "Dashboard Provider Card", "fee_currency": null, "fee_amount": 0, "arn": null, "rrn": null } ], "signature": "EksxDdDygDQ30JKsfK6QSvubpNRSj3wtLI5FzWDJuNY0nEhLXt65Y77dtKMJRcd39NegA7YK1eojA2EB1hIbnQ==" } ``` Для проверки подписи необходимо: 1. Удалить из тела ответа параметр `signature` вместе с его значением: ``` {#codeblock_znl_nx3_1fc .language-json} { "operations": [ { "project_id": "183", "operation_id": "9048253065548", "payment_id": "EP834a-40521580376090593", "operation_type": "cancel", "operation_status": "success", "account_number": "431422******0056", "customer_ip": "192.0.0.255", "payment_method_name": "visa", "payment_method_type": "visa", "payment_description": null, "operation_created_at": "2020-01-30T12:29:03+03:00", "operation_completed_at": "2020-01-30T12:29:04+03:00", "provider_date": null, "shipment_date": "", "mid": "3416123", "sum_initial": { "amount": 2000, "currency": "EUR" }, "sum_converted": { "amount": 2000, "currency": "EUR" }, "provider_name": "Dashboard Provider Card", "fee_currency": null, "fee_amount": 0, "arn": null, "rrn": null } ], ** "signature": "EksxDdDygDQ30JKsfK6QSvubpNRSj3wtLI5FzWDJuNY0nEhLXt65Y77dtKMJRcd39NegA7YK1eojA2EB1hIbnQ=="** } ``` 2. Заменить пустой строкой данные на четвёртом уровне вложенности: ``` {#codeblock_g4b_fhq_1fc .language-json} { "operations": [ { "project_id": "183", "operation_id": "9048253065548", "payment_id": "EP834a-40521580376090593", "operation_type": "cancel", "operation_status": "success", "account_number": "431422******0056", "customer_ip": "192.0.0.255", "payment_method_name": "visa", "payment_method_type": "visa", "payment_description": null, "operation_created_at": "2020-01-30T12:29:03+03:00", "operation_completed_at": "2020-01-30T12:29:04+03:00", "provider_date": null, "shipment_date": "", "mid": "3416123", **"sum\_initial": \{ "amount": 2000, "currency": "EUR" \},** **"sum\_initial":"",** **"sum\_converted": \{ "amount": 2000, "currency": "EUR" \},** **"sum\_converted":"",** "provider_name": "Dashboard Provider Card", "fee_currency": null, "fee_amount": 0, "arn": null, "rrn": null } ] } ``` 3. Преобразовать оставшиеся параметры в строки UTF-8 согласно правилам алгоритма: ``` {#codeblock_b4l_nx3_1fc .language-json} operations:0:project_id:183 operations:0:operation_id:9048253065548 operations:0:payment_id:EP834a-40521580376090593 operations:0:operation_type:cancel operations:0:operation_status:success operations:0:account_number:431422******0056 operations:0:customer_ip:192.0.0.255 operations:0:payment_method_name:visa operations:0:payment_method_type:visa operations:0:payment_description: operations:0:operation_created_at:2020-01-30T12:29:03+03:00 operations:0:operation_completed_at:2020-01-30T12:29:04+03:00 operations:0:provider_date: operations:0:shipment_date: operations:0:mid:3416123 operations:0:sum_initial: operations:0:sum_converted: operations:0:provider_name:Dashboard Provider Card operations:0:fee_currency: operations:0:fee_amount:0 operations:0:arn: operations:0:rrn: ``` 4. Отсортировать полученные строки в естественном порядке: ``` {#codeblock_d4l_nx3_1fc .language-json} operations:0:account_number:431422******0056 operations:0:arn: operations:0:customer_ip:192.0.0.255 operations:0:fee_amount:0 operations:0:fee_currency: operations:0:mid:3416123 operations:0:operation_completed_at:2020-01-30T12:29:04+03:00 operations:0:operation_created_at:2020-01-30T12:29:03+03:00 operations:0:operation_id:9048253065548 operations:0:operation_status:success operations:0:operation_type:cancel operations:0:payment_description: operations:0:payment_id:EP834a-40521580376090593 operations:0:payment_method_name:visa operations:0:payment_method_type:visa operations:0:project_id:183 operations:0:provider_date: operations:0:provider_name:Dashboard Provider Card operations:0:rrn: operations:0:shipment_date: operations:0:sum_converted: operations:0:sum_initial: ``` 5. Объединить отсортированные строки в одну строку с использованием в качестве разделителя точки с запятой: ``` {#codeblock_f4l_nx3_1fc} operations:0:account_number:431422******0056;operations:0:arn:;operations:0:customer_ip:192.0.0.255;operations:0:fee_amount:0;operations:0:fee_currency:;operations:0:mid:3416123;operations:0:operation_completed_at:2020-01-30T12:29:04+03:00;operations:0:operation_created_at:2020-01-30T12:29:03+03:00;operations:0:operation_id:9048253065548;operations:0:operation_status:success;operations:0:operation_type:cancel;operations:0:payment_description:;operations:0:payment_id:EP834a-40521580376090593;operations:0:payment_method_name:visa;operations:0:payment_method_type:visa;operations:0:project_id:183;operations:0:provider_date:;operations:0:provider_name:Dashboard Provider Card;operations:0:rrn:;operations:0:shipment_date:;operations:0:sum_converted:;operations:0:sum_initial: ``` 6. Вычислить HMAC полученной строки с использованием функции хеширования SHA-512 и используемого ключа, после чего кодировать двоичный код HMAC с применением алгоритма Base64: ``` {#codeblock_h4l_nx3_1fc} F58IW7JCqHsUthlmgQ/i1plf6lRPfdSVTGMXeEfhUMpdmwDMHKlO/rbtTy+V8cmQtvPNBjvuyQnl/rWxT7gPGg== ``` 7. Сравнить полученную подпись с проверяемой. В данном случае подписи не совпадают, а это значит, что такой ответ недостоверен или ошибочен и должен быть отброшен. ### Форма тестирования для ответов через Data API {#section_fnv_4x3_1fc .section} Далее представлена интерактивная форма для самостоятельной проверки корректной работы с подписанными данными. **Прим.:** При работе с запросами, отправляемыми к платформе через Data API, и ответами на такие запросы необходимо учитывать, что расчётная подпись составляется с ограничением на 3 уровня вложенности и данные на более глубоких уровнях вложенности не принимаются в расчёт.