Request Signing and Response Signature Validation - csob/paymentgateway GitHub Wiki
The security and trustworthiness of the communication between the merchant and the gateway is guaranteed by the signing of the calls (and responses) using the keys. The description of the process for obtaining the required keys can be found on the page Integration and API security.
Signing requests by the merchant is mandatory, verification of the signatures of the payment gateway responses is recommended.
Compilation of the signature calls
From the data sent to the server, TEXT_TO_SIGN is compiled by ordering the individual data items in the same order in which these are listed in the specification. The "|" delimiter is used to separate individual items. All parameters sent in the request are included in the list. If any of the optional parameters is not added, it will not appear in the resulting compiled chain.
If the message item is a nested data object, it is transmitted through the items of that object. In the case of a list (e.g. items in payment initialisation), items are inserted into the resulting string in the same order as these appear in the message.
Numbers are represented in ASCII form, characters are written in their binary representation (entities \uXXXX are not allowed).
The merchant's private key is subsequently used for the signature calculation itself:
signature = BASE64_ENCODE(RSA_SIGN(TEXT_TO_SIGN))
In the case of signature verification at the payment gateway for GET operations, parameter values are entered into the signature, which are "URL decoded".
An algorithm based on SHA-256 must be used for signing (Please note that in previous versions of eAPI 1.7 and older the SHA-1 algorithm was used, since version 1.8 SHA-256 was used). For example, in Java you need to use the "SHA256withRSA" algorithm when initialising the java.security.Signature class , for PHP it is necessary to use "OPENSSL_ALGO_SHA256", which is the default algorithm for the functions openssl_sign() and openssl_verify().
Example for creating the signature for a request sent using the POST method:
In the operation for payment initialization we sign the parameters as follows:
{
"merchantId":"M1MIPS0000",
"orderNo":"5547",
"dttm":"20220125131559",
"payOperation":"payment",
"payMethod":"card",
"totalAmount":123400,
"currency":"CZK",
"closePayment": true,
"returnUrl":"https://shop.example.com/return",
"returnMethod":"POST",
"cart":[
{
"name": "Wireless headphones",
"quantity": 1,
"amount": 123400
},
{
"name": "Shipping",
"quantity": 1,
"amount": 0,
"description": "DPL"
}
],
"merchantData":"some-base64-encoded-merchant-data",
"language":"cs",
"signature":"base64-encoded-signature-of-payment-request"
}
TEXT_TO_SIGN = "M1MIPS0000|5547|20220125131559|payment|card|123400|CZK|true|https://shop.example.com/return|POST|Wireless headphones|1|123400|Shipping|1|0|DPL|some-base64-encoded-merchant-data|cs"
signature = BASE64_ENCODE(RSA_SIGN(TEXT_TO_SIGN))
As can be seen, the optional customerId parameter is not filled in the request, nor is it part of the TEXT_TO_SIGN value. The value of merchantData is followed by the value of the parameter language - without the need to insert an extra delimiter | for an empty parameter.
When creating a TEXT_TO_SIGN value, the order of the items in the JSON request does not matter, which is determined by the order of the parameters specified in this specification.
Example for building a signature for payment / init containing nested structures
{
"merchantId":"M1MIPS0000",
"orderNo":"5547",
"dttm":"20220125131559",
"payOperation":"payment",
"payMethod":"card",
"totalAmount":123400,
"currency":"CZK",
"closePayment": true,
"returnUrl":"https://shop.example.com/return",
"returnMethod":"POST",
"cart":[
{
"name": "Wireless headphones",
"quantity": 1,
"amount": 123400
},
{
"name": "Shipping",
"quantity": 1,
"amount": 0,
"description": "DPL"
}
],
"customer": {
"name":"Jan Novák",
"email":"[email protected]",
"mobilePhone":"+420.800300300",
"account": {
"createdAt":"2022-01-12T12:10:37+01:00",
"changedAt":"2022-01-15T15:10:12+01:00"
},
"login": {
"auth":"account",
"authAt":"2022-01-25T13:10:03+01:00"
}
},
"order": {
"type":"purchase",
"availability":"now",
"delivery":"shipping",
"deliveryMode": "1",
"addressMatch":true,
"billing": {
"address1":"Karlova 1",
"city":"Praha",
"zip":"11000",
"country":"CZE"
}
},
"merchantData":"some-base64-encoded-merchant-data",
"language":"cs",
"signature":"base64-encoded-signature-of-payment-request"
}
TEXT_TO_SIGN = "M1MIPS0000|5547|20220125131559|payment|card|123400|CZK|true|https://shop.example.com/return|POST|Wireless headphones|1|123400|Shipping|1|0|DPL|Jan Novák|[email protected]|+420.800300300|2022-01-12T12:10:37+01:00|2022-01-15T15:10:12+01:00|account|2022-01-25T13:10:03+01:00|purchase|now|shipping|1|true|Karlova 1|Praha|11000|CZE|some-base64-encoded-merchant-data|cs"
signature = BASE64_ENCODE(RSA_SIGN(TEXT_TO_SIGN))
Example for creating a signature for a request sent using the PUT method:
In the operation for inserting payment into the queue for settlement the parameters merchantId, payId and dttm are signed as follows:
{
"merchantId":"M1MIPS0000",
"payId":"7624c5e60252@HA",
"dttm":"20220125131615",
"signature":"base64-encoded-request-signature"
}
TEXT_TO_SIGN = "M1MIPS0000|7624c5e60252@HA|20220125131615"
signature = BASE64_ENCODE(RSA_SIGN(TEXT_TO_SIGN))
Example for creating a signature for a request sent using the GET method:
In the operation (GET) echo the parameters merchantId and dttm are signed as follows:
Transmitted parameters must be "URL encoded".
curl -v -X GET https://api.platebnibrana.csob.cz/api/v1.9/echo/M1MIPS0000/20220125131615/url-encoded-signature
TEXT_TO_SIGN = "M1MIPS0000|20220125131615"
signature = BASE64_ENCODE(RSA_SIGN(TEXT_TO_SIGN))
Debugging of TEXT_TO_SIGN value for POST and PUT methods
The API on the sandbox environment returns for every POST or PUT request a special HTTP response header REQUEST_TEXT_TO_SIGN. It contains the value of TEXT_TO_SIGN string compiled from request parameters (the payment gateway uses this value to verify request signature). Using this response header the merchant can check whether the TEXT_TO_SIGN value compiled on the eshop's side corresponds to the value on the payment gateway side.
Response signature verification procedure
The signature contained in the signature parameter is always returned in responses from the payment gateway with the http response code 200 (for a more detailed description, see API Integration).
Similarly as with the creation of the request signature, a TEXT_TO_SIGN is created from the individual response items to verify the signature of the response and the public key of the payment gateway is used to verify the signature.
For the following response to create a payment using payment/init
{
"payId":"7624c5e60252@HA",
"dttm":"20220125131610",
"resultCode": 0,
"resultMessage":"OK",
"paymentStatus": 1,
"signature":"base64-encoded-response-signature"
}
The signature validation string will be as follows:
TEXT_TO_SIGN = "7624c5e60252@HA|20220125131610|0|OK|1"
For payments in the 4 or 7 state (response to payment/status, payment/close operations, etc.) an authorization code is also sent, which forms part of the signature:
{
"payId":"7624c5e60252@HA",
"dttm":"20220125131615",
"resultCode": 0,
"resultMessage":"OK",
"paymentStatus": 4,
"authCode": "qwFDF32",
"signature":"base64-encoded-response-signature"
}
The signature validation string will be as follows:
TEXT_TO_SIGN = "7624c5e60252@HA|20220125131615|0|OK|4|qwFDF32"
When redirecting from the payment gateway back to the e-shop, the response also includes the merchantData parameter (if it was passed within the payment/init operation) ...
{
"payId":"7624c5e60252@HA",
"dttm":"20220125131821",
"resultCode": 0,
"resultMessage":"OK",
"paymentStatus": 7,
"authCode": "qwFDF32",
"merchantData": "base64-encoded-merchant-data",
"signature":"base64-encoded-response-signature"
}
The signature validation string will be as follows:
TEXT_TO_SIGN = "7624c5e60252@HA|20220125131821|0|OK|7|qwFDF32|base64-encoded-merchant-data"
Note: In general, the parameters paymentStatus, authCode and merchantData are added to the signature verification string only if these are filled in (e.g. for a payment in state 3 the authCode will not be filled in but the parameter merchantData, the resulting string will then be in the format payId|dttm|resultCode|resultMessage|paymentStatus|merchantData).