Security Academy→Course→Secrets og API keys
Modul 6 / 12

Secrets og API keys

Alt som når browseren er offentlig. Lær å finne lekkasjer i bundles og storage.

Typer nøkler

  • ›Public/publishable keys (Supabase anon, Stripe pk_): laget for browseren. Sikkerhet kommer fra RLS/server.
  • ›Secret keys (sk_, service_role, OpenAI): kun server. Lekkasje = full tilgang.
  • ›Environment variables: VITE_* bygges inn i JS-bundlen. process.env leses kun på server.
  • ›Database credentials / connection strings: aldri i klient, aldri i repo.
  • ›Service-role credentials: bypasser alt — behandles som root-passord.

Hvorfor sendt = eksponert

Browseren må kunne lese verdien for å bruke den, og det kan brukeren også. Minifisering, base64 eller å «skjule» i en variabel endrer ingenting.

Er en secret noen gang sendt til klienten: roter den. Fjerning fra koden hjelper ikke — den ligger i gamle bundles og git-historikk.

Vulnerable · ts
// Klientkomponent
const openai = new OpenAI({
  apiKey: import.meta.env.VITE_OPENAI_KEY,
  dangerouslyAllowBrowser: true,
});
Secure · ts
// server function
export const ask = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .inputValidator(z.object({ q: z.string().max(2000) }))
  .handler(async ({ data }) => {
    const key = process.env.OPENAI_KEY; // kun server
    ...
  });

Slik leter du i browseren

  • ›Sources: Ctrl+Shift+F søk i alle filer etter sk_, service_role, secret, eyJ, apiKey, password
  • ›Network: se på headers — sendes en secret som Authorization til et tredjeparts-API direkte fra browser?
  • ›JS bundles: last ned og grep (under)
  • ›Local Storage / Session Storage: tokens er forventet, API-nøkler og roller er det ikke
# Lokalt etter build
grep -rEo "(sk_(live|test)_[A-Za-z0-9]+|service_role|eyJ[A-Za-z0-9_-]{20,})" dist/ | sort -u

# Decode en eyJ-token og sjekk "role"
echo "<payload-del>" | base64 -d   # role: "service_role" = kritisk
Kontroller i din egen app
Labs for denne modulen

Quiz

Scenario 1

Du finner en JWT i bundlen. Payload inneholder "role":"anon". Er det kritisk?

Scenario 2

Payload inneholder "role":"service_role". Hva gjør du?