Skip to content

Podpis požadavku a ověření podpisu odpovědi

Daniel Marek edited this page Apr 24, 2023 · 3 revisions

K zabezpečení a zajištění důvěryhodnosti komunikace mezi obchodníkem a bránou slouží podepisování volání (a odpovědí) pomocí klíčů, jejichž získání je popsané v části věnované API integraci a zabezpečení.

Podepisování požadavků obchodníkem je povinné, ověřování podpisů odpovědí brány u obchodníka doporučujeme.

Sestavení podpisu volání  

Z dat odesílaných na server sestavíme RETEZEC_ZPRAVY tak, že jednotlivé datové položky seřadíme za sebe v pořadí, v jakém jsou ve specifikaci uvedeny. Pro oddělení jednotlivých položek se použije oddělovač "|". Do výpočtu zahrneme všechny parametry odeslané v požadavku. Pokud tedy nebude některý nepovinný parametr použit, nebude ani ve výsledném řetězci.

Pokud je položkou zprávy vnořený datový objekt, prostupuje se položkami tohoto objektu. V případě seznamu (např. položky items v inicializaci platby) se do výsledného řetězce vkládají položky ve stejném pořadí, v jakém jsou uvedeny ve zprávě.

Čísla jsou reprezentována v ASCII podobě, znaky jsou zapisované ve své binární reprezentaci (nejsou povoleny entity \uXXXX).

Pro samotný výpočet podpisu se pak použije privátní klíč obchodníka:

signature = BASE64_ENCODE(RSA_SIGN(RETEZEC_ZPRAVY))

V případě ověření podpisu na platební bráně u GET operací do podpisu vstupují hodnoty parametrů, které jsou "URL dekódovány".

Pro podepisování je potřeba použít algoritmus založený na SHA-256 (Pozor, v předchozích verzích eAPI 1.7 a starších byl použit algoritmus SHA-1, od verze 1.8 byl použit SHA-256). Například v Javě je potřeba použít při inicializaci třídy java.security.Signature algoritmus "SHA256withRSA", v PHP je potřeba použít "OPENSSL_ALGO_SHA256", což je defaultní algoritmus pro funkce openssl_sign() a openssl_verify().

Příklad sestavení podpisu pro požadavek posílaný pomocí metody POST:

V operaci pro založení platby podepisujeme parametry následujícím způsobem:

{
  "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"
}
RETEZEC_ZPRAVY = "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(RETEZEC_ZPRAVY))

Jak je vidět, nepovinný parametr customerId není v požadavku vyplněn, není ani součástí hodnoty RETEZEC_ZPRAVY. Po hodnotě merchantData následuje hodnota parametru language - bez nutnosti vkládat extra odddělovač | pro nevyplněný parametr.

Při vytváření hodnoty RETEZEC_ZPRAVY nezáleží na pořadí položek v JSON požadavku, určující je pořadí parametrů uvedených v této specifikaci.

Příklad sestavení podpisu pro payment/init obsahující zanořené struktury

{
  "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"
}
RETEZEC_ZPRAVY = "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(RETEZEC_ZPRAVY))

Příklad sestavení podpisu pro požadavek posílaný pomocí metody PUT:

V operaci pro zařazení platby do zúčtování podepisujeme parametry merchantId, payId a dttm následujícím způsobem:

{
  "merchantId":"M1MIPS0000",
  "payId":"7624c5e60252@HA",
  "dttm":"20220125131615",
  "signature":"base64-encoded-request-signature"
}
RETEZEC_ZPRAVY = "M1MIPS0000|7624c5e60252@HA|20220125131615"
signature = BASE64_ENCODE(RSA_SIGN(RETEZEC_ZPRAVY))

Příklad sestavení podpisu pro požadavek posílaný pomocí metody GET:

V operaci (GET) echo podepisujeme parametry merchantId a dttm následujícím způsobem:

Přenášené parametry musí být "URL enkódovány".

curl -v -X GET https://api.platebnibrana.csob.cz/api/v1.9/echo/M1MIPS0000/20220125131615/url-encoded-signature
RETEZEC_ZPRAVY = "M1MIPS0000|20220125131615"
signature = BASE64_ENCODE(RSA_SIGN(RETEZEC_ZPRAVY))

Možnost debuggingu hodnoty RETEZEC_ZPRAVY pro POST a PUT metody

API v integrační prostředí vrací pro každý POST a PUT požadavek speciální HTTP response header REQUEST_TEXT_TO_SIGN. Obsahuje hodnotu RETEZEC_ZPRAVY sestavenou z parametrů přijatého požadavku (platební brána tuto hodnotu následně použije pro ověření podpisu požadavku). Pomocí této response header si může obchodník zkontrolovat, zda hodnota RETEZEC_ZPRAVY sestavená na straně eshopu odpovídá tomu, co sestaví platební brána.

Postup ověření podpisu odpovědi  

V odpovědích z platební brány s http response kódem 200 je vždy vrácen podpis obsažený v parametru signature (detailnější popis viz Volání rozhraní eAPI).

Podobně jako u vytvoření podpisu požadavku se pro ověření podpisu odpovědi z jednotlivých položek odpovědi vytvoří RETEZEC_ZPRAVY a pro ověření podpisu se použije veřejný klíč platební brány.

Pro následující odpověď pro založení platby pomocí payment/init

{
  "payId":"7624c5e60252@HA",
  "dttm":"20220125131610",
  "resultCode": 0,
  "resultMessage":"OK",
  "paymentStatus": 1,
  "signature":"base64-encoded-response-signature"
 }

bude řetězec pro ověření podpisu následující:

RETEZEC_ZPRAVY = "7624c5e60252@HA|20220125131610|0|OK|1"

U plateb ve stavu 4 nebo 7 (odpověď u operací payment/status, payment/close apod.) se posílá i autorizační kód, který je také součástí podpisu:

{
  "payId":"7624c5e60252@HA",
  "dttm":"20220125131615",
  "resultCode": 0,
  "resultMessage":"OK",
  "paymentStatus": 4,
  "authCode": "qwFDF32",
  "signature":"base64-encoded-response-signature"
 }

řetězec pro ověření podpisu bude následující:

RETEZEC_ZPRAVY = "7624c5e60252@HA|20220125131615|0|OK|4|qwFDF32"

Při přesměrování z platební brány zpět na e-shop je součástí odpovědi i parametr merchantData (pokud byl předán v rámci operace payment/init) ...

{
  "payId":"7624c5e60252@HA",
  "dttm":"20220125131821",
  "resultCode": 0,
  "resultMessage":"OK",
  "paymentStatus": 7,
  "authCode": "qwFDF32",
  "merchantData": "base64-encoded-merchant-data",
  "signature":"base64-encoded-response-signature"
 }

řetězec pro ověření podpisu bude následující:

RETEZEC_ZPRAVY = "7624c5e60252@HA|20220125131821|0|OK|7|qwFDF32|base64-encoded-merchant-data"

Poznámka: obecně platí, že parametry paymentStatus, authCode a merchantData se přidávají do řetězce pro ověření podpisu, jen pokud jsou vyplněné (např. pro platbu ve stavu 3 nebude vyplněn authCode, ale bude vyplněn parametr merchantData, výsledný řetězec pak bude ve formátu payId|dttm|resultCode|resultMessage|paymentStatus|merchantData).

Clone this wiki locally