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éfixe | Emplacement | Autorisations |
|---|---|---|
pk. / pk_test. | Navigateurs et applications mobiles | Démarrer des paiements et lire les données de référence |
sk. / sk_test. | Votre serveur uniquement | Effectuer toutes les actions autorisées à votre équipe |
rk. / rk_test. | Votre serveur, avec des scopes | Accé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ôle | Refus avec | Situation |
|---|---|---|
| Routage par environnement | Aucun | Le préfixe sélectionne la base de données de la sandbox ou du mode live |
| Détection du navigateur | 403 | Une clé sk. arrive avec un en-tête Origin ou Referer |
| Vérification de l'identifiant | 401 | Clé inconnue, révoquée, inactive ou ayant dépassé expires_at |
| Liste d'IP autorisées | 403 | L'IP de l'appelant ne figure pas dans la liste de la clé |
| Classe de la clé | 406 ou 403 | Clé publique sur une route privée, ou scope absent de la clé |
L'utilisation d'une clé privée dans un navigateur est signalée, pas seulement refusée
Wajub lit Origin et Referer. Une clé sk. envoyée avec l'un de ces en-têtes est refusée avec
un code 403. Un e-mail d'alerte est envoyé au propriétaire de la clé, avec une limite d'un
message par clé et par heure. Vous serez informé de la fuite, mais la clé se trouvera déjà dans une
application téléchargée par quelqu'un. Renouvelez-la.
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.
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.
| Ressource | Scopes |
|---|---|
payment | payment.read, payment.write |
customer | customer.read, customer.write |
transfer | transfer.read, transfer.write |
refund | refund.read, refund.write |
recipient | recipient.read, recipient.write |
invoice | invoice.read, invoice.write |
dispute | dispute.read, dispute.write |
webhook | webhook.read, webhook.write |
event | event.read, event.write |
link | link.read, link.write |
identity | identity.read, identity.write |
tax | tax.read, tax.write |
balance | balance.read |
account | account.read |
settings | settings.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
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
Déployez-la
Transmettez la nouvelle valeur à chaque service qui appelle Wajub, puis attendez qu'aucun n'utilise encore l'ancienne.
- 3
Vérifiez que l'ancienne clé est inactive
Son champ
last_used_atcesse d'évoluer lorsqu'elle n'est plus utilisée. - 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
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
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
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
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.
Pages associées
- AuthentificationLes types de clés, les en-têtes et toutes les erreurs d'authentification.
- Vérification de signatureVérifiez l'authenticité d'une livraison, avec ou sans SDK.
- KonsoleLe log des requêtes à consulter dès qu'un comportement semble anormal.
- Gestion des erreursDistinguez un problème d'autorisation d'une panne.