Sygnatura
Paymentic przy każdej notyfikacji przesyła sygnaturę w nagłówku X-Paymentic-Signature
Sygnatura notyfikacji może zostać obliczona za pomocą HASH HMAC SHA512 (RFC 2104 i RFC 6234).
Struktura do generowania sygnatury
W strukturze należy złączyć wartości (konkatenacja) z nagłówków i body oddzielając jest |
(Unicode U+007C) w kolejności: X-Paymentic-Event, User-Agent (Wersja z user-agenta np. 1.1),
Body, X-Paymentic-Notification-Id, X-Paymentic-Time
PAYMENT.TRANSACTION_STATUS_CHANGED|1.1|{"transactionId":"FJRS-LY7-3W0-30K9","pointId":"000cb241","status":"CREATED","amount":10,"currency":"PLN","commission":null,"custom":null,"channelId":null}|01j96yn02bhbv8j1jjtk36zn2t|2024-09-20T09:48:03+02:00
Przykłady jak wygenerować sygnaturę w różnych językach
- PHP
- Node.js
- Python
- Java
<?php
$signatureKey = '99ab572393014a7c2f20fe53253fc37819371a033c4507055e94e816683b9c8d';
$payload = 'PAYMENT.TRANSACTION_STATUS_CHANGED|1.1|{"transactionId":"FJRS-LY7-3W0-30K9","pointId":"000cb241","status":"CREATED","amount":10,"currency":"PLN","commission":null,"custom":null,"channelId":null}|01j96yn02bhbv8j1jjtk36zn2t|2024-09-20T09:48:03+02:00';
echo base64_encode(hash_hmac('sha512', $payload, $signatureKey, true));
Do porównania otrzymanej sygnatury z własnym wynikiem użyj hash_equals($received, $computed) zamiast === — chroni to przed atakiem timingowym.
const crypto = require('crypto');
const signatureKey = '99ab572393014a7c2f20fe53253fc37819371a033c4507055e94e816683b9c8d';
const payload = 'PAYMENT.TRANSACTION_STATUS_CHANGED|1.1|{"transactionId":"FJRS-LY7-3W0-30K9","pointId":"000cb241","status":"CREATED","amount":10,"currency":"PLN","commission":null,"custom":null,"channelId":null}|01j96yn02bhbv8j1jjtk36zn2t|2024-09-20T09:48:03+02:00';
const signature = crypto
.createHmac('sha512', signatureKey)
.update(payload)
.digest('base64');
console.log(signature);
Do porównania otrzymanej sygnatury z własnym wynikiem użyj crypto.timingSafeEqual(Buffer.from(received), Buffer.from(computed)) — chroni to przed atakiem timingowym. Pamiętaj, że oba bufory muszą mieć tę samą długość.
import hmac
import hashlib
import base64
signature_key = b'99ab572393014a7c2f20fe53253fc37819371a033c4507055e94e816683b9c8d'
payload = b'PAYMENT.TRANSACTION_STATUS_CHANGED|1.1|{"transactionId":"FJRS-LY7-3W0-30K9","pointId":"000cb241","status":"CREATED","amount":10,"currency":"PLN","commission":null,"custom":null,"channelId":null}|01j96yn02bhbv8j1jjtk36zn2t|2024-09-20T09:48:03+02:00'
signature = base64.b64encode(
hmac.new(signature_key, payload, hashlib.sha512).digest()
).decode()
print(signature)
Do porównania otrzymanej sygnatury z własnym wynikiem użyj hmac.compare_digest(received, computed) zamiast == — chroni to przed atakiem timingowym.
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class SignatureExample {
public static void main(String[] args) throws Exception {
String signatureKey = "99ab572393014a7c2f20fe53253fc37819371a033c4507055e94e816683b9c8d";
String payload = "PAYMENT.TRANSACTION_STATUS_CHANGED|1.1|{\"transactionId\":\"FJRS-LY7-3W0-30K9\",\"pointId\":\"000cb241\",\"status\":\"CREATED\",\"amount\":10,\"currency\":\"PLN\",\"commission\":null,\"custom\":null,\"channelId\":null}|01j96yn02bhbv8j1jjtk36zn2t|2024-09-20T09:48:03+02:00";
Mac mac = Mac.getInstance("HmacSHA512");
mac.init(new SecretKeySpec(signatureKey.getBytes(StandardCharsets.UTF_8), "HmacSHA512"));
byte[] digest = mac.doFinal(payload.getBytes(StandardCharsets.UTF_8));
String signature = Base64.getEncoder().encodeToString(digest);
System.out.println(signature);
}
}
Do porównania otrzymanej sygnatury z własnym wynikiem użyj MessageDigest.isEqual(received.getBytes(), computed.getBytes()) zamiast String.equals — chroni to przed atakiem timingowym.