Sécurité5 min de lecture

Secrets exposés côté navigateur : risques, détection et séparation

Comprendre pourquoi le frontend est un environnement public, distinguer un identifiant public d'un secret confidentiel et empêcher la fuite de clés sensibles.

Un secret exposé côté navigateur est une information d'authentification ou d'autorisation confidentielle qui est rendue accessible dans le code client, le bundle JavaScript ou les échanges réseau d'une application web. Dans les applications modernes, notamment développées avec Next.js, Vite ou des environnements de vibe coding, une confusion fréquente persiste sur la frontière entre ce qui s'exécute sur le serveur et ce qui est distribué à chaque visiteur.

Le principe fondamental de l'ingénierie web est invariable : le navigateur est un environnement d'exécution public et non fiable. Tout ce qui est transmis au client peut être inspecté, extrait et réutilisé par n'importe quel utilisateur ou robot.

Le frontend n'est pas un coffre-fort

Lorsqu'un framework JavaScript compile une application pour la production, il assemble les composants dans des fichiers statiques minifiés (les bundles .js).

Une erreur courante consiste à penser qu'une clé est protégée parce qu'elle :

  • n'est pas affichée directement dans l'interface visuelle ;
  • est injectée via un fichier .env ou une variable d'environnement ;
  • est dissimulée au sein d'un composant complexe.

En réalité, dès qu'une valeur est incluse dans le code d'un composant client, elle est incorporée en clair dans le code JavaScript téléchargé par le navigateur. Les outils d'inspection des navigateurs (DevTools), l'onglet Réseau ou un simple script d'extraction permettent de retrouver ces valeurs en quelques secondes, sans nécessiter la moindre compétence en intrusion. De surcroît, si les cartes de sources (source maps) sont accidentellement publiées en production, l'intégralité du code source original devient lisible.

Secret sensible vs Identifiant public

Toutes les clés d'API ne sont pas des secrets, et toute chaîne de caractères ressemblant à un jeton ne représente pas une faille. Une distinction claire est indispensable :

1. L'identifiant conçu pour être public

Certains services tiers fonctionnent selon un modèle où le client web dialogue directement avec leurs serveurs. Pour identifier le projet émetteur, ils fournissent une clé publique :

  • La clé anon Supabase : Conçue pour être publique, elle identifie votre projet. Sa sécurité repose intégralement sur les politiques Row Level Security (RLS) de votre base de données.
  • La clé publiable Stripe (pk_live_... / pk_test_...) : Conçue pour initialiser le formulaire de paiement sécurisé (Stripe Elements) dans le navigateur. Elle ne permet pas d'émettre des remboursements ni de consulter les coordonnées bancaires de vos clients.
  • L'identifiant de suivi analytics ou d'affichage de carte : Permet de charger des tuiles cartographiques ou d'enregistrer des événements de visite.

2. Le secret confidentiel privilégié

À l'inverse, un secret confère des droits d'administration ou permet de réaliser des actions sensibles sans restriction :

  • La clé secrète Stripe (sk_live_...) : Permet de créer des charges, d'émettre des virements et d'accéder à l'historique financier complet de votre compte.
  • La clé service_role Supabase : Associée au rôle PostgreSQL privilégié disposant de l'attribut BYPASSRLS, elle permet d'effectuer des opérations d'administration sans être filtrée par les politiques de lignes habituelles.
  • Les clés d'API de modèles d'IA (OpenAI, Anthropic, Groq) : Permettent de consommer des crédits d'API sans limite au nom de votre compte, risquant d'engendrer des surcoûts considérables.
  • Les jetons de webhook, clés privées de signature ou accès base de données (Database URLs avec mot de passe).

Ces valeurs doivent impérativement demeurer cantonnées au serveur.

Variables d'environnement : le rôle des préfixes

Dans les frameworks modernes, la convention de nommage détermine l'inclusion d'une variable dans le bundle public :

  • Next.js : Seules les variables préfixées par NEXT_PUBLIC_ sont injectées dans le code client. Une variable nommée STRIPE_SECRET_KEY restera confinée au serveur, tandis qu'une variable renommée par erreur NEXT_PUBLIC_STRIPE_SECRET_KEY sera divulguée à chaque internaute.
  • Vite : Seules les variables préfixées par VITE_ sont exposées au client (import.meta.env).

Un piège classique dans le vibe coding survient lorsqu'un composant marqué de la directive "use client" a besoin d'appeler une API payante. Pour résoudre l'erreur de compilation, l'assistant ou le développeur préfixe la clé secrète avec NEXT_PUBLIC_, exposant ainsi le secret au grand jour.

Le pattern d'architecture : la séparation client/serveur

La règle pour utiliser un service tiers payant ou sensible est de mettre en place une couche intermédiaire (un proxy serveur) :

[Navigateur / Client]
       │
       │ (1) Appel authentifié sans secret tiers
       ▼
[Route API Serveur / Server Action]
  (Détient la clé secrète dans process.env)
       │
       │ (2) Requête vers le service tiers avec le vrai secret
       ▼
[Service Tiers : Stripe, OpenAI, etc.]

Le navigateur appelle votre propre route API (/api/generate ou une Server Action) en transmettant le cookie de session de l'utilisateur. C'est votre serveur qui vérifie les droits, applique le contrôle de débit (rate limiting) et sollicite l'API externe avec le secret sécurisé.

Que faire en cas d'exposition avérée ?

Si un secret a été présent dans un composant client déployé ou commité sur un dépôt public :

  1. Révoquer immédiatement : Ne vous contentez pas de retirer la clé du code source. Considérez-la comme compromise et générez une nouvelle clé dans le tableau de bord du fournisseur (Stripe, OpenAI, Supabase).
  2. Nettoyer l'historique Git : Si le secret a été validé dans un commit, il subsiste dans l'historique de version même après sa suppression. Utilisez des outils comme git-filter-repo ou réécrivez l'historique si le dépôt est partagé.
  3. Inspecter les journaux d'accès : Vérifiez si des requêtes anormales ou des consommations inhabituelles de crédits ont eu lieu pendant la période d'exposition.

Ce que GVO observe sur ce sujet

Dans son analyse de votre code, GVO examine les fichiers sources pour détecter les motifs de fuite de secrets :

  • Ce que GVO peut observer : GVO repère l'utilisation directe de clés secrètes hardcodées, les variables privées malencontreusement préfixées par des identifiants publics (NEXT_PUBLIC_*), et l'import de variables de configuration sensibles dans des composants s'exécutant côté client.
  • Ce que GVO ne peut pas garantir : Une analyse statique ne vérifie pas la configuration des variables d'environnement définies directement sur votre plateforme d'hébergement (Vercel, AWS, Cloudflare) si elles ne sont pas déclarées dans le dépôt analysé.

Pour passer en revue les secrets de votre projet avant la mise en ligne, suivez les étapes de notre Guide de sécurisation Supabase et notre Checklist de production.

Vérifier ce point sur votre projet

GVO confronte le code et les configurations de votre application aux règles de sécurité réelles.