API's en sleutels beveiligen
De actuele securitystatus en de concrete acties voor Share, Google, Gemini en Sentry.
Belangrijk onderscheid: een sleutel die in een mobiele app of webpagina zit, is geen geheim. Beperk daarom precies waar hij gebruikt mag worden, welke API hij mag aanroepen en hoeveel hij maximaal kan kosten. Een echte serversecret — zoals een Sentry Auth Token of de nieuwe Gemini-proxy-key — hoort nooit in de app.
Huidige prioriteit vóór een publieke apprelease. De appmigratie is lokaal voorbereid: Gemini en Places gaan via aparte serverproxies en de kaart via een eigen HTTPS-pagina. De resterende stappen zijn de drie afzonderlijke Google-sleutels correct beperken, serversecrets plaatsen, live testen en de historische Sentry Auth Token roteren.
Deze handleiding behandelt vier onderdelen:
- Private Share API — huidige bescherming en volgende servermaatregelen
- Google Cloud Platform (Maps & Places) — aparte keys per client voorbereiden
- Google AI Studio (Gemini) — API-beperking, quota en serverproxy
- Sentry — tokenrotatie en build-only secret
0. Controleer eerst of er geen sleutel in git is gecommit. Open een terminal in de projectmap en draai:
git ls-files | grep -iE "env|key|secret"
Er mag alleen .env.example verschijnen. Als .env in de lijst staat, trek die sleutels meteen in en draai ze om (rotatie). Alleen .env.example (zonder echte waarden) hoort gecommitted te zijn.
Doel: voorkom geheimen in de repository-geschiedenis. Zwakke plek die dit dekt: gelekte sleutels via het GitHub-archief.
1. Google Maps & Places API-sleutels (Google Cloud)
De voorbereide app gebruikt geen generieke Google-clientkey meer. Places gaat naar de Gustra-serverproxy; de WebView laadt een Gustra HTTPS-kaart met een afzonderlijke browserkey. Eventuele native Maps SDK-sleutels blijven per platform gescheiden en zijn nu niet nodig.
Status (2026-09-03): rotatie afgerond. Het project gustra-503718 bevat nog precies drie actieve, doelgericht beperkte keys — Gustra Maps - Browser 2026-08-26, Gustra Places - Server 2026-08-26 en Gustra Gemini - Server 2026-08-26. De historisch gedeelde, generieke key (die ooit in de app-code/git-historie stond) is niet meer aanwezig in het project.
Niet overslaan: Google laat per key slechts één soort toepassingsrestrictie toe. Android, iOS en website-referrers horen daarom niet op dezelfde key. Als je de huidige ene key zomaar op Android of iOS beperkt, kunnen andere Gustra-functies stoppen.
Stap 1.1 — Open de juiste console
- URL: https://console.cloud.google.com/apis/credentials
- Zorg dat bovenaan het juiste project geselecteerd is (het project dat je bij de Gustra-app gebruikt).
- Doel: jullie API-keys centraliseren. Weakness die dit dekt: verspreide/onbekende sleutels die je over het hoofd ziet.
Stap 1.2 — Maak eerst een key-inventaris (geen waarden kopiëren)
- Noteer uitsluitend key-namen en gebruik, nooit key-waarden in tickets, chat of documenten.
- Plan drie afzonderlijke keys: Gustra Android, Gustra iOS en Gustra WebView/web. Houd development-keys apart van productie.
- Doel: een lek of verkeerd ingestelde restrictie beperkt zich tot één platform. Let op: de appconfiguratie moet eerst per platform een eigen key kunnen lezen; doe deze opsplitsing als een kleine, geteste appwijziging.
Stap 1.3 — Zet één toepassingsrestrictie per afzonderlijke key
- Klik op één specifieke key. Scroll naar “Application restrictions” → klik “Restrict and edit key”.
- Kies uitsluitend het type dat bij die ene key past:
- Android apps — voeg
net.gustra.apptoe met de SHA-1 van Play App Signing voor de Play-build. - iOS apps — voeg
com.philip.gustratoe. - HTTP referrers (Web) — voeg alleen de exacte Gustra-domeinen toe die werkelijk een webkaart laden.
- Android apps — voeg
- Test elk platform vóór je de oude key intrekt. De huidige ingebedde Maps JavaScript-WebView vereist een afzonderlijke compatibiliteitstest; veronderstel niet dat een website-referrer daar automatisch werkt.
- Doel: een key mag maar vanuit één gecontroleerd clienttype gebruikt worden.
Stap 1.4 — Gebruik de juiste Android SHA-1
- Voor Play Internal en Play Production: Play Console → Setup → App integrity → App signing key certificate → SHA-1.
- Voor een lokale debug/dev-client gebruik je een aparte development-key met de lokale debug-SHA-1; meng die niet met de productiesleutel.
- Doel: alleen de door Google Play ondertekende Gustra-app mag de productiesleutel gebruiken.
Stap 1.5 — Zet de API-restrictie (welke API's deze sleutel mag aanroepen)
- Scroll naar “API restrictions” → kies “Restrict key”.
- Vink per key alleen de API's aan die die client werkelijk nodig heeft. Geef een Gemini-key nooit Maps/Places-toegang en omgekeerd.
- Klik “Save”.
- Doel: zelfs als de sleutel lekt, kan een aanvaller er geen andere Google API's mee aanroepen. Weakness: anders is één sleutel een greep in de volledige Google Cloud-mogelijkheden.
Stap 1.6 — Zet quota-limieten
- URL: https://console.cloud.google.com/apis/quotas
- Stel per API een realistische daglimiet in en maak een budgetalert aan vóór kosten ontstaan. Start bewust laag tijdens Internal Testing en verhoog alleen na meetbaar legitiem gebruik.
- Doel: begrenzen wat een lek of fout in één dag kan verbruiken. Client-side Gustra-limieten zijn nuttig voor UX, maar geen beveiligingsgrens.
Stap 1.7 — Gebruik precies drie sleutelrollen
- Places server: alleen Places API (New), opgeslagen buiten de webroot; geen app- of browserrestrictie.
- Maps web: alleen Maps JavaScript API, HTTP-referrer
https://share.gustra.net/map/*. - Gemini server: alleen Gemini API, eveneens uitsluitend server-side.
- Maak pas iOS-/Android-Maps-keys wanneer Gustra daadwerkelijk naar een native Maps SDK verhuist.
2. Gemini API-sleutel (Google AI Studio / wijnlabels)
De mobiele app bevat vanaf de volgende interne build geen Gemini-sleutel meer. Wijnlabels en zoekopdrachten gaan naar een doelgerichte Gustra-proxy; alleen de server gebruikt de geroteerde key Gustra Gemini - Server 2026-08-26. De vorige serverkey is verwijderd.
Status (2026-09-03): de oude client-side Gemini/Google-sleutels (EXPO_PUBLIC_GEMINI_API_KEY en EXPO_PUBLIC_GOOGLE_API_KEY) zijn uit .env verwijderd én ingetrokken in Google AI Studio resp. Google Cloud Console. De app gebruikt uitsluitend nog de serverproxy.
Stap 2.1 — Open Google AI Studio
- URL: https://aistudio.google.com/apikey
- Kies het juiste Google-project bovenaan.
- Doel: jullie Gemini-sleutels beheren. Weakness: zonder centrale plaats zie je niet alle regels/changes voor je project.
Stap 2.2 — Server-key en kosten begrenzen
- De nieuwe key is gekoppeld aan
gustra-backenden beperkt tot uitsluitend de Gemini API. Bewaar hem alleen als serversecret buiten de webroot; nooit in EAS,EXPO_PUBLIC_*, git of appbuilds. - Het Google-project heeft een uitgavenlimiet van €50 en waarschuwingen op €25, €40 en €50. De Gustra-proxy voegt daar per-IP-limieten en standaard maximaal 250 aanvragen per UTC-dag aan toe.
- Doel: de sleutel geheim houden en de maximale impact van bugs of misbruik technisch begrenzen.
Stap 2.3 — Proxy veilig activeren
- De proxy accepteert alleen twee vaste handelingen: wijnetiket herkennen of wijn op naam zoeken. Model, prompts en JSON-output staan server-side vast; vrije prompts, onbekende velden, ongeldige talen en te grote afbeeldingen worden geweigerd.
- Volgorde: serversecret plaatsen → proxy deployen en live testen → interne appbuild maken → oude
EXPO_PUBLIC_GEMINI_API_KEYpas verwijderen wanneer die build bewezen werkt. - Voor brede publieke schaal blijft sterke app-attestatie (Apple App Attest / Google Play Integrity) de volgende hardening. IP- en daglimieten plus de Google-spendcap beschermen de beperkte bètafase.
3. Sentry DSN en Auth Token
- De
EXPO_PUBLIC_SENTRY_DSNis gewoonlijk een client-DSN en is bedoeld om publiek te zijn — je hoeft die dus niet te verbergen. - De Sentry Auth Token is wél een secret: roteer hem vóór publieke release, bewaar hem uitsluitend in
.env.localof EAS Secrets en verwijder oude tokens. Hij mag nooit ineas.json, git of een buildlog staan. - Status (2026-09-03): rotatie is afgerond. De token die in de git-historie stond (
eas.json,sntrys_…hXQ0) is ingetrokken in Sentry en vervangen door een nieuwe token in.env.local(uitgegeven 2026-09-03, orgnone-zzo). De Auth Token blijft een build-only secret en komt nooit in de app-bundel of git terecht. - De lokale pre-buildscan (
npm run security:secrets) blokkeert herkenbare credentials in tracked bestanden en draait voortaan ook automatisch in CI (per push/PR). - Sentry verwijdert gevoelige queryparameters, Bearer-tokens, cookies en URL-fragmenten voordat telemetry vertrekt; zo kan een Private Share-decryptiesleutel niet via navigatiedata lekken.
4. Private Share API (share.gustra.net)
Private Share gebruikt geen accountlogin voor een ontvanger. Dat is bewust: de versleutelde inhoud kan alleen worden geopend met de sleutel in het URL-fragment, die nooit naar de server wordt gestuurd.
Wat nu al live beschermd is
- Client-side AES-256-GCM-encryptie; payloads en sidecars staan buiten de webroot.
- 128-bit willekeurige share-ID's en revoke-tokens; revoke-token wordt server-side alleen als hash bewaard.
- 20 MB maximum, automatisch verval na 7 dagen, dagelijkse cleanup en veilige tombstones voor ingetrokken links.
- Per-IP rate limits: create 10 per 10 minuten, get 120 per minuut en revoke 30 per minuut; daarnaast CSP,
no-store,no-referreren geen open CORS.
Resterende serveracties vóór brede publieke uitrol
- Verifieer bij de host dat PHP het echte bezoeker-IP ziet; pas daarna zijn per-IP-limieten betrouwbaar achter eventuele proxies.
- Voeg een harde totale opslaggrens en een bytes-per-IP-per-tijdvenster toe. De huidige 20 MB-limiet per upload voorkomt geen langdurige disk-fill-aanval.
- Zet een WAF/CDN-laag voor
share.gustra.neten configureer privacyveilige alerts voor 429, 5xx en lage schijfruimte. Log nooit URL-fragmenten, decryptiesleutels of memory-inhoud.
Klaar? Verifieer het resultaat
Herstart de app zodra je restricties en quota hebt ingesteld. Test dat je de kaart nog altijd ziet en zoeken nog werkt. Als iets springt, betekent dat meestal dat de restrictie te strikt is (bijv. vergeten SHA-1 of referrer).
- Kaart opent, zoeken werkt → goedgekeurd.
- Kaart blank / “development purposes only” → controleer RESTRICTIE + QUOTA, niet alleen de key zelf.