Aller au contenu
WebViewGold Du vibe coding à l'App Store
Français
Obtenir WebViewGold

Sécurité

Clés API et secrets dans les apps créées par IA : ce qu'un wrapper natif ne cache pas, et comment relire le code de n'importe quel agent

Encapsuler une web app dans une coque native ne cache pas son JavaScript : le même bundle se charge depuis votre URL, et n'importe qui peut l'ouvrir dans un navigateur. Les règles du web s'appliquent donc. Les clés publiables (Supabase publishable ou anon, Stripe pk_, configuration web Firebase, App ID OneSignal) peuvent être livrées ; les clés secrètes (Supabase secret ou service_role, Stripe sk_, clés App API OneSignal, comptes de service, clés API de LLM) jamais. Voici comment les distinguer, pourquoi la row-level security est le vrai verrou, et une routine de relecture qui fonctionne avec n'importe quel agent de code.

Dès $109 en paiement unique par plateforme, ou notre équipe s'occupe de tout dès $698.

  • Garantie d'approbation – ou remboursement sous 14 jours
  • Aucun codage requis
  • Paiement unique, mises à jour gratuites
  • Support humain 24/7
  • Conçu en Allemagne depuis 2014 · ISO 27001

Pourquoi le wrapper natif ne protège pas vos clés

Une app WebViewGold est une coque native autour de votre URL déployée. Le JavaScript qu'exécutent vos utilisateurs est téléchargé depuis votre serveur, exactement comme dans Safari ou Chrome. N'importe qui peut ouvrir votre domaine sur un ordinateur portable, ouvrir les outils de développement et lire chaque chaîne du bundle, y compris les variables d'environnement que votre outil de build y a intégrées. La fiche sur les stores n'y change rien.

Le projet natif n'est pas non plus un coffre-fort. Les valeurs de Config.swift, Config.java, Info.plist, google-services.json et des fichiers custom.js et custom.css finissent dans l'IPA ou l'APK, et un package d'app est une archive que des outils décompressent en quelques secondes. Considérez tout ce qui est livré sur un appareil comme public. Les clés conçues pour les clients s'en accommodent ; les clés secrètes, non.

Les outils de build rendent l'erreur facile. Les variables préfixées par VITE_ (Vite) ou NEXT_PUBLIC_ (Next.js) sont intégrées au bundle client par conception. Un agent qui « corrige » une erreur 401 en déplaçant une clé dans une telle variable, ou en la collant dans un appel fetch, vient de la publier. Les agents le font parce que cela fait disparaître l'erreur ; c'est à votre relecture de le repérer.

Les clés qui peuvent être livrées, et celles qui ne le peuvent jamais

ServiceAccepté dans le code clientServeur uniquementCe qui vous protège vraiment
SupabaseClé publishable (sb_publishable_...) ou l'ancienne clé anonClé secrète (sb_secret_...) ou l'ancienne clé service_role ; les deux contournent la row-level securityDes politiques RLS sur chaque table et chaque bucket de stockage
FirebaseConfiguration web (apiKey, authDomain, projectId, appId)JSON de compte de service, identifiants de l'Admin SDKSecurity Rules, App Check, restrictions de clé API dans Google Cloud
StripeClé publiable (pk_live_...)Clé secrète (sk_live_...), clés restreintes (rk_live_...), secret de signature des webhooks (whsec_...)Créer les Checkout Sessions et les PaymentIntents sur votre serveur ; vérifier les webhooks
OneSignalApp ID (la valeur de Config.swift / build.gradle)Clé App API (os_v2_app_...), ancienne clé REST API, clé Organization APIEnvoyer les push depuis votre serveur vers les ID d'abonnement que vous avez enregistrés
RevenueCatClé SDK publique propre à l'app, celle qu'utilise une app nativeClé API secrète pour les appels RESTDroits (entitlements) vérifiés côté serveur via des webhooks
API de LLM (Gemini, OpenAI, Anthropic)RienToutes les clés APIUn serveur ou une edge function qui authentifie les utilisateurs et limite le débit

Le schéma que les agents ratent le plus souvent

Trois versions de la même erreur, puis la correction. La correction a toujours la même forme : le client appelle votre propre endpoint avec la session de l'utilisateur, et seul le serveur détient le secret.

javascript
// FAUX : clé service_role dans le navigateur. Contourne toutes les politiques RLS.
const admin = createClient(SUPABASE_URL, import.meta.env.VITE_SUPABASE_SERVICE_ROLE_KEY);

// FAUX : clé secrète Stripe dans un fetch côté client
await fetch("https://api.stripe.com/v1/checkout/sessions", {
  method: "POST",
  headers: { Authorization: "Bearer " + import.meta.env.VITE_STRIPE_SECRET_KEY }
});

// FAUX : envoyer des push depuis le navigateur avec la clé App API de OneSignal
await fetch("https://api.onesignal.com/notifications", {
  method: "POST",
  headers: { Authorization: "Key " + ONESIGNAL_APP_API_KEY, "Content-Type": "application/json" },
  body: JSON.stringify({ app_id: ONESIGNAL_APP_ID, contents: { en: "Hi" } })
});

// CORRECT : le client appelle votre endpoint avec le jeton de session de l'utilisateur
const res = await fetch("/api/checkout", {
  method: "POST",
  headers: { Authorization: "Bearer " + session.access_token, "Content-Type": "application/json" },
  body: JSON.stringify({ priceId: "price_basic_monthly" })
});

// CORRECT : sur le serveur (route API, Supabase Edge Function, Cloud Function)
// 1. vérifier le jeton de session et en déduire l'ID utilisateur, jamais à partir du body
// 2. lire STRIPE_SECRET_KEY / ONESIGNAL_APP_API_KEY / SUPABASE_SECRET_KEY dans l'environnement serveur
// 3. appeler le fournisseur, ne renvoyer que ce dont le client a besoin

La row-level security est le vrai verrou

Une clé Supabase publishable n'est sûre que parce que Postgres décide de ce que chaque requête peut voir : sans utilisateur connecté, elle s'exécute en tant que anon, avec un utilisateur en tant que authenticated, et les politiques filtrent les lignes. Une clé secrète s'exécute en tant que service_role, qui dispose de BYPASSRLS (documentation des clés API Supabase). Chaque table du schéma exposé a besoin de RLS et de politiques comme celles-ci ; Firebase obtient le même résultat avec les Security Rules. La checklist Supabase et la checklist Firebase couvrent le reste du backend.

text
-- Supabase SQL : activer RLS et ne laisser chaque utilisateur voir et modifier que sa propre ligne
alter table public.profiles enable row level security;

create policy "profiles: read own" on public.profiles
  for select to authenticated
  using ((select auth.uid()) = id);

create policy "profiles: update own" on public.profiles
  for update to authenticated
  using ((select auth.uid()) = id)
  with check ((select auth.uid()) = id);

-- Règles Firestore, même principe :
-- match /profiles/{uid} {
--   allow read, write: if request.auth != null && request.auth.uid == uid;
-- }

Comment relire le code de n'importe quel agent à la recherche de secrets

Fonctionne de la même façon pour Claude Code, Codex, Cursor, Gemini CLI, Antigravity, Kiro, Cline et tous les app builders.

  1. Scannez le bundle compilé, pas le code source

    Lancez le build de production et cherchez dans le dossier de sortie (scan ci-dessous). Le code source peut sembler propre alors qu'une variable d'environnement intégrée se trouve dans le bundle.

  2. Vérifiez chaque préfixe public

    Listez toutes les variables qui commencent par VITE_, NEXT_PUBLIC_ ou un préfixe similaire. Chacune doit être une valeur que vous pourriez afficher sur un panneau publicitaire.

  3. Vérifiez les projets natifs

    Config.swift, Config.java, Info.plist, build.gradle, custom.js et les fichiers de configuration Firebase ne peuvent contenir que des ID publics (App ID OneSignal, clé publique RevenueCat, ID AdMob, configuration Firebase).

  4. Vérifiez le backend

    Supabase : RLS activée sur chaque table, aucune politique d'écriture qui se résume à true, avertissements du Security Advisor résolus. Firebase : aucune règle if true. Les edge functions déduisent l'utilisateur du jeton, jamais d'un ID utilisateur présent dans le corps de la requête.

  5. Vérifiez l'historique et renouvelez

    Une clé qui a été committée ou déployée un jour a fuité, même si le dernier commit l'a supprimée. Renouvelez-la d'abord dans le tableau de bord du fournisseur, puis faites le ménage. Activez le secret scanning et la push protection pour le dépôt.

  6. Formez l'agent

    Ajoutez une section sur les secrets à votre fichier de contexte pour que la session suivante ne recommence pas : CLAUDE.md, AGENTS.md, GEMINI.md, .clinerules ou steering Kiro, selon votre agent de code.

Un scan de fuites en deux minutes après chaque build

Adaptez les dossiers à votre stack (Vite : dist/, Next.js : .next/static/, Create React App : build/). Une correspondance sur AIza est attendue pour une configuration web Firebase ; vérifiez que cette clé est restreinte et qu'il ne s'agit pas d'une clé Gemini.

bash
# 1. Générer le bundle de production
npm run build

# 2. Chercher dans les fichiers livrés des chaînes qui ressemblent à des secrets
grep -rEn "sk_live_|sk_test_|rk_live_|whsec_|sb_secret_|os_v2_app_|BEGIN (RSA )?PRIVATE KEY|AIza[0-9A-Za-z_-]{35}" dist/ .next/static/ build/ 2>/dev/null

# 3. Les anciennes clés Supabase sont des JWT : décoder chacune et regarder "role"
#    "anon" est attendu, "service_role" signifie qu'une clé secrète a été livrée
grep -rhoE "eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+" dist/ 2>/dev/null | sort -u | while read -r t; do
  echo "$t" | cut -d. -f2 | tr '_-' '/+' | base64 -d 2>/dev/null; echo
done

# 4. Projets natifs et historique git
grep -rEn "sk_live_|sb_secret_|os_v2_app_|service_role" ios/ android/ 2>/dev/null
git log -p --all | grep -En "sk_live_|sb_secret_|os_v2_app_|SERVICE_ROLE" | head -20

Prompt de revue de sécurité pour n'importe quel agent de code

Il demande d'abord un rapport et n'affiche jamais les secrets en entier : vous pouvez donc le lancer même dans une session partagée.

À coller dans votre agent, à la racine du projet
Faites une revue des secrets et des accès aux données de ce dépôt avant que nous le publiions sous forme d'apps iOS et Android avec WebViewGold. Rappel : les apps chargent notre web app déployée, donc chaque fichier du bundle client est public, et chaque valeur de ios/ et android/ est livrée dans le package de l'app.

1. Listez chaque clé API, jeton, secret et identifiant référencé où que ce soit : code source, fichiers env, configuration, workflows CI, ios/, android/. Pour chacun : service, endroit où il est utilisé, s'il atteint le bundle client, et s'il est publiable (Supabase publishable ou anon, Stripe pk_, configuration web Firebase, App ID OneSignal, clé SDK publique RevenueCat) ou secret (Supabase secret ou service_role, Stripe sk_, rk_ ou whsec_, clé App API OneSignal, comptes de service, toute clé API de LLM).
2. Pour chaque secret qui atteint le client : proposez de déplacer l'appel dans une route ou une fonction serveur qui vérifie d'abord la session de l'utilisateur et lit le secret dans des variables d'environnement côté serveur. Montrez-moi le plan avant de modifier tout code de paiement.
3. Supabase : listez chaque table et chaque bucket de stockage, si RLS est activée et quelles politiques existent. Signalez les tables sans RLS et les politiques qui ne vérifient pas auth.uid(). Firebase : signalez les règles qui autorisent l'accès sans request.auth ou d'un utilisateur à l'autre.
4. Edge functions et routes API : signalez celles qui prennent un ID utilisateur dans le corps de la requête au lieu du jeton vérifié.
5. Historique Git : trouvez les fichiers .env ou les clés committés et listez les clés à renouveler. Ne réécrivez pas l'historique.
6. Ajoutez à notre fichier de contexte d'agent une courte section sur les secrets, qui nomme les clés publiables autorisées et interdit tout le reste dans le code client.

Présentez le résultat sous forme de tableau. N'affichez jamais une valeur secrète en entier ; montrez seulement les 6 premiers caractères.

Les pièges qui survivent à une relecture rapide

  • « C'est une app, personne ne peut voir le code. » Le code est sur votre URL et dans le package ; les deux sont publics.
  • L'obfuscation au lieu de la suppression. Base64, découpage de chaînes ou minification ne protègent pas une clé ; quiconque lance l'app peut la voir être utilisée.
  • Une « page admin » dans le même bundle, qui utilise la clé service role. Les fonctions d'administration ont besoin de leurs propres endpoints côté serveur, avec vérification des rôles.
  • Un endpoint de suppression de compte ou de push qui fait confiance à un ID utilisateur venu de la requête. N'importe qui peut alors supprimer ou contacter n'importe qui ; déduisez l'utilisateur du jeton vérifié.
  • Des fonctionnalités payantes débloquées par un indicateur côté client. Vérifiez les droits sur le serveur ; le guide RevenueCat montre le schéma avec webhooks.
  • Supprimer du code une clé qui a fuité sans la renouveler. L'ancienne valeur fonctionne toujours pour quiconque l'a copiée.

Checklist de publication

  • Le scan de fuites ne trouve aucun préfixe secret dans le résultat du build, les projets natifs ou l'historique git.
  • Chaque table et chaque bucket Supabase a la RLS ; les règles Firebase ne contiennent aucun if true.
  • Les paiements, les push, les appels aux LLM et la suppression de compte passent par du code serveur qui vérifie l'utilisateur.
  • Les clés API Google publiques sont restreintes aux API dont elles ont besoin ; Gemini a sa propre clé côté serveur.
  • Les push OneSignal sont envoyés depuis votre serveur avec la clé App API, vers les ID d'abonnement que les apps transmettent (voir la documentation des notifications push).
  • Toute clé qui a fuité un jour a été renouvelée, pas seulement supprimée.

Questions fréquentes

La clé anon de Supabase est-elle sûre dans mon app ?

Oui, elle est conçue pour les clients publics, tout comme la nouvelle clé publishable, à condition que la row-level security soit activée avec des politiques sensées sur chaque table. Supabase prévoit de déprécier les anciennes clés anon et service_role d'ici fin 2026 : les nouveaux projets doivent donc utiliser des clés publishable et secret.

Quelqu'un peut-il extraire des clés de mon app iOS ou Android ?

Oui. Le bundle web se télécharge depuis votre URL et peut être lu dans n'importe quel navigateur, et les fichiers IPA et APK sont des archives dont les fichiers de configuration et les chaînes sont faciles à inspecter. Ne livrez que des clés destinées à être publiques.

L'apiKey de Firebase est-elle un secret ?

Pas par conception : elle identifie votre projet, et ce sont les Security Rules et App Check qui protègent. Comme les clés API Google non restreintes peuvent aussi atteindre l'API Gemini une fois celle-ci activée dans le projet, restreignez la clé aux API dont elle a besoin et gardez les appels Gemini sur le serveur.

Quelle valeur OneSignal va dans l'app WebViewGold ?

Uniquement l'App ID public, dans Config.swift sur iOS et dans build.gradle sur Android. La clé App API qui envoie les notifications reste sur votre serveur, qui cible les utilisateurs grâce aux ID d'abonnement que l'app transmet à votre web app.

J'ai laissé fuiter une clé. Que faire ?

Renouvelez-la immédiatement dans le tableau de bord du fournisseur, vérifiez les logs et la facturation du fournisseur pour repérer un éventuel abus, puis supprimez-la du code et déplacez l'appel côté serveur. La supprimer sans la renouveler laisse l'ancienne clé valide.

Apple ou Google vont-ils refuser mon app pour une clé exposée ?

La validation des stores n'est pas un audit de sécurité : ne comptez pas sur elle pour repérer les fuites. Les vrais risques sont les abus, les factures inattendues et l'exposition de données utilisateur, qui peuvent devenir un problème de confidentialité auprès des deux stores.

Trois façons de mettre votre app dans les stores

Même résultat, charge de travail différente de votre côté. Les trois formules incluent la garantie d'approbation et le support humain 24/7.

Faites-le vous-même

$109 par plateforme, paiement unique

La licence WebViewGold : un projet Xcode ou Android Studio prêt à l'emploi. Collez votre URL, définissez le nom et l'icône, activez les fonctionnalités, compilez et soumettez. Mises à jour gratuites à vie.

Voir les offres sur la page principale

Full Service

$698 par plateforme $798

Envoyez-nous votre URL et votre icône. Notre équipe configure, compile et livre votre app sous 72 heures, en marque blanche, projets sources inclus. Les deux plateformes pour $1,158.

Détails du Full Service Propulsé par WeSetupYourWebViewApp

Prix Soldes d'hiver valables jusqu'au 31 décembre 2026.

Prêt à publier votre app ?

Garantie d'approbation App Store & Google Play – ou remboursement sous 14 jours

Vous préférez déléguer ? Full Service : nous configurons, compilons et livrons sous 72 heures, dès $698 par plateforme. Des questions ? Chattez avec nous 24/7.

Les remboursements sont accordés aux conditions indiquées dans notre FAQ : un refus non lié au contenu par Apple et/ou Google, demandé dans les 14 jours suivant l'achat.