Подпись запроса API
В некоторых случаях для обеспечения безопасного обмена данными может потребоваться реализовать асимметричную подпись запроса.
Чтобы иметь возможность подписывать запросы, вам необходимо выполнить следующие шаги:
- Создайте и загрузите сертификат.
- Рассчитайте хеш и подпись, используя свой закрытый ключ, и передайте сгенерированный хеш (X-Hash) и значение подписи (X-Signature) в заголовке запроса.
Эти шаги подробно описаны ниже.
Создание и загрузка сертификата
-
Создайте 2048-битный закрытый ключ RSA. Способ генерации зависит от политики конфиденциальности в вашей компании. Например, вы можете сделать это с помощью OpenSSL:
openssl genrsa -out private.key 2048 -
Создайте общедоступный CSR (запрос на подпись сертификата), используя сгенерированный закрытый ключ:
openssl req -key private.key -new -out public.csr -
Создайте сертификат, используя сгенерированный закрытый ключ и CSR. Пример формирования сертификата на 5 лет:
openssl x509 -signkey private.key -in public.csr -req -days 1825 -out public.cer Загрузите сгенерированный сертификат в Личный кабинет. Для этого перейдите в Сертификаты > Merchant API, нажмите Добавить сертификат и загрузите сгенерированный общедоступный сертификат.

Для использования этой функции в Личном кабинете требуется специальное разрешение Партнера в банке. Если раздел сертификатов не отображается в меню, для загрузки сертификата обратитесь в службу поддержки.
Вычисление хеша и подписи
-
Рассчитайте хеш SHA256 тела запроса следующим образом:
- Используйте тело запроса в виде строки, например
{"orderId": "243d940e-bedd-4e95-8e78-b08f459a242f","password": "test-user-password","userName": "test-user"}. - Вычислите хэш SHA256 из этой строки в необработанных байтах (hex-формате).
- Преобразуйте необработанные байты в кодировку base64.
Hash Base64: MmI1ZmUwZjc2YmUxNGJiY2ZjN2M3NzQ3OGYwYTU4ODUwYzhmNzEyNDg5YjczOTg3NzZlYTg4ODEwNDczYzFmYg== - Используйте тело запроса в виде строки, например
-
Для вычисленного хеша SHA256 (исходного в hex-формате, а не base64) сгенерируйте подпись с помощью алгоритма RSA, используя закрытый ключ.
В примере используется ключ:
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC0NQCjnqUmdEK1aisFXGMIihI73zofZycI/EGTJkQ6HOT2e/dG4j1RqHwuE6FEPL8lGG3EddFSiZzjDbIH+bm5m0CpcnFN1ShTxbA8BzM+OGxRHsuHU168HiS3OSIO9IxCKlaYzNgL1IygkjF6xqXLRvAPJ70zb/ymD2Cszfbw3ZNcZnr07QtJF/Jbn/+UJt+1hin9y6ikKZH+laZlMOx6LLGsj3W1PjFyEuzNUmau3iX6I6PdfgVwbB7TRVFuFDfxzBZxtBDympGRxpTGNFHug1NNPA9ekWa+zVlNVbzPrMuf6rF4yvKc8Tv9OkQ7RfGv1YmFCgEjqgnW2puIuufJAgMBAAECggEAdzDzakVdMJEHKly9db9ElXpVUxpzpB+jFvNaIAzYZaOE4W7fABhVvHP3Jra/HJYdS1jcCWxv9eqlRRxi25mV+Six3SGfxX4uPTJtPVb50raZFhKLRcejykMZv8JfP4sKVh0Qx+H9J93+4Zmwdmd7c3dJAo0jPCle7ysOo11bbrXTMwgg/i9Rxfzf5j4HYVTqYGIOL8cwNDE9XzDV7ekYJ147Ro15QnXK315fij2y7HFEJoyXp4BySm2nGNjxBjPn7sd/0Y8IrnYtpAnD7PG6oHRMITAEpZGEGyAi5cxAwTK1p43megM9ZaddSYPGtyrelNW6xm86x5Ulv8Bqhg1gzQKBgQDcAkILsNGV1eazxsv7QEg9Xs7h9VHrmPVTSGx6OjcZNP/VSZCzLT6IiK68c5ywkTe8SuDCLgU6Tcf4YOuno7gRplnLm6KzTatu/WE4qiz+WzrT4/+uspOli5YdTBXWtGXgWWvcnuQ1TTECdFf83na/cPDM5qKfJuoOan3gbMNVowKBgQDRr+MarMxNnoaH/XlY0HURtAUENieoyll72iHLofdlyQPDqoo0G00zjlV11DH/pH8qQ1PsswJDxL6oiY9XkxZ0P2Pd5BnYW8wSUdQ033ReSxc9WHlnTnixPp/YHraAmzZXncM6B8YJWAO5CtLW7Xym58BLUgMMH6FUM0gKiLMrowKBgQCx1alpJb3jrYjTnEdZifZalP4JK3DSTUtPzGTSz6el2m9JCjPKgTHgzwrfDVyEZH1219ehXe2f2Stgm4cgdHfe3GYM7HqxEIEYL/ucAAJqf3enus37eiFaWOA4Qj4M1LjchatoI483fnO1FjHhFjlKOZKLLYoZtyzOBkpFU+T4nQKBgQDNCpYj3ncFK4/X6NfBLk5b2lHRdXdAiWYJQxsq+Z1m7bJ9ogT0wQGz+Wm+B5pApkUnOaEWY1FCnV/mhGUjuJQLZnUsZEGVnOYnv9anQR6Umg8GkL5ec5B3mYpKlnXVunDgKkfeNf3D40n4pwnW23G58ALMZEzQjRl/sYmvq06wywKBgQCer3/ehngsL6xpdmWaWOyZja992F9s7JKb+M5esEltp5utpB9DEGrV1KKnLTWtM99vbxBEm5zeaYimdy1359YxzaDdmDm+w2tV+qjA3u3RgZpjqfw5uiASgL8hT12Rgme4itBC6tuhf3fZEGlQI5cKSJn+fB2XMXw/3S7RfGRT9w==Полученная подпись:
WR5bDw3XFuf29y9j1IJIM3E96g9d1fgyaWwUVKYIHOhOflKWuT0ei1Myz8aJzP1k2XlztQARK1h4Rj5LHMbZDZMSkkwfdNdr0VoKrfxPv6bJqW/paduYv47wQ5Q6YSqpuLsNjCjy5MMLKtLnuff9Drc18lEQU2RGq7eh8lELUVB6asts+8FOp7PIawfeSGbM+kSKPdH181E3XR0/V+ck1/m6cBouGeZHM7767S6nkbl8b7wx9kCj5z1j0mbvQxU3lPjK1qS+ntkbP4V0oMaDKe8kfnbZK9/LX6tRZFHoDjjMspwy3M72pe+ohn9FkfPg5G39H2L2dVtV/fb5BXlOBQ== Передайте сгенерированный хэш (
X-Hash) и значение подписи (X-Signature) в заголовке запроса. Запрос будет выглядеть так:
curl 'https://api.router.rbsuat.com/v1/getOrderStatusExtended.do' \
-H 'X-hash: MmI1ZmUwZjc2YmUxNGJiY2ZjN2M3NzQ3OGYwYTU4ODUwYzhmNzEyNDg5YjczOTg3NzZlYTg4ODEwNDczYzFmYg==' \
-H 'X-signature: WR5bDw3XFuf29y9j1IJIM3E96g9d1fgyaWwUVKYIHOhOflKWuT0ei1Myz8aJzP1k2XlztQARK1h4Rj5LHMbZDZMSkkwfdNdr0VoKrfxPv6bJqW/paduYv47wQ5Q6YSqpuLsNjCjy5MMLKtLnuff9Drc18lEQU2RGq7eh8lELUVB6asts+8FOp7PIawfeSGbM+kSKPdH181E3XR0/V+ck1/m6cBouGeZHM7767S6nkbl8b7wx9kCj5z1j0mbvQxU3lPjK1qS+ntkbP4V0oMaDKe8kfnbZK9/LX6tRZFHoDjjMspwy3M72pe+ohn9FkfPg5G39H2L2dVtV/fb5BXlOBQ==' \
-H 'Content-Type: application/json' \
-d '{"orderId": "243d940e-bedd-4e95-8e78-b08f459a242f","password": "test-user-password","userName": "test-user"}'Запрос должен соответствовать следующим требованиям:
- Все параметры запроса включены в тело запроса (не в URL)
-
Поскольку параметры запроса передаются в формате JSON, должен использоваться следующий заголовок:
--header 'content-type: application/json' Запрос содержит правильный логин и пароль пользователя API.
Заголовок
X-Hashсодержит хэш SHA256 тела запроса (рассчитывается на Шаге 1).Заголовок
X-Signatureсодержит подпись для хэша SHA256, рассчитанного с помощью алгоритма RSA с использованием закрытого ключа (генерируется на Шаге 2).
Пример кода Groovy
Ниже приведен пример кода Groovy, который генерирует хэш и подпись:
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.Key;
import java.security.KeyFactory;
Base64.Decoder b64d = Base64.getDecoder();
Base64.Encoder b64e = Base64.getEncoder();
//2048 pair
def privKeyBase64 = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC0NQCjnqUmdEK1aisFXGMIihI73zofZycI/EGTJkQ6HOT2e/dG4j1RqHwuE6FEPL8lGG3EddFSiZzjDbIH+bm5m0CpcnFN1ShTxbA8BzM+OGxRHsuHU168HiS3OSIO9IxCKlaYzNgL1IygkjF6xqXLRvAPJ70zb/ymD2Cszfbw3ZNcZnr07QtJF/Jbn/+UJt+1hin9y6ikKZH+laZlMOx6LLGsj3W1PjFyEuzNUmau3iX6I6PdfgVwbB7TRVFuFDfxzBZxtBDympGRxpTGNFHug1NNPA9ekWa+zVlNVbzPrMuf6rF4yvKc8Tv9OkQ7RfGv1YmFCgEjqgnW2puIuufJAgMBAAECggEAdzDzakVdMJEHKly9db9ElXpVUxpzpB+jFvNaIAzYZaOE4W7fABhVvHP3Jra/HJYdS1jcCWxv9eqlRRxi25mV+Six3SGfxX4uPTJtPVb50raZFhKLRcejykMZv8JfP4sKVh0Qx+H9J93+4Zmwdmd7c3dJAo0jPCle7ysOo11bbrXTMwgg/i9Rxfzf5j4HYVTqYGIOL8cwNDE9XzDV7ekYJ147Ro15QnXK315fij2y7HFEJoyXp4BySm2nGNjxBjPn7sd/0Y8IrnYtpAnD7PG6oHRMITAEpZGEGyAi5cxAwTK1p43megM9ZaddSYPGtyrelNW6xm86x5Ulv8Bqhg1gzQKBgQDcAkILsNGV1eazxsv7QEg9Xs7h9VHrmPVTSGx6OjcZNP/VSZCzLT6IiK68c5ywkTe8SuDCLgU6Tcf4YOuno7gRplnLm6KzTatu/WE4qiz+WzrT4/+uspOli5YdTBXWtGXgWWvcnuQ1TTECdFf83na/cPDM5qKfJuoOan3gbMNVowKBgQDRr+MarMxNnoaH/XlY0HURtAUENieoyll72iHLofdlyQPDqoo0G00zjlV11DH/pH8qQ1PsswJDxL6oiY9XkxZ0P2Pd5BnYW8wSUdQ033ReSxc9WHlnTnixPp/YHraAmzZXncM6B8YJWAO5CtLW7Xym58BLUgMMH6FUM0gKiLMrowKBgQCx1alpJb3jrYjTnEdZifZalP4JK3DSTUtPzGTSz6el2m9JCjPKgTHgzwrfDVyEZH1219ehXe2f2Stgm4cgdHfe3GYM7HqxEIEYL/ucAAJqf3enus37eiFaWOA4Qj4M1LjchatoI483fnO1FjHhFjlKOZKLLYoZtyzOBkpFU+T4nQKBgQDNCpYj3ncFK4/X6NfBLk5b2lHRdXdAiWYJQxsq+Z1m7bJ9ogT0wQGz+Wm+B5pApkUnOaEWY1FCnV/mhGUjuJQLZnUsZEGVnOYnv9anQR6Umg8GkL5ec5B3mYpKlnXVunDgKkfeNf3D40n4pwnW23G58ALMZEzQjRl/sYmvq06wywKBgQCer3/ehngsL6xpdmWaWOyZja992F9s7JKb+M5esEltp5utpB9DEGrV1KKnLTWtM99vbxBEm5zeaYimdy1359YxzaDdmDm+w2tV+qjA3u3RgZpjqfw5uiASgL8hT12Rgme4itBC6tuhf3fZEGlQI5cKSJn+fB2XMXw/3S7RfGRT9w=="
def body = """{"orderId": "243d940e-bedd-4e95-8e78-b08f459a242f","password": "test-user-password","userName": "test-user"}"""
KeyFactory keyFactory = KeyFactory.getInstance('RSA');
Signature signatureProvider = Signature.getInstance("SHA256withRSA");
//// HASH /////
byte[] bodyHash = body.digest('SHA-256')
def bodyHashBase64 = b64e.encodeToString(bodyHash);
println "Hash Hex: " + new String(bodyHash)
println "Hash Base64: $bodyHashBase64"
//// SIGN /////
byte[] byteKey = b64d.decode(privKeyBase64.getBytes());
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(byteKey)
Key privKey = keyFactory.generatePrivate(keySpec);
signatureProvider.initSign(privKey);
signatureProvider.update(bodyHash);
byte[] signature = signatureProvider.sign();
def signatureBase64 = b64e.encodeToString(signature)
println "Signature: $signatureBase64"Пример кода Python
Аналогичный пример на Python — генерация хеша и подписи.
import base64
import hashlib
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.backends import default_backend
data = """{"orderId": "243d940e-bedd-4e95-8e78-b08f459a242f","password": "test-user-password","userName": "test-user"}"""
priv_key_pem = """
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC0NQCjnqUmdEK1aisFXGMIihI73zofZycI/EGTJkQ6HOT2e/dG4j1RqHwuE6FEPL8lGG3EddFSiZzjDbIH+bm5m0CpcnFN1ShTxbA8BzM+OGxRHsuHU168HiS3OSIO9IxCKlaYzNgL1IygkjF6xqXLRvAPJ70zb/ymD2Cszfbw3ZNcZnr07QtJF/Jbn/+UJt+1hin9y6ikKZH+laZlMOx6LLGsj3W1PjFyEuzNUmau3iX6I6PdfgVwbB7TRVFuFDfxzBZxtBDympGRxpTGNFHug1NNPA9ekWa+zVlNVbzPrMuf6rF4yvKc8Tv9OkQ7RfGv1YmFCgEjqgnW2puIuufJAgMBAAECggEAdzDzakVdMJEHKly9db9ElXpVUxpzpB+jFvNaIAzYZaOE4W7fABhVvHP3Jra/HJYdS1jcCWxv9eqlRRxi25mV+Six3SGfxX4uPTJtPVb50raZFhKLRcejykMZv8JfP4sKVh0Qx+H9J93+4Zmwdmd7c3dJAo0jPCle7ysOo11bbrXTMwgg/i9Rxfzf5j4HYVTqYGIOL8cwNDE9XzDV7ekYJ147Ro15QnXK315fij2y7HFEJoyXp4BySm2nGNjxBjPn7sd/0Y8IrnYtpAnD7PG6oHRMITAEpZGEGyAi5cxAwTK1p43megM9ZaddSYPGtyrelNW6xm86x5Ulv8Bqhg1gzQKBgQDcAkILsNGV1eazxsv7QEg9Xs7h9VHrmPVTSGx6OjcZNP/VSZCzLT6IiK68c5ywkTe8SuDCLgU6Tcf4YOuno7gRplnLm6KzTatu/WE4qiz+WzrT4/+uspOli5YdTBXWtGXgWWvcnuQ1TTECdFf83na/cPDM5qKfJuoOan3gbMNVowKBgQDRr+MarMxNnoaH/XlY0HURtAUENieoyll72iHLofdlyQPDqoo0G00zjlV11DH/pH8qQ1PsswJDxL6oiY9XkxZ0P2Pd5BnYW8wSUdQ033ReSxc9WHlnTnixPp/YHraAmzZXncM6B8YJWAO5CtLW7Xym58BLUgMMH6FUM0gKiLMrowKBgQCx1alpJb3jrYjTnEdZifZalP4JK3DSTUtPzGTSz6el2m9JCjPKgTHgzwrfDVyEZH1219ehXe2f2Stgm4cgdHfe3GYM7HqxEIEYL/ucAAJqf3enus37eiFaWOA4Qj4M1LjchatoI483fnO1FjHhFjlKOZKLLYoZtyzOBkpFU+T4nQKBgQDNCpYj3ncFK4/X6NfBLk5b2lHRdXdAiWYJQxsq+Z1m7bJ9ogT0wQGz+Wm+B5pApkUnOaEWY1FCnV/mhGUjuJQLZnUsZEGVnOYnv9anQR6Umg8GkL5ec5B3mYpKlnXVunDgKkfeNf3D40n4pwnW23G58ALMZEzQjRl/sYmvq06wywKBgQCer3/ehngsL6xpdmWaWOyZja992F9s7JKb+M5esEltp5utpB9DEGrV1KKnLTWtM99vbxBEm5zeaYimdy1359YxzaDdmDm+w2tV+qjA3u3RgZpjqfw5uiASgL8hT12Rgme4itBC6tuhf3fZEGlQI5cKSJn+fB2XMXw/3S7RfGRT9w==
-----END PRIVATE KEY-----
""".strip()
# HASH Hex
sha256_hash = hashlib.sha256(data.encode('utf-8')).hexdigest()
print(f"Hash Hex: {sha256_hash}")
# HASH Base64
base64_hash = base64.b64encode(sha256_hash.encode('utf-8')).decode('utf-8')
print(f"Hash Base64: {base64_hash}")
# Signature
private_key = serialization.load_pem_private_key(priv_key_pem.encode('utf-8'), password=None, backend=default_backend())
signature = private_key.sign(sha256_hash.encode('utf-8'), padding.PKCS1v15(), hashes.SHA256())
signature_base64 = base64.b64encode(signature).decode('utf-8')
print(f"Signature: {signature_base64}")Обратите внимание, что в скрипте на Python ключ нужно использовать в PEM-формате (с элементами BEGIN и END).