Aller au contenu

Bonnes pratiques de sécurité

Les clés, les scopes, les listes d'IP autorisées et la réaction de l'API en cas de fuite.

La plupart des failles de paiement ne sont pas sophistiquées. Une clé secrète se retrouve dans un dépôt, une application mobile ou une capture d'écran envoyée dans une discussion. La personne qui la trouve peut alors faire tout ce que vous pouvez faire. Les contrôles présentés ici réduisent les conséquences de cette erreur : elle devient plus difficile à commettre, moins grave et plus rapide à corriger.

Trois types de clés, dont un seul peut être exposé

Une clé se compose d'un préfixe, d'un point et de 96 caractères aléatoires. Le préfixe détermine tout le modèle de sécurité.

PréfixeEmplacementAutorisations
pk. / pk_test.Navigateurs et applications mobilesDémarrer des paiements et lire les données de référence
sk. / sk_test.Votre serveur uniquementEffectuer toutes les actions autorisées à votre équipe
rk. / rk_test.Votre serveur, avec des scopesAccéder uniquement aux ressources sélectionnées

Wajub stocke le hash SHA-256, jamais la valeur, et recherche les clés à partir de ce hash. La fuite d'une sauvegarde de base de données ne révèle donc aucun identifiant utilisable. Pour vous, la conséquence est simple : la valeur n'est affichée qu'une fois, lors de la création ou du renouvellement de la clé.

Cinq contrôles avant d'atteindre un endpoint

Connaître leur ordre permet de comprendre les codes de statut, souvent attribués à la mauvaise cause.

ContrôleRefus avecSituation
Routage par environnementAucunLe préfixe sélectionne la base de données de la sandbox ou du mode live
Détection du navigateur403Une clé sk. arrive avec un en-tête Origin ou Referer
Vérification de l'identifiant401Clé inconnue, révoquée, inactive ou ayant dépassé expires_at
Liste d'IP autorisées403L'IP de l'appelant ne figure pas dans la liste de la clé
Classe de la clé406 ou 403Clé publique sur une route privée, ou scope absent de la clé

Restreignez la clé avant d'en avoir besoin

Deux contrôles s'appliquent à tous les types de clés, y compris les clés publiques, mais ils sont rarement activés.

Une liste d'IP autorisées limite une clé aux machines qui doivent l'utiliser. Les entrées sont des adresses IPv4 ou IPv6 exactes, ou des plages CIDR de l'une de ces familles. Une liste vide ne pose aucune restriction. Un appel provenant d'une autre adresse reçoit 403 IP address not allowed for this API key, quel que soit le type de clé. Si votre backend utilise une adresse de sortie fixe, une clé divulguée devient inutilisable.

Une date d'expiration limite la durée de vie de la clé. Une fois cette date dépassée, tous les appels répondent avec 401. Définissez-en une pour tout usage temporaire : clé d'un prestataire, script de migration ou démonstration.

Une clé utilisable uniquement depuis votre cluster
{
"type": "restricted",
"allowed_ips": [
"203.0.113.0/24",
"2001:db8::/32"
],
"expires_at": "2026-12-31T23:59:59Z",
"permissions": [
"payment.read",
"payment.write",
"refund.read"
]
}

Scopes disponibles pour une clé restreinte

Les scopes suivent le format {resource}.{read|write}. Le verbe détermine la partie requise : GET, HEAD et OPTIONS nécessitent read, tous les autres nécessitent write.

RessourceScopes
paymentpayment.read, payment.write
customercustomer.read, customer.write
transfertransfer.read, transfer.write
refundrefund.read, refund.write
recipientrecipient.read, recipient.write
invoiceinvoice.read, invoice.write
disputedispute.read, dispute.write
webhookwebhook.read, webhook.write
eventevent.read, event.write
linklink.read, link.write
identityidentity.read, identity.write
taxtax.read, tax.write
balancebalance.read
accountaccount.read
settingssettings.read, settings.write

Une clé restreinte est refusée sur toute route qui ne correspond à aucune ressource, avec le message 403 This API key cannot access this resource. Ce comportement est volontaire. Une clé restreinte fonctionne comme une liste d'autorisations, et non comme un filtre : si une route ne figure pas dans le tableau ci-dessus, la clé ne peut pas l'atteindre. Quatre chemins font exception et restent accessibles à toute clé valide, car ils ne contiennent aucune donnée sensible : /channels, /countries, /currencies et la racine de l'API.

Notez les deux lignes en lecture seule. balance et account ne possèdent aucun scope d'écriture. Une clé restreinte peut donc lire une connexion Sync, mais jamais en créer une. Utilisez pour cela une clé privée sur votre serveur.

Le renouvellement d'une clé est immédiat

Le renouvellement remplace immédiatement la valeur et vide les caches de l'ancienne clé. L'ancienne valeur cesse donc aussitôt de fonctionner. Il n'existe ni délai de grâce ni période de chevauchement. Renouveler la clé utilisée par votre checkout de production interrompt ce checkout jusqu'au déploiement de la nouvelle valeur.

La procédure sûre évite toute interruption.

  1. 1

    Créez une seconde clé du même type

    Votre équipe peut posséder plusieurs clés. La nouvelle fonctionne dès sa création.

  2. 2

    Déployez-la

    Transmettez la nouvelle valeur à chaque service qui appelle Wajub, puis attendez qu'aucun n'utilise encore l'ancienne.

  3. 3

    Vérifiez que l'ancienne clé est inactive

    Son champ last_used_at cesse d'évoluer lorsqu'elle n'est plus utilisée.

  4. 4

    Supprimez l'ancienne clé

    Elle est désormais désactivée, sans interruption visible.

Renouvelez une clé sur place uniquement lorsqu'elle est déjà compromise. Dans ce cas, une interruption coûte moins cher que de la laisser active.

En cas de fuite d'une clé

  1. 1

    Révoquez-la

    Supprimez-la ou désactivez-la dans le Dashboard. Dès cet instant, chaque appel qui l'utilise répond avec 401.

  2. 2

    Rétablissez une clé fonctionnelle

    Créez une clé de remplacement et déployez-la. Suivez la procédure ci-dessus pour les services encore actifs.

  3. 3

    Vérifiez les actions effectuées avec la clé

    Konsole contient le log des requêtes. Recherchez les appels provenant d'IP inconnues, en particulier les remboursements, les transferts et les bénéficiaires.

  4. 4

    Corrigez la faille

    Une clé présente dans l'historique git y reste après la modification du fichier. Renouvelez-la d'abord, puis nettoyez l'historique.

Les secrets de webhook sont aussi des identifiants

Chaque livraison est signée avec un secret propre à l'endpoint, et non à votre API key. Vérifiez la signature avant d'analyser le contenu. Renouvelez le secret comme une clé, avec POST /webhooks/{id}/rotate-secret.

Deux erreurs méritent d'être signalées, car le code semble fonctionner dans les deux cas. Si vous analysez le corps avant de vérifier la signature, toute personne qui connaît votre URL peut lancer la livraison de la commande. Comparer les signatures avec == révèle aussi des informations de temps d'exécution. Utilisez la comparaison en temps constant de votre langage après avoir vérifié que les deux chaînes ont la même longueur. Plusieurs implémentations lèvent une erreur au lieu de renvoyer false lorsque les longueurs diffèrent.

Vérification de signature présente l'implémentation manuelle pour les stacks sans SDK.

La sandbox et le mode live utilisent des bases distinctes

Le préfixe de la clé sélectionne la connexion à la base de données avant l'exécution de la première requête. Une clé pk_test. ou sk_test. accède à la base de la sandbox et ne peut pas lire une ligne du mode live. L'inverse est également vrai. Les identifiants des objets de la sandbox contiennent test_, ce qui permet de repérer immédiatement une valeur passée d'un environnement à l'autre.

C'est aussi pour cette raison qu'un identifiant provenant d'un environnement répond avec 404 dans l'autre, et non avec une erreur d'autorisation. La ressource n'y existe pas.

Vos responsabilités

  • Placez les clés dans des variables d'environnement, jamais dans le code source ni dans une variable intégrée au bundle par votre outil.
  • NEXT_PUBLIC_, VITE_, EXPO_PUBLIC_ et leurs équivalents signifient que la valeur sera publique. Seule une clé pk. peut utiliser l'un de ces préfixes.
  • Lors de la création d'un paiement, récupérez le montant dans votre propre base de données. Un prix provenant du navigateur peut avoir été choisi par le navigateur.
  • Attribuez à chaque service sa propre clé restreinte, avec les scopes nécessaires à ses actions.
  • Activez l'authentification à deux facteurs obligatoire pour votre équipe dans le Dashboard et donnez à chaque membre le rôle le plus limité qui lui permet de travailler.
  • Ajoutez une date d'expiration à tout élément temporaire.

Signaler une vulnérabilité

Envoyez-la à security@wajub.com au lieu d'ouvrir une issue publique. Indiquez ce que vous avez découvert, la procédure pour le reproduire et vos coordonnées.

Que pensez-vous de ce contenu ?