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 d'une partie secrète aléatoire. Le préfixe détermine tout le modèle de sécurité.
| Préfixe | Emplacement | Autorisations |
|---|---|---|
pk. / pk_test. | Navigateurs et applications mobiles | Créer des paiements. Voir les endpoints qui l'acceptent |
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 ne conserve jamais une clé en clair. Une clé égarée peut être réaffichée dans le Dashboard par un membre de votre équipe, après saisie d'un code de vérification de sécurité. Une clé que vous pensez exposée doit être renouvelée.
Les contrôles avant d'atteindre un endpoint
Chaque contrôle répond avec son propre code de statut, et ces codes sont souvent attribués à la mauvaise cause.
| Contrôle | Refus avec | Situation |
|---|---|---|
| Version d'API | 400 | X-Wajub-Version nomme une version que l'API ne sert pas |
| Vérification de l'identifiant | 401 | Clé inconnue, révoquée, inactive ou ayant dépassé expires_at |
| Détection du navigateur | 403 | Une clé sk. est utilisée depuis un navigateur |
| Restriction du compte | 403 | Wajub a fermé l'API pour le compte (error_code: merchant_restricted) |
| 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é |
| Connexion | 403 | Une connexion X-Sync qui n'est pas la vôtre, pas active, sans la capacité, ou dont les paiements sont suspendus |
| Environnement et plan | 403 | Une route réservée au live appelée avec une clé sandbox, ou Sync ou Tax absent de votre plan (error_code: feature_not_in_plan) |
| Limites de requêtes | 429 | L'équipe, la clé ou l'endpoint dépasse son plafond, voir Limites de requêtes |
La version et les limites de requêtes sont contrôlées avant la clé : un appel avec une mauvaise clé
peut donc répondre 400 ou 429.
L'utilisation d'une clé privée dans un navigateur est signalée, pas seulement refusée
N'utilisez jamais une clé sk. depuis un navigateur. Lorsque Wajub en détecte une, il refuse la
requête avec un code 403 et envoie un e-mail d'alerte au propriétaire de la clé. 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 |
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. /shield n'a aucun scope : aucune clé restreinte
ne l'atteint, seule une clé privée.
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 l'ancienne valeur cesse de fonctionner dès la requête suivante. 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 de chaque type, clés publiques comprises : Add new key sur la page des 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 ne partagent aucune donnée
Le préfixe de la clé détermine l'environnement. Une clé pk_test. ou sk_test. ne voit que les
données de la sandbox, jamais un objet 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.
- Déclarez les sites qui intègrent votre checkout dans Settings → Checkout embedding avant de passer en live. La page existe sur tous les plans. Une fois la liste renseignée, seuls ces sites peuvent afficher votre checkout. Voir où le checkout peut être intégré.
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.