TIPS 23 · CHIAVI

La clé dans le code

Le prompt qui cherche les clés et mots de passe dans le code et l'historique git, comment les déplacer dans .env, et quoi faire si une vous a déjà échappé.

Ce que c'est et pourquoi ça compte

Quand vous connectez un service à votre app, comme une base de données, les paiements ou une IA, on vous donne une clé. C'est une longue chaîne de caractères, et le plus simple est de la coller directement dans le code. Si vous la donnez à Claude dans le chat sans lui dire où la mettre, il lui arrive de faire pareil.

Le problème, c'est l'endroit où finit le code. Si vous le poussez sur GitHub, la clé voyage avec lui. Dans un dépôt public, n'importe qui peut la lire, et il existe des programmes qui tournent exprès pour ramasser les clés dès qu'elles apparaissent. Celui qui la trouve l'utilise en votre nom.

Et l'effacer du code ne suffit pas. Git garde tout l'historique : si la clé a été dans un commit, même un seul, même il y a des mois, elle est toujours là. Celui qui télécharge le dépôt la retrouve.

Toutes les clés ne sont pas secrètes. La clé publique de Supabase ou Firebase est faite pour être dans l'app : j'en parle dans le guide PORTA (strikt.fit/porta). Ici je parle des autres : la clé secrète de la base de données, celle de l'IA, des paiements, des e-mails. Celles-là restent uniquement sur le serveur, comme dans le guide LIMITE (strikt.fit/limite).

1. Le contrôle

Avant de corriger, regardez ce qu'il y a. Ouvrez Claude Code dans le dossier du projet et collez :

Le prompt
Cherche dans le projet et dans tout l'historique git les clés, tokens et mots de passe écrits dans le code, y compris dans les fichiers de configuration et les anciens commits. Pour chacun, dis-moi le fichier, la ligne (ou le commit) et le service. N'affiche jamais la valeur.

« Tout l'historique », sinon Claude ne regarde que les fichiers actuels. « N'affiche jamais la valeur », parce qu'il vous suffit de savoir où elle est : la clé ne doit pas apparaître dans le chat.

Un deuxième avis : gitleaks

Un programme fait exprès reconnaît la forme d'énormément de types de clés. J'utilise gitleaks, qui est open source. Sur Mac, vous l'installez avec Homebrew :

La ligne
brew install gitleaks

Puis, dans le dossier du projet :

Les commandes
gitleaks git -v --redact
gitleaks dir -v --redact
  • gitleaks git examine tout l'historique, commit par commit.
  • gitleaks dir examine les fichiers actuels, y compris ceux que git ne suit pas.
  • --redact masque les valeurs dans les résultats, -v affiche les détails.

Sur GitHub

Dans les dépôts publics, le secret scanning de GitHub est gratuit et automatique : s'il trouve la clé d'un service qu'il connaît, il met une alerte dans l'onglet Security and quality. La push protection va plus loin : elle bloque un push qui contient une clé, avant qu'elle n'arrive en ligne. Pour vos propres push vers des dépôts publics, elle est active par défaut ; sur le dépôt, vous l'activez depuis Settings → Advanced Security. Sur les dépôts privés, cela pourrait nécessiter une fonction payante de GitHub.

2. Les clés dans .env

Le bon endroit pour une clé, c'est un fichier .env que git n'envoie jamais. Ça marche comme ça :

  1. Les clés vont dans un fichier .env dans le dossier du projet : NOM_CLE=valeur.
  2. Dans le fichier .gitignore, ajoutez la ligne .env : git ne l'envoie jamais.
  3. Dans le code, il ne reste que le nom : process.env.NOM_CLE (votre framework ou dotenv lit le fichier).
  4. Là où vous publiez l'app, les mêmes variables vont dans les réglages de l'hébergeur.

Le prompt pour le faire faire à Claude :

Le prompt
Sors les clés du code : mets-les dans .env, ajoute .env au .gitignore, crée un .env.example avec seulement les noms et vérifie qu'aucune clé secrète ne se retrouve dans le code du navigateur.

Le .env.example, lui, vous l'envoyez : il ne contient que les noms, par exemple AI_API_KEY= sans rien derrière. Ainsi, plus tard, vous et ceux qui travaillent avec vous savez quelles clés il faut sans en voir aucune.

Si .env était déjà dans le dépôt

Le .gitignore ne s'applique qu'aux fichiers que git ne suit pas encore. Si .env avait déjà été envoyé, le .gitignore ne suffit pas : lancez git rm --cached .env, qui le retire du dépôt et le laisse sur l'ordinateur, puis faites un commit. Ensuite, changez les clés qu'il contenait, car elles restent dans l'historique : voir la partie 4. Si vous voulez, demandez à Claude de le faire et de vous expliquer chaque étape.

3. Les variables qui finissent dans le navigateur

C'est là qu'on tombe le plus souvent. Mettre une clé dans .env ne la rend pas secrète : ce qui compte, c'est où tourne le code qui l'utilise. Ce qui tourne sur le serveur reste à vous. Ce qui arrive dans le navigateur, ou dans l'app sur le téléphone, tout le monde peut le voir, .env ou pas.

Certains frameworks envoient exprès au navigateur les variables avec un certain préfixe :

  • Next.js : NEXT_PUBLIC_. La valeur est écrite dans le JavaScript qui arrive au navigateur.
  • Vite : VITE_. La documentation de Vite dit explicitement de ne pas y mettre de clés.
  • Expo : EXPO_PUBLIC_. La valeur reste en clair dans l'app compilée.

Une clé secrète avec un de ces préfixes est publique, même si elle est dans .env. Ça se passe comme ça : l'appel à l'IA depuis le navigateur ne marche pas, on ajoute le préfixe, maintenant ça marche, et la clé est sortie. La bonne solution, c'est de déplacer l'appel sur le serveur.

Si vous ne voulez pas que Claude lise .env

Claude Code peut lire les fichiers du dossier, .env compris. Si vous préférez que non, ajoutez une règle de blocage dans .claude/settings.json, dans le dossier du projet :

Le fichier
{
  "permissions": {
    "deny": ["Read(./.env)"]
  }
}

Ajoutez-la après avoir déplacé les clés : elle bloque aussi l'écriture de ce fichier. Elle s'applique aux outils avec lesquels Claude lit les fichiers et aux commandes comme cat, pas à un script qui ouvre le fichier de lui-même : pour ça, il faut la sandbox de Claude Code.

4. Si une vous a déjà échappé

Si vous trouvez une clé secrète dans un commit, sur GitHub ou dans le code qui part dans le navigateur, considérez-la comme grillée. Vous ne savez pas qui l'a déjà copiée. Aujourd'hui, dans cet ordre :

  1. Sur le site du service, révoquez la clé et créez-en une nouvelle. C'est l'étape qui compte : celui qui l'a copiée peut encore l'utiliser.
  2. Mettez la nouvelle uniquement dans .env et dans les réglages de l'hébergeur.
  3. Vérifiez sur le service s'il y a une consommation bizarre.
  4. Ensuite, tranquillement, nettoyez l'historique.

Si l'app est en ligne, vous pouvez créer la nouvelle clé juste avant de révoquer l'ancienne, pour qu'elle ne s'arrête pas. Mais l'ancienne, vous la révoquez aujourd'hui, pas demain. Pour la dernière étape, demandez d'abord une explication :

Le prompt
Une clé s'est retrouvée dans un ancien commit. Explique-moi comment la retirer de l'historique git avant de toucher à quoi que ce soit.

Pourquoi cet ordre. Retirer une clé de l'historique, c'est réécrire l'histoire du dépôt (GitHub recommande git-filter-repo) et l'envoyer avec un force push, et les anciennes copies et les forks la contiennent encore. C'est pour ça que GitHub met comme première étape la révocation de la clé, et dit que parfois ça suffit : une clé révoquée n'ouvre plus rien.

Les erreurs les plus courantes

  • Effacer la clé du code et s'arrêter là. Elle reste dans l'historique : révoquez-la et créez-en une nouvelle.
  • Nettoyer l'historique avant de révoquer la clé. Révoquez-la tout de suite : le nettoyage vient après.
  • Ajouter .env au .gitignore alors qu'il avait déjà été envoyé. Retirez-le avec git rm --cached .env et un commit, puis changez les clés qu'il contenait.
  • Mettre une clé secrète dans une variable NEXT_PUBLIC_, VITE_ ou EXPO_PUBLIC_. Elle finit dans le navigateur ou dans l'app : déplacez l'appel sur le serveur.
  • Coller les nouvelles clés dans le chat avec Claude. Mettez-les vous-même dans .env et donnez-lui seulement le nom de la variable.

Check-list

  • Contrôle fait sur les fichiers et l'historique, avec Claude et avec gitleaks.
  • Les clés secrètes sont uniquement dans .env et dans les réglages de l'hébergeur.
  • .env est dans le .gitignore et pas dans le dépôt.
  • Il y a un .env.example avec les noms, sans valeurs.
  • Aucune clé secrète dans des variables NEXT_PUBLIC_, VITE_ ou EXPO_PUBLIC_.
  • Chaque clé échappée a été révoquée et remplacée.
  • Push protection activée sur le dépôt GitHub.

Questions fréquentes

Mon dépôt est privé. Est-ce que je dois le faire quand même ?

Oui. Si un jour vous le rendez public ou ajoutez quelqu'un, l'historique arrive en entier, clés comprises. Et les variables qui finissent dans le navigateur sont publiques de toute façon.

La clé publique de Supabase dans une variable NEXT_PUBLIC_, ça va ?

Oui, elle est faite pour être dans le navigateur. Ce qui protège les données, ce sont les règles sur la base de données, comme je l'explique dans le guide PORTA. La clé secrète (secret ou service_role), en revanche, jamais.

J'ai déjà révoqué la clé. Est-ce que je dois quand même nettoyer l'historique ?

Pas toujours : une clé révoquée n'ouvre plus rien. S'il y a autre chose de sensible dans l'historique, comme des données de personnes, ou si vous n'êtes pas sûr d'avoir tout révoqué, nettoyez, en partant du prompt de la partie 4.

← Tous les guides