Sécurité
La sécurité d’une intégration de paiement repose sur quelques principes simples mais stricts. Cette page résume les pratiques attendues côté marchand.
Vos clés API et vos secrets webhook donnent accès à vos encaissements. Traitez-les comme des mots de passe : jamais dans le code versionné, jamais côté navigateur, jamais dans un dépôt public.
Clés API
- L’authentification de l’API publique se fait via l’en-tête
X-API-Key. - Deux préfixes selon l’environnement :
kadryza_test_…(sandbox) etkadryza_live_…(production). - Une clé n’est affichée qu’une seule fois à la création, depuis le dashboard. Stockez-la immédiatement.
- Conservez les clés dans des variables d’environnement côté serveur, jamais en dur dans le code.
# ✅ Bon - variable d'environnement, côté serveur
export KADRYZA_API_KEY="kadryza_live_•••"// ❌ À éviter - clé en dur, exposée côté client
const kadryza = new Kadryza({ apiKey: 'kadryza_live_abcd…' })Rotation : en cas de doute (fuite, départ d’un collaborateur), générez une nouvelle clé depuis le dashboard et révoquez l’ancienne. Utilisez des clés distinctes par environnement et par service.
Signature des webhooks
Chaque webhook est signé. Vérifiez toujours la signature avant de traiter l’événement.
- En-tête :
X-Kadryza-Signatureau formatsha256=<hmac>. - Algorithme : HMAC-SHA256 du corps brut de la requête, avec le secret de l’endpoint (64 caractères hexadécimaux) comme clé.
- Le secret est retourné une seule fois à la création de l’endpoint webhook.
import crypto from 'node:crypto'
function verifierSignature(corpsBrut: string, header: string | undefined, secret: string): boolean {
if (!header) return false
const attendu =
'sha256=' + crypto.createHmac('sha256', secret).update(corpsBrut).digest('hex')
const recu = Buffer.from(header)
const calcule = Buffer.from(attendu)
// timingSafeEqual lève une exception si les longueurs diffèrent : on compare d'abord.
if (recu.length !== calcule.length) return false
// Comparaison à temps constant pour éviter les attaques temporelles
return crypto.timingSafeEqual(recu, calcule)
}Ne faites jamais confiance au corps d’un webhook sans vérifier X-Kadryza-Signature.
Une requête non signée ou mal signée doit être rejetée.
Les webhooks payment_session.* de l’environnement test et les envois transaction.test portent en plus l’en-tête X-Kadryza-Test: true. Pour tout événement, data.environment ou le préfixe de la clé qui a créé l’objet indiquent l’environnement.
Transport (HTTPS)
- Tous les appels API se font en HTTPS uniquement.
- Votre URL de réception de webhook doit être publiquement accessible, et en HTTPS pour recevoir des événements live. Kadryza refuse les URL qui pointent vers des adresses privées ou locales.
Idempotence
Le réseau peut rejouer une requête ou une livraison de webhook. Rendez vos traitements idempotents :
- côté création de paiement, une commande = une
reference: en cas de doute après une coupure, relisez la session par sa référence au lieu d’en créer une nouvelle ; - côté réception de webhook, dédupliquez sur
event_id(en-têteX-Kadryza-Event-ID) ; pour les événementstransaction.*, qui n’en ont pas, surevent + data.id + data.status.
La signature ne couvre pas d’horodatage séparé : conserver les event_id déjà
traités est aussi votre protection contre le rejeu d’une livraison.
Données sensibles
- Kadryza ne manipule pas de données de carte bancaire : les paiements passent par le mobile money.
- Ne stockez aucune clé ni secret réel dans vos exemples, vos logs ou vos tickets de support.
- Limitez l’accès aux clés live aux seules personnes et services qui en ont besoin.
Signaler une vulnérabilité
Vous avez identifié un problème de sécurité ? Écrivez à contact@kadryza.com en décrivant le problème, sans le divulguer publiquement.