Les clés API expliquées : longueur, format, stockage et rotation

Mis à jour :

Une clé API est une longue chaîne aléatoire qu’un programme envoie avec chaque requête pour indiquer quelle application appelle. Contrairement à un mot de passe, personne n’a à la retenir : elle peut donc être aussi longue et aléatoire que nécessaire. Contrairement à un jeton de connexion, elle dure en général jusqu’à ce que quelqu’un la révoque. La documentation de Google résume le risque : les clés API sont des identifiants au porteur, et quiconque en détient une peut s’en servir.

Cette quatrième partie de la série sur la sécurité couvre toute la vie d’une clé : combien de bits aléatoires il lui faut, dans quel format l’écrire, pourquoi des préfixes comme sk_live_ existent, comment l’envoyer, ce que le serveur doit stocker, et comment la renouveler et la révoquer.

Clé API, mot de passe ou jeton d’accès ?

Tous trois prouvent quelque chose à un serveur, d’où la confusion fréquente. La différence tient à qui les crée, à leur durée et à ce que le serveur conserve :

IdentifiantCréé parDuréeLe serveur conserve
Mot de passeune personnejusqu’à ce que la personne le changeun hachage lent (Argon2id, scrypt, bcrypt)
Clé APIun générateur aléatoirejusqu’à son renouvellement ou sa révocationun hachage rapide, comme SHA-256
Jeton d’accès (OAuth, JWT)le serveur de connexion, après une connexionde quelques minutes à quelques heuresune signature à vérifier, ou un enregistrement du jeton

Une clé API identifie en général une application ou une intégration plutôt qu’une personne. Quand une clé tiendrait lieu de connexion d’une personne, un jeton d’accès obtenu par un vrai parcours de connexion est souvent le meilleur outil, comme l’explique la partie précédente sur les JSON Web Tokens.

Quelle longueur pour une clé

Ce qui protège une clé, c’est le nombre de bits aléatoires qu’elle contient, pas sa longueur en caractères. Chaque bit double le nombre de clés possibles : 128 bits aléatoires donnent environ 3,4 × 10³⁸ clés, si bien qu’en essayer ne serait-ce qu’un millionième à un milliard d’essais par seconde prendrait environ 10¹⁶ ans, près d’un million de fois l’âge de l’univers. 128 bits est donc un minimum solide, et 256 bits ne coûtent que quelques caractères de plus.

Les bits doivent venir d’un générateur aléatoire cryptographique. Dans un navigateur, c’est crypto.getRandomValues() ; MDN avertit que Math.random() ne fournit pas de nombres sûrs au sens cryptographique et ne doit servir à rien qui touche à la sécurité. Les langages côté serveur ont leurs équivalents, comme le module secrets de Python ou crypto.randomBytes() dans Node.js.

GitHub a porté ses jetons OAuth de 160 à 178 bits d’entropie en changeant leur format en 2021. Un cas demande encore plus : un secret qui signe des JSON Web Tokens avec HMAC. Le RFC 7518 exige une clé au moins aussi longue que la sortie du hachage : 256 bits pour HS256, 384 pour HS384 et 512 pour HS512.

Formats : base62, hexadécimal ou base64url

Les bits aléatoires doivent être écrits sous forme de texte. L’alphabet détermine combien de caractères il faut et où l’on peut coller la clé sans difficulté :

FormatCaractèresBits par caractèreLongueur pour 256 bits
base62a–z, A–Z, 0–95,9543
hex0–9, a–f464
base64urla–z, A–Z, 0–9, - et _643

Le base62 s’est répandu pour les clés parce qu’il ne contient que des lettres et des chiffres : rien qu’une URL, un terminal ou un fichier de configuration traite à part, et un double-clic sélectionne toute la clé. L’hexadécimal est plus long mais passe là où seuls 0–9 et a–f sont acceptés. Le base64url, du RFC 4648, est le plus court, mais son - peut interrompre la sélection au double-clic. Le Base64 standard est un mauvais choix, car ses + et / doivent être échappés dans les URL.

Écrire du base62 correctement demande du soin : un octet aléatoire a 256 valeurs, et 256 n’est pas un multiple de 62, si bien qu’un simple octet % 62 rend les huit premiers caractères un peu plus probables. Un bon générateur écarte les octets à partir de 248, comme le fait celui de nTools.

Préfixes et détection de secrets

Beaucoup de fournisseurs font commencer leurs clés par un préfixe fixe et lisible. Les clés secrètes de Stripe commencent par sk_live_ ou sk_test_, ses clés publiables par pk_ et ses clés restreintes par rk_. Depuis 2021, les jetons de GitHub commencent par ghp_ pour les jetons d’accès personnels, gho_ pour les jetons OAuth et ghs_ pour les jetons de serveur à serveur.

Un préfixe n’est pas secret et n’ajoute aucune robustesse, mais il rend trois services. On voit d’un coup d’œil à quoi sert une clé et si c’est une clé de test. GitHub a choisi le tiret bas parce que ce n’est pas un caractère Base64 — des chaînes aléatoires comme des empreintes ne peuvent donc pas ressembler à un jeton par hasard — et parce qu’un double-clic sélectionne tout le jeton. Surtout, un préfixe permet aux scanners de trouver les clés divulguées : la détection de secrets de GitHub parcourt tout l’historique Git de toutes les branches et, quand elle trouve le secret d’un fournisseur partenaire, prévient ce fournisseur, qui peut révoquer la clé.

GitHub termine aussi ses jetons par une somme de contrôle CRC32 de 32 bits, écrite en six caractères base62. Elle n’ajoute pas de sécurité, mais permet à un scanner d’écarter les chaînes aléatoires hors ligne, sans demander au serveur si le jeton existe.

L’envoyer dans un en-tête, jamais dans l’URL

Le RFC 6750, qui définit les jetons au porteur d’OAuth 2.0, indique que les clients doivent les envoyer dans l’en-tête Authorization et ne pas les mettre dans les URL de pages, car les adresses finissent dans l’historique du navigateur et dans les journaux des serveurs. Google donne le même conseil pour ses propres clés API et prévoit un en-tête pour elles. Le même RFC impose TLS : une clé envoyée en http simple peut être lue par n’importe qui sur le trajet.

Ce que le serveur doit stocker

Le serveur n’a pas besoin de garder la clé elle-même, seulement un moyen de la reconnaître. Stockez une empreinte de la clé, comme son SHA-256 ; quand une requête arrive, calculez l’empreinte de la clé reçue et recherchez-la. Si la base de données fuit, les empreintes ne permettent pas d’appeler l’API et on ne peut pas en retrouver les clés.

Les mots de passe demandent un hachage lent parce que, comme l’explique la fiche OWASP sur le stockage des mots de passe, un hachage rapide comme SHA-256 permet aux attaquants d’essayer très vite d’énormes quantités de mots de passe. Ce raisonnement suppose que les mots de passe peuvent être devinés. Une clé de 256 bits aléatoires ne le peut pas : un seul hachage rapide suffit, et chaque requête reste rapide.

Comme seule l’empreinte est conservée, la clé complète ne peut être montrée qu’une fois, à sa création. Stripe fonctionne ainsi pour les clés secrètes en mode réel que vous créez : le tableau de bord affiche la clé une seule fois et ne peut plus la révéler. Gardez en clair le préfixe et les derniers caractères si les gens doivent distinguer leurs clés.

Garder les clés hors du code

Les clés divulguées se trouvent surtout là où les développeurs les ont mises par commodité. Stripe prévient que des acteurs malveillants analysent en permanence les dépôts publics à la recherche de clés API, et que même des dépôts privés peuvent être exposés. Ses conseils, repris par Google et l’OWASP :

Renouvellement et révocation

Toute clé doit pouvoir être remplacée rapidement. La renouveler, c’est créer une nouvelle clé, y faire passer toutes les applications, puis supprimer l’ancienne. Fait régulièrement, cela limite la durée pendant laquelle une clé volée fonctionne et, comme le souligne Stripe, prouve que vous savez où chaque clé est utilisée. Le tableau de bord de Stripe garde l’ancienne et la nouvelle clé actives ensemble jusqu’à sept jours pour faciliter le passage.

Quand une clé est exposée — envoyée dans un dépôt, collée dans une discussion, écrite dans un journal —, révoquez-la tout de suite, même si vous n’êtes pas sûr que quelqu’un l’ait vue. Supprimer le commit ne suffit pas : la clé a peut-être déjà été copiée, et elle reste dans l’historique Git et dans chaque clone. Quand le système le permet, donnez aussi une date d’expiration aux clés, pour qu’une clé oubliée cesse de fonctionner d’elle-même.

Générer une clé

Le générateur de clés API de nTools crée des clés en base62, hexadécimal ou base64url, de 128 à 512 bits, avec un préfixe facultatif et, si vous le souhaitez, l’empreinte SHA-256 à stocker sur le serveur. Il utilise crypto.getRandomValues() et fonctionne entièrement dans votre navigateur : les clés ne sont envoyées nulle part.

Générateur de clés API

Questions fréquentes

Puis-je utiliser un UUID comme clé API ?

Un UUID version 4 n’a que 122 bits aléatoires et une forme fixe et reconnaissable, et il a été conçu comme identifiant, pas comme secret. Mieux vaut générer une clé dédiée de 128 bits ou plus.

Une clé générée dans le navigateur est-elle sûre ?

Oui, si elle vient de crypto.getRandomValues(), le générateur cryptographique que le navigateur utilise pour sa propre sécurité, et si la page ne l’envoie nulle part. Le générateur de nTools fonctionne ainsi : aucune requête ne quitte la page quand vous cliquez sur « Générer ».

Les clés API doivent-elles expirer ?

Quand le système le permet, oui : une date d’expiration limite les dégâts d’une clé oubliée ou divulguée sans qu’on le sache. Les clés de longue durée sont courantes, ce qui rend le renouvellement et la révocation rapide d’autant plus importants.

J’ai envoyé une clé dans Git. Que faire ?

Révoquez-la ou renouvelez-la d’abord, puis nettoyez le dépôt. Réécrire l’historique ensuite ne rend pas la clé sûre à nouveau, car elle a peut-être déjà été copiée.

Faut-il chiffrer la clé plutôt que la hacher ?

Seulement si le serveur lui-même doit réutiliser la clé plus tard, par exemple pour appeler un autre service avec elle. Une clé qu’il suffit de vérifier doit être hachée : il n’y a alors rien à déchiffrer si la base de données fuit.

Partie précédente ← Les JSON Web Tokens expliqués : revendications, signatures, validation sûre

Références

  1. GitHub — Behind GitHub’s new authentication token formats (April 2021)
  2. GitHub Docs — About secret scanning
  3. GitHub Docs — About secret scanning for partners
  4. Stripe — API keys
  5. Stripe — Best practices for managing secret API keys
  6. Google Cloud — Best practices for managing API keys
  7. RFC 6750 — The OAuth 2.0 Authorization Framework: Bearer Token Usage (October 2012)
  8. RFC 7518 — JSON Web Algorithms (JWA) (May 2015)
  9. RFC 4648 — The Base16, Base32, and Base64 Data Encodings (October 2006)
  10. OWASP — Secrets Management Cheat Sheet
  11. OWASP — Password Storage Cheat Sheet
  12. MDN — Crypto: getRandomValues()
  13. MDN — Math.random()

Guides associés