API-sleutels veilig opslaan in elke AI-webtoepassing

Pim Feltkamp6 min leestijd
How to Store API Keys Securely in Any AI Web App
Deel dit artikel

Een API-sleutel lekken is een van de snelste manieren om een rekening van vijf cijfers op te bouwen of aanvallers toegang te geven tot de gegevens van je gebruikers. Het gebeurt vaker dan je zou denken — en begint bijna altijd met één regel zoals const apiKey = "sk-live-abc123" die naar een codebase wordt gecommit. Dit artikel legt precies uit hoe blootstelling van geheimen plaatsvindt, hoe de juiste architectuur eruitziet en welke concrete stappen je nu meteen kunt nemen om API-sleutels veilig op te slaan in elke webtoepassing.

De veiligste manier om API-sleutels op te slaan in een webtoepassing is ze uitsluitend aan de serverzijde te bewaren — versleuteld in rust in een secrets manager, geïnjecteerd in de runtime-omgeving bij het opstarten, en nooit gebundeld in client-side JavaScript. Sleutels mogen nooit voorkomen in broncode, versiebeheersgeschiedenis, build-logs of enige HTTP-respons die een browser bereikt.

Wat zijn de risico's van het hardcoderen van API-sleutels in broncode?

Een sleutel rechtstreeks hardcoderen in je JavaScript- of TypeScript-bestand creëert minstens drie afzonderlijke aanvalsoppervlakken:

  1. Blootstelling via publieke repository. De secret-scanning-bot van GitHub onderschept sommige sleutels, maar draait na de push. In de minuten tussen push en detectie scrapen geautomatiseerde bots voortdurend nieuwe commits. GitGuardian rapporteerde in 2023 dat meer dan 10 miljoen geheimen werden gedetecteerd in publieke commits — een stijging van 67% jaar-op-jaar.
  2. Opname in de client-bundle. Zelfs als je repository privé is, zal een bundler zoals webpack of de Next.js-compiler elke geïmporteerde constante inlinen in het JavaScript dat naar de browser wordt gestuurd. Iedereen kan Chrome DevTools → Sources openen en zoeken naar je sleutelprefix (sk-, SG., pk_live_).
  3. Lekkage via build-logs. CI-systemen printen omgevingswaarden vaak tijdens installatie- of bouwstappen. Een verkeerd geconfigureerd logbewaarbeleid kan die logs leesbaar maken voor iedereen met toegang tot de repository.

"Het duurde minder dan 30 seconden nadat ik naar GitHub had gepusht voordat een geautomatiseerde bot mijn AWS-sleutel vond en GPU-instanties begon op te starten. De rekening bedroeg $8.000 voordat ik het merkte." — een veelgemeld patroon in ontwikkelaar-postmortems op Hacker News.

De conclusie is simpel: een sleutel die ooit de client-bundle of een publieke log raakt, is al gecompromitteerd, zelfs als je hem onmiddellijk roteert.

Moeten API-sleutels worden opgeslagen in omgevingsvariabelen?

Omgevingsvariabelen zijn de standaard stap omhoog ten opzichte van hardcoderen, maar ze komen met een belangrijke kanttekening in frameworks zoals Next.js: alleen variabelen met het voorvoegsel NEXT_PUBLIC_ worden opzettelijk blootgesteld aan de browser. Elke variabele zonder dat voorvoegsel blijft op de server — maar alleen als je er uitsluitend toegang toe hebt binnen getServerSideProps, Route Handlers, API-routes of servercomponenten.

De val waar veel ontwikkelaars in trappen, is het verwijzen naar een niet-publieke omgevingsvariabele binnen een component die Next.js statisch rendert tijdens build-time. De bundler ziet de verwijzing, lost de waarde op en inlinet die in de uitvoer-HTML. Op dat punt bood de naam van de variabele valse veiligheid.

Build-time vs. runtime-injectie is het cruciale onderscheid:

  • Build-time — waarden die tijdens next build in de bundle worden ingebakken. Snel, maar het geheim is bevroren in het artifact.
  • Runtime-injectie — waarden die worden gelezen uit de procesomgeving van de server nadat de container is gestart, waarbij de bundle nooit wordt aangeraakt. Dit is het juiste model voor geheimen.

Runtime-injectie betekent dat zelfs als iemand je build-artifact verkrijgt, de sleutel er niet in zit. Het geheim leeft alleen in de uitvoeringsomgeving.

Hoe gebruik je een secrets manager om API-sleutels op te slaan?

Een secrets manager is een speciale dienst die inloggegevens versleuteld in rust opslaat, toegang beheert via IAM-achtig beleid en waarden bij runtime aan je applicatie levert zonder ze tijdens transport bloot te stellen. AWS Secrets Manager en HashiCorp Vault zijn de twee meest voorkomende keuzes.

De typische stroom ziet er zo uit:

  1. Je slaat het geheim (bijv. je Stripe-geheime sleutel) op in de secrets manager via de UI of CLI.
  2. Het geheim wordt versleuteld met een KMS-sleutel die alleen de IAM-rol van je applicatie kan ontsleutelen.
  3. Wanneer je server opstart, roept hij de secrets manager API aan, ontsleutelt de waarde en laadt die in process.env — alleen in het geheugen.
  4. Je code leest process.env.STRIPE_SECRET_KEY tijdens runtime. De waarde stond nooit in broncode, nooit in een build-artifact, nooit in een log.

Deze architectuur betekent dat het roteren van een sleutel alleen het bijwerken van de waarde in de secrets manager vereist; geen code-wijziging, geen heruitrol van de bundle.

Hoe werkt de versleutelde secrets-kluis van FloopFloop?

FloopFloop beschikt over een ingebouwde secrets-kluis ondersteund door AWS KMS. Wanneer je via de projectinstellingen-UI van het platform een externe API-sleutel toevoegt — bijvoorbeeld een Stripe-geheime sleutel of een SendGrid API-sleutel — versleutelt FloopFloop die onmiddellijk in rust. De sleutel wordt bij het opstarten geïnjecteerd in de Lambda-runtime-omgeving van je app en wordt nooit geschreven in gegenereerde broncode, nooit afgedrukt in build-logs en nooit blootgesteld in CloudFront-reacties.

Dit elimineert de meest voorkomende categorie van sleutellekkagefouten volledig. Je hoeft zelf geen IAM-rollen, rotatieroosters of KMS-sleutelbeleid te configureren — het platform beheert die laag.

Een externe API-sleutel toevoegen: stap voor stap

  1. Open je project in FloopFloop en navigeer naar het instellingenpaneel van het project.
  2. Zoek de sectie Secrets en klik op Add Secret.
  3. Voer de variabelenaam in (bijv. STRIPE_SECRET_KEY) en plak de sleutelwaarde.
  4. Sla op. FloopFloop versleutelt de waarde met KMS en koppelt deze aan je project.
  5. Verwijs er in de server-side code van je app naar als process.env.STRIPE_SECRET_KEY. Het is beschikbaar tijdens runtime in Lambda-functies en servercomponenten — nooit in client-bundles.
  6. De continue implementatie van FloopFloop neemt het nieuwe geheim op bij de volgende generatiedoorloop; er is geen handmatige heruitrolstap nodig.

Je geheime waarde wordt versleuteld voordat ze je browsersessie verlaat en wordt nergens in de infrastructuur van FloopFloop in platte tekst opgeslagen.

Hoe voorkom je dat API-sleutels worden blootgesteld in client-side code?

Voor LLM-aanroepen is het meest robuuste patroon een AI-gateway — een server-side proxy die de API-inloggegevens bewaart en verzoeken van je frontend doorstuurt. Je browsercode roept /api/chat aan; je server roept OpenAI aan. De sleutel komt nooit bij de client.

FloopFloop gaat hier verder met een ingebouwde AI-gateway. Apps die op het platform worden gegenereerd, kunnen ondersteunde LLM's aanroepen via de gateway zonder dat de gebruiker een persoonlijke API-sleutel van OpenAI, Anthropic of een andere modelleverancier hoeft op te geven. Het platform beheert modelroutering, snelheidslimieten en gebruikstegoeden centraal. Dit betekent dat het LLM-integratiepad nul-inloggegevens vereist voor de ontwikkelaar — er is simpelweg geen sleutel die kan lekken.

Kunnen API-sleutels veilig worden opgeslagen in een database?

Ja, onder voorwaarden. Geheimen opslaan in een database is geldig als:

  • De kolom is versleuteld op de applicatielaag (niet alleen schijfversleuteling in rust, die geen bescherming biedt tegen SQL-injectie).
  • Toegang tot de ontsleutelingssleutel strikt wordt gecontroleerd (bij voorkeur via een KMS-beheerde sleutel, niet een hardgecodeerde sleutel).
  • Het geheim server-side wordt opgehaald en alleen voor de duur van het verzoek in het geheugen wordt bewaard — nooit geserialiseerd in een JSON-respons.

Een database is niet geschikt als primaire geheimopslag als de verbindingsreeks van diezelfde database zelf onveilig wordt opgeslagen. Dan kom je in een circulaire afhankelijkheid terecht. Een toegewijde secrets manager (of een platform dat er een biedt) vermijdt die val.

Beveiligingsverificatiechecklist voor je gedeployde app

Na het deployen, doorloop deze controles op je live <project>.floop.tech-URL (of je aangepaste domein):

  • Bekijk paginabron — zoek naar je sleutelprefixen (sk-, pk_live_, SG., Bearer ). Geen enkele mag verschijnen.
  • DevTools → Netwerktabblad — inspecteer API-reacties. Geheime waarden mogen niet voorkomen in enige JSON-payload die naar de browser wordt teruggestuurd.
  • DevTools → Sources — zoek alle geladen JS-bundles naar de eerste 8 tekens van elke sleutel.
  • Build-logs — bevestig dat geen console.log, debug-uitvoer of foutstack-trace een geheime waarde afdrukt.
  • HTTP-reactieheaders — geheimen mogen niet voorkomen in Set-Cookie, aangepaste headers of foutpagina's.
  • Roteer elke sleutel die een controle niet doorstaat onmiddellijk — ga ervan uit dat hij al bekend is bij aanvallers.

Afsluiting

API-sleutels veilig opslaan in een webtoepassing komt neer op één regel: geheimen horen op de server, versleuteld in rust, geïnjecteerd tijdens runtime en nooit in enig artifact dat een browser bereikt. Gebruik omgevingsvariabelen correct, geef de voorkeur aan een KMS-ondersteunde secrets manager boven .env-bestanden en overweeg een AI-gateway om LLM-inloggegevens volledig uit je project te verwijderen. Als je bouwt op FloopFloop, behandelen de versleutelde secrets-kluis en de ingebouwde AI-gateway beide zorgen automatisch, zodat je je kunt concentreren op wat je app daadwerkelijk doet.

Veelgestelde vragen

Wat is de veiligste manier om API-sleutels op te slaan in een webtoepassing?

De veiligste aanpak is om API-sleutels uitsluitend aan de serverzijde op te slaan, versleuteld in rust in een toegewijde secrets manager (zoals AWS Secrets Manager of een door het platform beheerde kluis), en geïnjecteerd in de runtime-omgeving van de server bij het opstarten. Sleutels mogen nooit voorkomen in client-side JavaScript-bundles, versiebeheersgeschiedenis, build-logs of enige HTTP-respons die naar een browser wordt gestuurd.

Moeten API-sleutels worden opgeslagen in omgevingsvariabelen?

Ja, maar met zorg. In frameworks zoals Next.js blijven alleen server-side omgevingsvariabelen (die zonder het voorvoegsel NEXT_PUBLIC_) buiten de client-bundle — en alleen als je ze uitsluitend benadert in server-side code zoals API-routes of servercomponenten. Voor sterkere bescherming gebruik je een secrets manager die waarden injecteert tijdens runtime in plaats van ze in te bakken in het build-artifact.

Hoe voorkom je dat API-sleutels worden blootgesteld in client-side code?

Importeer of verwijs nooit naar een geheime sleutel binnen een component of module die in de browser wordt uitgevoerd. Routeer alle geauthenticeerde API-aanroepen via een server-side handler of een AI-gateway die de inloggegevens bewaart. De browsercode roept je server aan; je server roept de externe API aan. De sleutel komt nooit bij de client.

Wat zijn de risico's van het hardcoderen van API-sleutels in broncode?

Hardgecodeerde sleutels zijn om drie redenen gevaarlijk: ze belanden in de versiebeheersgeschiedenis (waar geautomatiseerde bots publieke repositories scannen binnen seconden na een push), ze worden door bundlers ingelind in client-JavaScript-bundles, en ze kunnen verschijnen in CI-build-logs. Elk van deze blootstellingen moet worden behandeld als een volledige compromittering die onmiddellijke sleutelrotatie vereist.

Hoe gebruik je een secrets manager om API-sleutels op te slaan?

Sla het geheim op in de secrets manager via de UI. De dienst versleutelt de waarde met een KMS-sleutel die is gekoppeld aan de toegangsrol van je applicatie. Wanneer je server opstart, haalt hij de waarde op en ontsleutelt die alleen in het procesgeheugen — hij raakt je broncode of build-uitvoer nooit aan. Het roteren van de sleutel vereist alleen het bijwerken van de waarde in de secrets manager, zonder dat er codewijzigingen nodig zijn.

Kunnen API-sleutels veilig worden opgeslagen in een database?

Ja, mits het geheim is versleuteld op de applicatielaag met een KMS-beheerde sleutel (niet alleen schijfniveau-versleuteling), toegang is beperkt tot server-side processen, en de ontsleutelde waarde nooit wordt geserialiseerd in een API-respons. Een toegewijde secrets manager verdient echter over het algemeen de voorkeur omdat die het circulaire probleem vermijdt van het beveiligen van de databaseverbindingsreeks zelf.

Deel dit artikel

Abonneer je op de FloopFloop-nieuwsbrief

Nieuwe artikelen, product-updates en af en toe een les — rechtstreeks in je inbox.

We delen je e-mailadres nooit. Je kunt je op elk moment uitschrijven.

Gerelateerde artikelen