Naar de inhoud
CodeAuditAgent
Alle artikelen

Gelekte secrets in de git-geschiedenis: vinden, roteren, voorkomen

Een gecommitte API-sleutel verdwijnt niet uit de git-geschiedenis. Zo vind je gelekte secrets, roteer je ze eerst en voorkom je het volgende lek.

· 7 min. leestijd · Lina Source LLC

Iemand commit een .env-bestand, of plakt een live API-sleutel in een configuratiemodule om snel iets te testen. Een reviewer merkt het op, de sleutel wordt in de volgende commit verwijderd en iedereen gaat verder. De sleutel staat er nog steeds. Git bewaart elke versie van elk bestand, en iedereen die de repository kan clonen, kan de commit lezen die hem toevoegde.

Hardgecodeerde credentials worden bijgehouden als CWE-798. Deze gids behandelt wat je doet als er al een in de geschiedenis is beland: elk secret vinden, ze vóór alles roteren, bepalen of het herschrijven van de geschiedenis de moeite waard is, en de waarborgen inrichten die het volgende lek tegenhouden.

Waarom de regel verwijderen niet genoeg is

Een commit die een secret verwijdert, voegt een nieuwe momentopname toe zonder dat secret. De vorige momentopname, mét het secret, wordt nog altijd door de geschiedenis van de branch aangehaald. git log -p laat hem zien, een git checkout van de oude commit herstelt hem, en elke bestaande clone en fork heeft al een kopie. De branch squashen vóór de merge helpt evenmin als de oorspronkelijke commits ooit zijn gepusht: de remote kan ze nog hebben, en iedereen die ze heeft opgehaald, heeft ze lokaal.

Ga er bij een openbare repository van uit dat het secret is gezien. Geautomatiseerde scrapers houden openbare pushes in de gaten op patronen van credentials, en het venster tussen een push en het eerste misbruik kan heel kort zijn. Bij een privérepository is de blootstelling kleiner maar niet nul: elke medewerker, contractor, elk CI-systeem en elke integratie met leestoegang heeft hem.

Stap 1: roteer eerst

Roteren is de enige stap die het risico echt wegneemt. De geschiedenis herschrijven verbergt het secret voor toekomstige clones; aan de kopieën die al bestaan verandert het niets. Trek de credential dus in en vervang hem voordat je aan de repository komt.

Plan de rotatie zo dat er geen storing ontstaat. Veel providers laten twee sleutels tegelijk geldig zijn: maak de nieuwe sleutel aan, rol hem uit op alle plekken waar de oude werd gebruikt, bevestig dat het verkeer is verplaatst en trek daarna de oude in. Staat de provider maar één sleutel toe, neem dan een korte onderbreking voor lief; een paar minuten downtime is een betere afweging dan een bekend gelekte credential actief laten terwijl je een perfecte overgang coördineert.

  • Genereer een nieuwe sleutel in de console van de provider en rol hem uit via je gebruikelijke configuratiepad.
  • Trek de oude sleutel in. Stop niet alleen met het gebruik ervan; een ongebruikte geldige sleutel is nog steeds een geldige sleutel.
  • Bekijk de auditlogs van de provider op activiteit met de oude sleutel sinds de datum van de commit: API-aanroepen, nieuwe gebruikers, gewijzigde rechten, onverwachte facturering.
  • Was het secret een databasewachtwoord of ondertekeningssleutel, denk dan na over wat het kon ontsluiten. Een gelekt JWT-ondertekeningssecret betekent dat elk token vervalst kan zijn, dus maak bestaande sessies ongeldig.
  • Leg vast wat er is blootgesteld, hoe lang en wat je hebt gewijzigd. Je hebt het nodig als een klant of auditor ernaar vraagt.

Stap 2: vind alles wat is gelekt

Waar één gecommit secret is, zijn er vaak meer. Doorzoek de volledige geschiedenis, niet alleen de huidige boom, en neem elke branch en tag mee.

# Commits die ergens in de geschiedenis een string toevoegden of verwijderden
git log -p -S "sk_live_" --all

# Regex-zoekactie door de diffs van alle commits
git log -p -G "AKIA[0-9A-Z]{16}" --all

# Bestanden die ooit op een verdacht pad hebben bestaan
git log --all --oneline -- .env config/production.json

# Speciale scanners kennen honderden bekende credential-formaten
gitleaks git -v .
trufflehog git file://. --only-verified

gitleaks en trufflehog zijn opensourcescanners die hiervoor zijn gemaakt. Ze kennen de formaten van veelgebruikte providersleutels, en trufflehog kan controleren of een gevonden credential nog actief is. Oudere gitleaks-versies gebruiken gitleaks detect --source . in plaats van het git-subcommando. Draai een scanner één keer over de volledige geschiedenis en houd hem daarna op nieuwe commits draaien. Verwacht wat vals-positieven, zoals testfixtures en voorbeeldsleutels in documentatie. Beoordeel ze stuk voor stuk en leg de bevestigde vals-positieven vast in de allowlist of het baselinebestand van de scanner, zodat de volgende run alleen nieuwe bevindingen toont.

Vergeet de plekken rondom de repository niet: CI-logs die omgevingsvariabelen hebben geëchood, opmerkingen bij issues en pull requests, wikipagina’s, Docker-imagelagen die vanuit de repository zijn gebouwd, en gists of pastes die tijdens het debuggen zijn gedeeld.

Stap 3: bepaal of je de geschiedenis herschrijft

Zodra het secret is geroteerd, is het waardeloos, dus de geschiedenis herschrijven is opruimen en geen indamming. Toch is het de moeite waard als de repository openbaar is, als het secret meer prijsgeeft dan zichzelf (een interne hostnaam, een klantnaam), of als compliance het vereist. Er hangt een prijskaartje aan: elke medewerker moet opnieuw clonen, openstaande pull requests raken ontregeld en commit-hashes veranderen. Alles wat naar een commit-hash verwijst, zoals release notes, deploy-registraties, issuelinks of vastgezette dependencies in andere repository’s, wijst daarna naar commits die niet meer op de branch bestaan. Kondig het herschrijven van tevoren aan, kies een rustig moment en merge of sluit eerst de openstaande pull requests.

git filter-repo is de tool die het Git-project hiervoor aanbeveelt, in plaats van het oudere git filter-branch. Hij werkt op een verse clone en verwijdert uit voorzorg de origin-remote, dus die voeg je vóór het pushen weer toe.

# Begin met een verse clone
git clone [email protected]:acme/api.git api-clean
cd api-clean

# Optie A: verwijder een bestand uit elke commit
git filter-repo --invert-paths --path config/production.env

# Optie B: vervang secret-strings overal waar ze voorkomen
# replacements.txt bevat één regel per vervanging, bijvoorbeeld:
#   PASTE_THE_OLD_KEY_HERE==>REDACTED
git filter-repo --replace-text ../replacements.txt

# filter-repo verwijdert origin; voeg hem terug toe en force-push
git remote add origin [email protected]:acme/api.git
git push --force --all
git push --force --tags

Wat herschrijven niet kan

  • Het bereikt bestaande clones, forks, CI-caches of back-ups niet. Wie vóór het herschrijven heeft opgehaald, houdt de oude commits.
  • Op GitHub zijn de referenties die voor pull requests worden aangemaakt alleen-lezen en kunnen ze oude commits bereikbaar houden. Voor het verwijderen van gecachete weergaven en die referenties moet je contact opnemen met GitHub Support.
  • Medewerkers die vanuit een oude clone pullen of mergen, kunnen de oude geschiedenis zo weer terugpushen. Vraag iedereen opnieuw te clonen en bescherm de branch zolang dat loopt.
  • Het verwijdert het secret niet van alle andere plekken waar het is gekopieerd: logs, tickets, chatberichten of gebouwde artefacten.

Daarom doet de volgorde ertoe. Eerst roteren, dan opruimen. Een herschreven geschiedenis met een actieve sleutel geeft een vals gevoel van veiligheid. Draai na de push je scanner over een verse clone om te bevestigen dat het secret echt uit elke branch en tag verdwenen is.

Stap 4: voorkom het volgende lek

Het doel is een secret committen moeilijk maken en er een opmerken snel. Geen enkele maatregel doet allebei, dus stapel ze.

Houd secrets buiten het codepad

Lees credentials tijdens runtime uit omgevingsvariabelen of een secret manager, en controleer bij het opstarten of de benodigde waarden aanwezig zijn. Commit een .env.example met placeholderwaarden en zet .env vanaf de eerste commit in .gitignore. Voor productie geeft een secret manager zoals AWS Secrets Manager, Google Secret Manager, HashiCorp Vault of de versleutelde omgevingsinstellingen van je platform je toegangsbeheer, auditlogs en eenvoudiger roteren.

Blokkeer secrets voordat ze worden gecommit

Een pre-commit hook vangt de fout op de machine van de ontwikkelaar, nog voordat die de remote bereikt. Met het pre-commit-framework is dat een paar regels configuratie die iedere bijdrager kan installeren.

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: vX.Y.Z  # pin op de laatste release-tag
    hooks:
      - id: gitleaks

# Eén keer per clone installeren
#   pip install pre-commit
#   pre-commit install

Hooks zijn lokaal en kunnen worden overgeslagen, dus draai dezelfde scanner als vangnet in CI bij elke push. Zet op GitHub secret scanning en push protection aan waar je abonnement dat ondersteunt; push protection weigert aan de serverkant pushes die herkende providertokens bevatten.

Beperk de schade van de lekken die je mist

  • Geef elke sleutel de minimale rechten en, waar de provider dat toestaat, een beperking tot specifieke IP’s of referrers.
  • Geef de voorkeur aan kortlevende credentials, zoals OIDC-federatie van CI naar je cloudprovider, boven langlevende statische sleutels.
  • Gebruik aparte sleutels per omgeving, zodat een gelekte testsleutel niet aan productie kan komen.
  • Houd voor elk kritiek secret een rotatie-runbook bij, zodat roteren onder druk routine is in plaats van improvisatie.

Waar codereview past

Scanners herkennen bekende formaten goed; ze zijn zwakker in context, zoals een wachtwoord dat uit twee constanten wordt samengesteld of een standaardcredential die als fallback in een configuratie meekomt. Een reviewronde door de code vangt die wel. CodeAuditAgent markeert hardgecodeerde credentials als CWE-798 met het geciteerde bewijs wanneer het de standaardbranch van een openbare repository of een geplakt codefragment auditeert. Het leest de huidige code, niet de commitgeschiedenis, dus houd een geschiedenisscanner in de lucht voor eerdere commits.

Kort samengevat: een gecommit secret is een gelekt secret. Roteer het vandaag, ruim de geschiedenis op als het de verstoring waard is, en zorg dat het volgende lek strandt bij de pre-commit hook in plaats van op een openbare pagina.