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 viennent d'une clé secrète laissée dans un dépôt, une application mobile ou une capture d'écran : la personne qui la trouve peut faire tout ce que vous pouvez faire. Les contrôles présentés ici rendent cette erreur 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. Une clé rk. est signalée, pas encore refusée |
| 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 | 404 ou 403 | 404 pour une connexion X-Sync qui n'existe pas ou n'est pas la vôtre ; 403 pour une connexion 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 |
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 du compte et aux
administrateurs. 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. Une clé restreinte (rk.) détectée dans un navigateur
déclenche la même alerte ; pour l'instant, sa requête aboutit encore, et Wajub la refusera plus tard
avec le même 403.
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 : Ajouter une nouvelle clé 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 Paramètres → Intégration de la page de paiement 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.