Bezpečnost

Bezpečnost

TLS

Veškerá komunikace s bránou je povinně zabezpečena použitím Transport Layer Security se serverovým certifikátem.

Server brány požaduje použití TLS verze 1.2 nebo vyšší.

Server brány požaduje použití ciphersuites aktuálně (Q3/2023) považovaných za silné. To jsou:

  • Ve verzi 1.2:

    • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

    • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

    • TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

  • Ve verzi 1.3:

    • TLS_AES_256_GCM_SHA384

    • TLS_CHACHA20_POLY1305_SHA256

    • TLS_AES_128_GCM_SHA256

Které ciphersuites jsou považované za silné se průběžně mění. Počítejte s tím, že tento výčet není pevný a server jej může změnit.

Autentizace e-shopu - authenticate()

Před zahájením platby se e-shop musí nejprve k bráně přihlásit operací POST: /auth/token. Operace slouží k ověření e-shopu a získání dočasného přístupového tokenu potřebného pro další komunikaci s bránou. Pro autentizaci této operace použijete schéma Basic podle RFC 7617 s přístupovými údaji eshopId a eshopPassword, které jste získali při registraci vašeho e-shopu.

Získaný token pak musíte poslat v návazných operacích s platbou.

Životnost tokenu je omezena do času vráceného ve validTo. V případě vypršení tokenu je potřeba požádat o nový.

Pokud brána e-shop neověří tak:

  • V testovacím prostředí brána požadavek zamítne s HTTP status 401.

  • V produkčním prostředí brána může požadavek ignorovat.

Ref: Platební brána | Sekvenční diagram platby #10, #11

Podepisování zpráv

Komunikace s bránou je dále zabezpečena elektronickým podepsáním jednotlivých vyměňovaných zpráv asymetrickou kryptografií.

Pokud je v požadavku operace specifikován podpis (pole signature) musíte:

  1. Sestavit pole z požadavku oddělená oddělovačem “|" (svislou čarou) do řetězce znaků k podepsání clearTextString.

  2. Podepsat metodou RSASSA-PKCS1-v1_5 specifikovanou v kapitole 8.2 RFC 8017 (SHA-256 with RSA) s použitím privátního podpisového klíče obchodníka ustanoveného při registraci vašeho e-shopu. Pro testovací prostředí viz Generování testovacích klíčů.

  3. Výsledný podpis zakódovat nejprve do Base64 a potom do URL encoded.

  4. Výsledný řetězec vložit do parametru signature, který nikdy není součástí podepisovaného řetězce.

Pole požadavku skládejte do řetězce k podepsání clearTextString vždy v pořadí, v jakém jsou uvedeny v tabulce níže.

Nezapomeňte, že pořadí záznamů v JSON není garantované.

Nepovinná pole, která nejsou v požadavku přítomná, do clearTextString nevkládejte. Nevkládejte ani jejich případné oddělovače.

Textová pole začínající a/nebo končící neviditelnými znaky budou bránou odmínuta jako nevalidní.

Při kontrole podpisu požadavku bránou budou textová pole s nulovou délkou považována za nepřítomná a do kontroly nebudou zahrnuta.

 

Skladba řetězce k podpisu v požadavcích jednotlivých operací

Operace

Seznam a pořadí polí ke vložení do řetězce k podepsání clearTextString - tučně jsou povinná

Operace

Seznam a pořadí polí ke vložení do řetězce k podepsání clearTextString - tučně jsou povinná

initPayment()

x-correlation-id*, amount, productCode, orderReferenceCode, orderDescription, merchantData, returnUrl, language

  • x-correlation-id je header parameter.

getPaymentState()

paymentId

cancelPayment()

paymentId

Příklad sestavení řetězce k podpisu pro operaci initPayment()

Budou složeny hodnoty z polí: amount, productCode, orderReferenceCode, merchantData, returnUrl, language, protože pole x-correlation-id a orderDescription jako nepovinná obchodník nevyplnil.

clearTextString=1250|LEISURE|34324Q22A4|cMWZw61rYWQ7ZGF0O29iY2hvZG7DrWth|https:/partners.eshop.cz/returns|cs

Příklad vytvoření podpisu operace getPaymentState()

Do clearTextString bude vloženo jen paymentId. Příklad hodnoty paymentId je “EC42E6695FFADAE5D0017952F0CF7A69”.

clearTextString=EC42E6695FFADAE5D0017952F0CF7A69

https://pay.benefit-plus.cz/v3/payments/EC42E6695FFADAE5D0017952F0CF7A69/state?signature=URL-encoded-Base64-encoded-hodnota-podpisu-vypočteného-z-řetězce-EC42E6695FFADAE5D0017952F0CF7A69

Příklad podepsání řetězce v jazyku Java

Příklady jsou poskytované tak jak jsou, bez záruky jejich použitelnosti ve vašem konkrétním eshopu!

/* merchantsPrivateKeyBytes is your private key in PKCS#8 clearTextString is compounded from selected request fields separated by the | (vertical bar) ordered according to this spec */ java.security.PrivateKey merchantsPrivateKey = java.security.KeyFactory.getInstance("RSA").generatePrivate(new java.security.spec.PKCS8EncodedKeySpec(merchantsPrivateKeyBytes)); java.security.Signature requestSignature = java.security.Signature.getInstance("SHA256withRSA"); requestSignature.initSign(merchantsPrivateKey); requestSignature.update(clearTextString.getBytes(java.nio.charset.StandardCharsets.UTF_8)); byte[] signatureBytes = requestSignature.sign(); String signatureString = java.net.URLEncoder.encode(java.util.Base64.getEncoder().encodeToString(signatureBytes), java.nio.charset.StandardCharsets.UTF_8);

 

Příklad podepsání řetězce v jazyku PHP

Příklady jsou poskytované tak jak jsou, bez záruky jejich použitelnosti ve vašem konkrétním eshopu!

<?php $dataToSign = "2500|LEISURE|ord3436232|https://eshop.partnerx.cz/returns|cs"; $privateKey = "-----BEGIN RSA PRIVATE KEY----- ... insert here your private key in ASN.1 encoded as DER according to PKCS#1 (traditional) -----END RSA PRIVATE KEY-----"; try { // Instatiates a private key $pkeyid = openssl_get_privatekey($privateKey); // Signs the data openssl_sign($dataToSign, $signature, $pkeyid, OPENSSL_ALGO_SHA256); // Releases the key resource openssl_free_key($pkeyid); // Otputs signature encoded in Base64 echo base64_encode($signature); echo "<br>"; // Otputs signature encoded in Base64 and then URL encoded echo urlencode(base64_encode($signature)); } catch (Exception $e) { http_response_code(500); echo 'Signing Error: ', $e->getMessage(), "\n"; } ?>

Kontrola požadavků e-shopu

Pokud je v požadavku operace specifikován podpis (pole signature) brána jej vždy ověří. Pokud kontrola podpisu selže, tak:

  • V testovacím prostředí brána zamítne požadavek s HTTP status 403 a s označením chybného pole signature.

  • V produkčním prostředí brána může požadavek ignorovat, nebo ho zamítnout s HTTP 401.

Kontrola odpovědí brány

Doporučujeme vám kontrolovat podpisy odpovědí přijatých z brány pomocí veřejného klíče brány. Můžete tak ověřit, že zprávy nejsou podvržené.

Testovací klíč

v X.509 formátu.

-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzMvwEmT983FnrEXC8nfX F+o+AKKvoGAOTUE+Ivo1EtsXBGAfavoj+xmWP+P8A+itquX7XWCX71Hh6VW/zeXJ YHrK60PdGYICAhjcWH4s7Lb/E1V0hQzhXl2hgs+O5ZruJoSel+obd1JX05scPVFo vhk4HPpWVcj2oOgTNEJ4wV4NlwUFbJuxNhWM0Wu5zfElqRAlgPhpS90u3bV1O1Xw WHSYcgYrvNfb3AKs/9AdjOKaPw53QIZu5PR4jLIf/3b3xfNm2cP5uZUxpHuxRAtq c6xjqaKnHwjhcOGiZWb+OE74t9SxOr8fpbu6Qug+5LTv0YfRDSITB4eAr/CbunaD BQIDAQAB -----END PUBLIC KEY-----

Produkční klíč

V X.509 formátu.

-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyeGC0UUZl4sOKPvVFJ5Z Mouy4R9E4PuXOqryxjk4NfUZElFMx5aLLLp1zWVDWKxjkR8Q9iNDpgs2fOUD24+M OilT5qXS63xzyTEpoVjJBMjCQZ+roUOMg+J7JWbn0kiC2dRCanfCYbFPQTEimR0v iH7jePiavl8MeEz4Xxcfa84eV0mcaph9dJhs1FADTCI2hkgpCbxcjDzfEGRmA+v9 KN6mLvl7cWMiFBSvBe4btBb7oa8ba/HOyxOQKOSNJt0Vnpr4njU2wc+Bfh+IdOue Pn5ukv8CeyonOPgrb2xNVbVxPLS96EsGQldKGQnY5iNyqEvGtKpig1358B7X5/4K LwIDAQAB -----END PUBLIC KEY-----

Brána používá stejnou metodu (RSASSA-PKCS1-v1_5) podepisování odpovědí, jakou používáte při podepsování požadavků.

V případě neověření podpisu byste takové odpovědi neměli důvěřovat.

Skladba řetězce clearTextString ke kontrole odpovědí z jednotlivých operací:

Operace

Seznam a pořadí polí ke vložení do kontrolního řetězce clearTextString - pokud jsou součástí odpovědi brány

Operace

Seznam a pořadí polí ke vložení do kontrolního řetězce clearTextString - pokud jsou součástí odpovědi brány

initPayment() response

x-correlation-id, paymentId, orderReferenceCode, beneficiaryId, amount, currency, gatewayUrl

getPaymentState() reponse

x-correlation-id, paymentId, amountAuthorized remainingAmount (version 2), paymentState, paymentDateTime, responseCode, orderReferenceCode, responseMessage

Příklad kontroly podpisu v jazyku Java

Příklady jsou poskytované tak jak jsou, bez záruky jejich použitelnosti ve vašem konkrétním eshopu!

* gatewayPublicKeyString is a gateway's public key in X509 format encoded in Base64 clearTextString is compounded from selected response fields separated by the | (vertical bar) ordered according to this spec receivedSignature is a value of signature field received in a gateway response */ java.security.PublicKey gatewayPublicKey = java.security.KeyFactory.getInstance("RSA").generatePublic(new java.security.spec.X509EncodedKeySpec(java.util.Base64.getDecoder().decode(gatewayPublicKeyString))); java.security.Signature recalculatedSignature = java.security.Signature.getInstance("SHA256withRSA"); recalculatedSignature.initVerify(gatewayPublicKey); recalculatedSignature.update(clearTextString.getBytes(java.nio.charset.StandardCharsets.UTF_8)); boolean canITrustTheResponse = recalculatedSignature.verify(java.util.Base64.getDecoder().decode(receivedSignature));

Příklad kontroly podpisu v jazyku PHP

Příklady jsou poskytované tak jak jsou, bez záruky jejich použitelnosti ve vašem konkrétním eshopu!

<?php // Public key of the gateway (use the right value for the environment) $publicKey = "-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzMvwEmT983FnrEXC8nfX F+o+AKKvoGAOTUE+Ivo1EtsXBGAfavoj+xmWP+P8A+itquX7XWCX71Hh6VW/zeXJ YHrK60PdGYICAhjcWH4s7Lb/E1V0hQzhXl2hgs+O5ZruJoSel+obd1JX05scPVFo vhk4HPpWVcj2oOgTNEJ4wV4NlwUFbJuxNhWM0Wu5zfElqRAlgPhpS90u3bV1O1Xw WHSYcgYrvNfb3AKs/9AdjOKaPw53QIZu5PR4jLIf/3b3xfNm2cP5uZUxpHuxRAtq c6xjqaKnHwjhcOGiZWb+OE74t9SxOr8fpbu6Qug+5LTv0YfRDSITB4eAr/CbunaD BQIDAQAB -----END PUBLIC KEY-----"; // Response data as received from the gateway // NOTE: use all the value strings exactly as receieved! $data = [ 'x-correlation-id' => '52BEFD5C95B84DF39549C402C241F900', 'paymentId' => '2A69ABB4829C4A41A5D0F7613A493220', 'orderReferenceCode' => '140654', 'beneficiaryId' => 'AAEEAA00001000000000200000000032', 'amount' => '600', 'currency' => 'CZK', 'gatewayUrl' => 'https://gateway-ui-dot-benefit-plus-sandbox-398907.ey.r.appspot.com/cs/sNax7vVyrqKLskX%2FfM0PpbDraOmDeXz82SKn8IEdYSed%2FYFKseHZRFyZUhi8IBPL3bXTG7Edwn53SDo0kgfCW18p', 'signature' => 'D9vIf/nMRxTLJ7EG3dHsXUH6QnI+HnEuAKBFP/LpbegjNKSJHB3/9j+IEZHgocQdWMf7bdzfPkqpDBFXcuFe4mjhAveEY7x5QiPNZ25EapyqYarv7WRN0WOTGhe9Y7F+lq+1ynavgN/CjawrJ9iy0uSuGmnfNexcYGqd2TgQPUPn5kzDdfZ0085X8h+Xx478OpIotUWTh4cWGmqjH3oun3nFOBUAx0Jyddw4ifDXWBtE2jLgD9tSMrZZsV5N48blNTjRwdpE50pCaTzLs/l3AcVbp6CAtxU/5ENtFvBcC5NiO8Ya/ZSiRU+ZPfwKF/BUJHahkp/Z+0cEIjRqp6tS4Q==' ]; // InitPayment response fields order $fields = [ 'x-correlation-id', 'paymentId', 'orderReferenceCode', 'beneficiaryId', 'amount', 'currency', 'gatewayUrl' ]; // Concatenation of the string for validation $values = []; foreach ($fields as $field) { if (isset($data[$field])) { $values[] = $data[$field]; } } $clearTextString = implode('|', $values); // Signature validation $key = openssl_pkey_get_public($publicKey); if ($key === false) { die('Invalid public key'); } $signature = base64_decode($data['signature']); if ($signature === false) { die('Invalid signature format (Base64)'); } $result = openssl_verify($clearTextString, $signature, $key, OPENSSL_ALGO_SHA256); openssl_free_key($key); if ($result === 1) { echo "Signature is valid\n"; } elseif ($result === 0) { echo "Signature is invalid\n"; } else { echo "Signature validation error: " . openssl_error_string() . "\n"; } ?>

 

Příklad kontroly podpisu pomocí OpenSSL (and Unix shell-u)

Příklady jsou poskytované tak jak jsou, bez záruky jejich použitelnosti ve vašem konkrétním eshopu!

# CORRELATION_ID is `x-correlation-id` header of response # RESPONSE is response body of init payment request RESPONSE_CLEAR_TEXT="${CORRELATION_ID}|$(jq -r .paymentId <<< $RESPONSE)|$(jq -r .orderReferenceCode <<< $RESPONSE)|$(jq -r .beneficiaryId <<< $RESPONSE)|$(jq -r .amount <<< $RESPONSE)|$(jq -r .currency <<< $RESPONSE)|$(jq -r .gatewayUrl <<< $RESPONSE)" echo echo "Response clear text:" # be sure to not introduce any new lines to cleartext printf "%s" "${RESPONSE_CLEAR_TEXT//[$'\n']}" > response.cleartext cat -A response.cleartext jq -r .signature <<< $RESPONSE | base64 --decode > response.signature #public.pem is public key provided by MúzaPay echo echo "Response signature verification:" openssl dgst -sha256 -verify public.pem -keyform PEM -signature response.signature response.cleartext

Ochrana přístupových dat

Pro bezpečnost použití platební brány je kritické, abyste udrželi v tajnosti:

  • vaše přístupové heslo eshopPassword

  • váš privátní klíč z páru pro podepisování požadavků.

Nastavte proto vaše procesy tak, aby nedošlo k jejich vyzrazení. Pokud k němu přesto dojde, informujte neprodleně Benefit Management.

Informace k PCI DSS

Platební brána žádným způsobem nepracuje s daty bankovních (ani jiných) platebních karet a nepodléhá tedy PCI standardům.

Brána MúzaPay je postavena na principu scanování QR prezentovaného obchodníkem (MPQR/Scan & Pay/Scan to Pay). Platby jsou autorizované ověřením identity plátce v mobilní aplikaci MúzaPay, buď s pomocí biometrie nebo PINu. Jde o funkční obdobu 3D Secure v2 klíčů v současných internetových bankovnictvích.