retrAIt Plan jouw dag ↗
Blog / Veilig bouwen met AI

Wachtwoorden en API-sleutels in je code: zo voorkom je een lek

5 minuten lezenDelen

Een oude sleutel hangt aan een spijker in een ruwe lemen muur, naast een tang en wat draad
Foto Baraa Obied via Pexels
Het korte antwoord

Een API-sleutel is een wachtwoord voor programma's en hoort in een .env-bestand op je server, buiten de webmap, alleen leesbaar voor jou en nooit in git. Alles wat de browser binnenkrijgt, is openbaar. Lekt er toch een sleutel, dan maak je een nieuwe en trek je de oude in, want alleen weghalen is niet genoeg.

Een API-sleutel is een lange code waarmee je programma zich meldt bij een andere dienst, zoals een maildienst of Mollie. API is de naam voor de manier waarop programma’s met elkaar praten, en de sleutel is het wachtwoord daarbij. Wie de sleutel heeft, kan bij die dienst alles wat jij kunt. Daarom hoort een sleutel op één plek: in een bestand op je server dat niet online komt en niet in git staat. Lekt hij toch, dan helpt alleen een nieuwe maken en de oude intrekken.

Wat een sleutel kan

Met de sleutel van je maildienst verstuurt een ander mail uit naam van je domein, en met een sleutel van je database kan hij bij alles wat erin staat. De schade komt bij jou, soms met de rekening erbij.

Twee gewoontes maken een lek minder erg. Geef een sleutel niet meer rechten dan nodig: veel diensten laten je kiezen wat een sleutel mag, bijvoorbeeld alleen mail versturen en geen instellingen veranderen. En bouw met een testsleutel als de dienst die heeft. Mollie geeft je naast een echte sleutel een testsleutel, en raadt in de eigen documentatie aan om daarmee te bouwen en pas over te stappen als je echte betalingen gaat ontvangen. Een testsleutel die uitlekt, raakt geen echt geld.

Waar een sleutel hoort

Een sleutel hoort in een bestand dat .env heet: een gewoon tekstbestand met op elke regel een naam en een waarde, zoals hieronder. Je programma leest de waarden daaruit wanneer het start.

MAIL_API_KEY=hier-de-sleutel
MOLLIE_API_KEY=hier-de-testsleutel

Voor zo’n bestand gelden vier afspraken:

  • Buiten de webmap. .env staat in de map van je programma, bijvoorbeeld /opt/mijnplatform. Nooit in /var/www, want daar staat alles wat bezoekers kunnen opvragen.
  • Alleen leesbaar voor de eigenaar. Dat regel je met chmod 600 .env. Draait je programma onder een eigen gebruiker, dan is die gebruiker de eigenaar.
  • Niet in git. Zet .env in .gitignore voordat je de eerste keer iets vastlegt. Een bestand met alleen de namen, zonder waarden, mag wel in git, zodat je later weet welke sleutels er nodig zijn.
  • Niet in het gesprek. Vul de waarden zelf in, bijvoorbeeld met de teksteditor nano. Zet ze niet in CLAUDE.md, niet in een chat en niet op een schermafbeelding die je deelt als je om hulp vraagt.

In Claude Code kun je bovendien vastleggen dat hij .env niet mag lezen. De documentatie over instellingen geeft daarvoor als voorbeeld de regels Read(./.env) en Read(./.env.*) in de lijst met wat niet mag. Zie zo’n regel als een stevige drempel, niet als een kluis.

Op een server van retrAIt zijn er nog twee vangnetten. publish, het commando dat een site online zet, neemt bestanden waarvan de naam met een punt begint niet mee. En de webserver weigert zulke bestanden op elke site die publish heeft ingericht. Bouw er niet op. Een vangnet is voor de keer dat het misgaat, niet voor elke dag.

Alles wat de browser krijgt, is openbaar

Een site met alleen pagina’s heeft geen geheime sleutels nodig, en hoort er ook geen te bevatten. Alles in je HTML, je scripts en je stijlbestanden downloadt elke bezoeker mee. Wie wil, leest het, bijvoorbeeld met de ontwikkelhulpmiddelen die in elke browser zitten. Een sleutel in een script is dus openbaar, ook als je hem op de pagina nergens ziet.

Heeft je site iets nodig waar een geheime sleutel bij hoort, zoals een formulier dat mail verstuurt, dan hoort daar een klein programma op je server bij. De browser stuurt het formulier naar dat programma, en alleen het programma praat met de maildienst. Zo werkt het in Een contactformulier dat echt aankomt.

Sommige diensten geven naast een geheime sleutel ook een sleutel die openbaar mag zijn. Die mag in de browser staan, maar hij geeft alleen de rechten van een willekeurige bezoeker, en hij is pas veilig als de dienst goed is ingesteld. Juist daar ging het vaak mis in het onderzoek uit Waarom apps die met AI gebouwd zijn zo vaak lekken.

Een voorbeeld. Sanne geeft yogales en laat Claude een aanmeldformulier bouwen dat een bevestiging mailt. Het werkt meteen. Een week later vraagt ze Claude om alle bestanden die online staan na te lopen op sleutels. Dan blijkt de sleutel van de maildienst in script.js te staan, het script dat elke bezoeker binnenkrijgt. Ze laat Claude een klein programma op de server maken dat de mail verstuurt, zet een nieuwe sleutel in een .env en trekt de oude in, precies zoals hieronder.

Git vergeet niets

Git bewaart elke versie van elk bestand dat je ooit hebt vastgelegd. Kwam je .env, of een sleutel in je code, ooit in een commit terecht, dan staat hij in de geschiedenis, ook als je hem een commit later weer weghaalt. Die geschiedenis gaat mee in elke kopie van je project, zoals de kopie die je naar je laptop haalt.

.gitignore helpt dan niet meer. Volgens de documentatie van git geldt het alleen voor bestanden die git nog niet volgt. Een bestand dat al is vastgelegd, haal je eerst uit git met git rm --cached .env, en pas daarna werkt de regel. De oude versies staan dan nog steeds in de geschiedenis.

Die geschiedenis herschrijven kan, maar het is lastig werk, en kopieën die al bestaan veranderen er niet door. GitHub zegt het in de uitleg over gevoelige gegevens zonder omwegen: gaat het om een geheim, trek het dan als eerste in of vervang het. Een ingetrokken sleutel doet niets meer, waar hij ook staat.

Een gelekte sleutel vervangen

Behandel een sleutel die ergens heeft gestaan waar hij niet hoorde als gelekt, ook als het maar tien minuten was. Je weet niet wie hem heeft gezien, en programma’s die internet afzoeken zijn snel. Werk dan in deze volgorde:

  1. Maak bij de dienst een nieuwe sleutel, met zo weinig rechten als nodig.
  2. Zet de nieuwe sleutel zelf in je .env en start je programma opnieuw.
  3. Controleer of alles werkt, bijvoorbeeld met een testmail.
  4. Trek de oude sleutel in bij de dienst. Vanaf dat moment doet hij niets meer.
  5. Kijk in het overzicht van de dienst of de oude sleutel is gebruikt op momenten dat jij niets deed.
  6. Haal de sleutel weg op de plek waar hij lekte, en zorg dat het niet opnieuw kan gebeuren.

Zie je dat de sleutel al wordt misbruikt, trek hem dan meteen in, nog vóór stap 1. Een uur zonder mail is minder erg dan een uur misbruik. OWASP, een internationale stichting voor veilige software, beschrijft in zijn overzicht over het beheer van geheimen dezelfde aanpak: de oude sleutel intrekken, een nieuwe in gebruik nemen en daarna opruimen waar hij lekte. Konden er via die sleutel gegevens van mensen worden ingezien, lees dan ook Een datalek op je eigen site.

Loop vandaag je eigen project na. Kijk met ls -la of er een .env en een .gitignore staan, en of git log --all --oneline -- .env niets teruggeeft. Vraag Claude daarna om in je bestanden en in de geschiedenis van git te zoeken naar sleutels, zonder .env te lezen en zonder een gevonden sleutel op je scherm te zetten. Elke geheime sleutel die hij vindt, vervang je volgens de stappen hierboven.

Foto bovenaan: Baraa Obied via Pexels

Delen

Ken je iemand die hier iets aan heeft?

Stuur het door, of deel het als beeld in je story of op LinkedIn.

Als beeld, voor je story of een post

Op een telefoon deel je het beeld meteen, bijvoorbeeld als story op Instagram of in je WhatsApp-status. Op een computer bewaar je het. Zet de link erbij, in je bericht of als sticker.

Meer over veilig bouwen met AI

Alles over veilig bouwen met AI