Authorisation og tilgangskontroll
IDOR/BOLA, horisontal og vertikal eskalering. Den vanligste kritiske feilen i genererte apper.
To retninger
- ›Horisontal: bruker A får tilgang til bruker Bs data (samme rolle).
- ›Vertikal: vanlig bruker får tilgang til admin-funksjoner.
- ›IDOR / BOLA: objektet identifiseres av en ID i requesten og serveren sjekker ikke eierskap.
/api/projects/123 → 124
Hvis serveren slår opp prosjektet kun på ID, får du det. Sekvensielle ID-er gjør det trivielt, men UUID-er er ikke en kontroll — de lekker i URL-er, logger og delte lenker.
// GET /api/projects/:id
const { data } = await supabaseAdmin
.from("projects")
.select("*")
.eq("id", params.id)
.single();
return Response.json(data);// Bruk brukerens egen klient: RLS gjelder
const { data, error } = await context.supabase
.from("projects")
.select("id, name, created_at")
.eq("id", params.id)
.maybeSingle();
if (!data) return new Response("Not found", { status: 404 });
return Response.json(data);
-- og i databasen:
create policy "owner reads" on projects for select
to authenticated using (owner_id = auth.uid());Returner 404 (ikke 403) for andres objekter så du ikke bekrefter at de finnes.
Testmetode: to brukere, to nettlesere
Opprett User A og User B i to separate browser-profiler. Lag data som A. Ta request fra As Network-fane og spill den av med Bs token.
for id in 101 102 103; do
curl -s -o /dev/null -w "$id -> %{http_code}\n" \
-H "Authorization: Bearer $TOKEN_B" https://localhost:8080/api/projects/$id
done
# Forventet: bare Bs egne prosjekter gir 200Glem ikke skriveoperasjoner
Mange apper sjekker SELECT men ikke UPDATE/DELETE. Test PATCH med andres ID, og test om du kan endre owner_id eller role i request body (mass assignment).
Quiz
Endpointet PATCH /api/profile tar { name, email, role } og gjør update(body).eq('id', userId). Hva er problemet?
Prosjekter bruker UUID som ID. Trenger du eierskapssjekk?