Skip to content

Instantly share code, notes, and snippets.

@nathan818fr
Last active June 18, 2019 10:39
Show Gist options
  • Save nathan818fr/c11a2a0f3fcae0834975a25e8557895d to your computer and use it in GitHub Desktop.
Save nathan818fr/c11a2a0f3fcae0834975a25e8557895d to your computer and use it in GitHub Desktop.
  1. On crée la commande, les identifiants wsLogin et wsPassword sont forcément spécifiés sinon la commande ne pourrait pas être créee.

> POST https://test-ws.hipay.com//soap/payment-v2/generate:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="https://test-ws.hipay.com/soap/payment-v2">
  <SOAP-ENV:Body>
    <ns1:generate>
      <parameters>
        <wsLogin>8a413ed7b226cbf7dc068a730ca96a3d</wsLogin>
        <wsPassword>********************************</wsPassword>
        <websiteId>573429</websiteId>
        <categoryId>621</categoryId>
        <amount>4.99</amount>
        <currency>EUR</currency>
        <rating>ALL</rating>
        <locale>en_US</locale>
        <customerIpAddress>127.0.0.1</customerIpAddress>
        <description>Order description</description>
        <executionDate>2019-06-18T09:27:38</executionDate>
        <manualCapture>0</manualCapture>
        <urlCallback>http://00ead46c.ngrok.io</urlCallback>
      </parameters>
    </ns1:generate>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

< Response:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="https://test-ws.hipay.com/soap/payment-v2">
  <SOAP-ENV:Body>
    <ns1:generateResponse>
      <generateResult>
        <redirectUrl>https://test-payment.hipay.com/index/ws/id/a7821290e89e3e31aa20fbb61134b4d4</redirectUrl>
        <code>0</code>
        <description>N/A</description>
      </generateResult>
    </ns1:generateResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
  1. On va sur la page de paiement indiquée par redirectUrl et on effectue le paiement.
    Puis on attend que la notification soit envoyée au serveur...

< Notification (authorization):

<?xml version="1.0" encoding="UTF-8"?>
<mapi>
  <mapiversion>1.0</mapiversion>
  <md5content>4a533f46b102bc190a61dc84f55d6d7e</md5content>
  <result><operation>authorization</operation><status>ok</status><date>2019-06-18</date><time>09:24:38 UTC+0000</time><origAmount>4.99</origAmount><origCurrency>EUR</origCurrency><idForMerchant/><emailClient>customer@example.com</emailClient><idClient>762443</idClient><cardCountry>US</cardCountry><ipCountry>FR</ipCountry><merchantDatas/><transid>5D08ADCC0E2C1236</transid><is3ds>No</is3ds><paymentMethod>VISA</paymentMethod><customerCountry>FR</customerCountry><returnCode/><returnDescriptionShort/><returnDescriptionLong/></result>
</mapi>
  1. On vérifie la signature de la notification avec md5content comme indiqué ici:
signature = md5('<result>...</result>' + wsPassword);

Dans mon cas le résultat est: 'a914f4de5519100e2fdbc3c3ce01b305'
Donc signature est différent de md5content => la notification est invalide!

Par contre, si on essaye sans concaténer wsPassword:

signature = md5('<result>...</result>');

On obtiens: '4a533f46b102bc190a61dc84f55d6d7e'
Cette fois, signature est égal à md5content.


Conclusion : md5content n'est qu'un hash md5 de '<result>...</result>' et ne fournis donc aucune sécurité concernant l'authenticité de la notification.
Par conséquent, n'importe qui trouvant l'endpoint sur lequel sont envoyés les notifications peut crafter ses propres notifications pour potentiellement abuser du système de paiement.

Mais même si le système de signature fonctionnait il semble comporter quelques points faibles:

  • L'utilisation de l'algorithme md5 qui n'est plus sûr pour de la cryptographie (l'ancienneté de l'API explique surement son utilisation).
  • L'utilisation d'une concaténation plutôt que d'un HMAC (voir https://crypto.stackexchange.com/a/15074).
  • Les erreurs d'implémentation qui arrivent facilement lorsque l'on récupère le contenu de '<result>...</result>':
    Par exemple, la librairie hipay-wallet-sdk-magento utilise strrpos afin de récupérer la string du result (https://github.com/hipay/hipay-wallet-sdk-magento/blob/cb62049efe447c5ad37ce4730e686a2e536f0581/src/app/code/local/HimediaPayments/Hipay/controllers/MapiController.php#L583).
    Un hacker qui parviendrait à récupérer une seule notification valide pourrait alors en crafter des fausses:
    <?xml version="1.0" encoding="UTF-8"?>
    <mapi>
      <mapiversion>1.0</mapiversion>
      <md5content>ORIGINAL_MD5CONTENT</md5content>
      <result>HACKER_TAMPERED_RESULT</result>
      <!--<result>ORIGINAL_RESULT</result>-->
    </mapi>
    
    (dans cet exemple, la librairie vérifiera le '<result>ORIGINAL_RESULT</result>' (qui est commenté) puisqu'elle utilise strrpos qui récupère la dernière occurrence! Par contre, le parser XML décodera le résultat altéré par le hacker!)

Une bonne solution serait d'implémenter une signature sur l'ensemble de la réponse avec un algorithme plus sûr:

signature = HMAC-SHA256(wsPassword, NOTIFICATION_BODY)

Puis d'envoyer cette signature dans un header HTTP (ex: X-Signature-Sha256). En bonus, de cette façon la version actuelle resterait complètement retro compatible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment