Supabase Security

Tip

Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Leer & oefen Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks

Basiese Inligting

Volgens hul landing page: Supabase is ’n open source Firebase-alternatief. Begin jou projek met ’n Postgres database, Authentication, instant APIs, Edge Functions, Realtime subscriptions, Storage, en Vector embeddings.

Subdomein

Basies, wanneer ’n projek geskep word, sal die gebruiker ’n supabase.co subdomein ontvang soos: jnanozjdybtpqgcwhdiz.supabase.co

Database configuration

Tip

Hierdie data kan bereik word vanaf ’n skakel soos https://supabase.com/dashboard/project/<project-id>/settings/database

Hierdie database sal in ’n AWS-streek ontplooi word, en om daaraan te koppel is dit moontlik om te koppel via: postgres://postgres.jnanozjdybtpqgcwhdiz:[YOUR-PASSWORD]@aws-0-us-west-1.pooler.supabase.com:5432/postgres (dit is geskep in us-west-1).
Die wagwoord is ’n wagwoord wat die gebruiker tevore ingestel het.

Aangesien die subdomein bekend is en dit as username gebruik word en die AWS-streke beperk is, kan dit moontlik wees om te probeer om die wagwoord te brute force.

Hierdie afdeling bevat ook opsies om:

  • Reset the database password
  • Configure connection pooling
  • Configure SSL: Reject plan-text connections (by default they are enabled)
  • Configure Disk size
  • Apply network restrictions and bans

API Configuration

Tip

Hierdie data kan bereik word vanaf ’n skakel soos https://supabase.com/dashboard/project/<project-id>/settings/api

Die URL om die supabase API in jou projek te bereik sal so lyk: https://jnanozjdybtpqgcwhdiz.supabase.co.

anon api keys

Dit sal ook ’n anon API key (role: "anon"), genereer, soos: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTQ5OTI3MTksImV4cCI6MjAzMDU2ODcxOX0.sRN0iMGM5J741pXav7UxeChyqBE9_Z-T0tLA9Zehvqk wat die toepassing sal moet gebruik om met die API te kommunikeer wat in ons voorbeeld blootgestel is in

Dit is moontlik om die API REST wat hierdie API kontak in die docs te vind, maar die mees interessante endpoints sou wees:

Signup (/auth/v1/signup) ``` POST /auth/v1/signup HTTP/2 Host: id.io.net Content-Length: 90 X-Client-Info: supabase-js-web/2.39.2 Sec-Ch-Ua: "Not-A.Brand";v="99", "Chromium";v="124" Sec-Ch-Ua-Mobile: ?0 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTQ5OTI3MTksImV4cCI6MjAzMDU2ODcxOX0.sRN0iMGM5J741pXav7UxeChyqBE9_Z-T0tLA9Zehvqk User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.60 Safari/537.36 Content-Type: application/json;charset=UTF-8 Apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTQ5OTI3MTksImV4cCI6MjAzMDU2ODcxOX0.sRN0iMGM5J741pXav7UxeChyqBE9_Z-T0tLA9Zehvqk Sec-Ch-Ua-Platform: "macOS" Accept: */* Origin: https://cloud.io.net Sec-Fetch-Site: same-site Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: https://cloud.io.net/ Accept-Encoding: gzip, deflate, br Accept-Language: en-GB,en-US;q=0.9,en;q=0.8 Priority: u=1, i

{“email”:“test@exmaple.com”,“password”:“SomeCOmplexPwd239.”}

</details>

<details>

<summary>Aanmelding (/auth/v1/token?grant_type=password)</summary>

POST /auth/v1/token?grant_type=password HTTP/2 Host: hypzbtgspjkludjcnjxl.supabase.co Content-Length: 80 X-Client-Info: supabase-js-web/2.39.2 Sec-Ch-Ua: “Not-A.Brand”;v=“99”, “Chromium”;v=“124” Sec-Ch-Ua-Mobile: ?0 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTQ5OTI3MTksImV4cCI6MjAzMDU2ODcxOX0.sRN0iMGM5J741pXav7UxeChyqBE9_Z-T0tLA9Zehvqk User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.60 Safari/537.36 Content-Type: application/json;charset=UTF-8 Apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTQ5OTI3MTksImV4cCI6MjAzMDU2ODcxOX0.sRN0iMGM5J741pXav7UxeChyqBE9_Z-T0tLA9Zehvqk Sec-Ch-Ua-Platform: “macOS” Accept: / Origin: https://cloud.io.net Sec-Fetch-Site: same-site Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: https://cloud.io.net/ Accept-Encoding: gzip, deflate, br Accept-Language: en-GB,en-US;q=0.9,en;q=0.8 Priority: u=1, i

{“email”:“test@exmaple.com”,“password”:“SomeCOmplexPwd239.”}

</details>

So, wanneer jy 'n klient ontdek wat supabase gebruik met die subdomein wat hulle toegewys is (dit is moontlik dat 'n subdomein van die maatskappy 'n CNAME oor hul supabase-subdomein het), kan jy probeer om **'n nuwe rekening op die platform te skep deur die supabase API te gebruik**.

### secret / service_role api keys

A secret API key will also be generated with **`role: "service_role"`**. Hierdie API-sleutel moet geheim gehou word omdat dit **Row Level Security** kan omseil.

Die API sleutel lyk soos dit: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTcxNDk5MjcxOSwiZXhwIjoyMDMwNTY4NzE5fQ.0a8fHGp3N_GiPq0y0dwfs06ywd-zhTwsm486Tha7354`

### JWT Secret

A **JWT Secret** sal ook gegenereer word sodat die toepassing **custom JWT tokens kan skep en teken**.

## Outentisering

### Aanmeldings

> [!TIP]
> Standaard sal supabase toelaat dat **nuwe gebruikers rekeninge kan skep** op jou projek deur die vroeër genoemde API-endpoints te gebruik.

Egter, hierdie nuwe rekeninge, standaard, **sal hul e-posadres moet bevestig** om in die rekening aan te meld. Dit is moontlik om **"Allow anonymous sign-ins"** te aktiveer om mense toe te laat om aan te meld sonder om hul e-pos te verifieer. Dit kan toegang gee tot **onverwagte data** (hulle kry die rolle `public` en `authenticated`).\
Dit is 'n baie slegte idee omdat supabase per aktiewe gebruiker hef, dus kan mense gebruikers skep en aanmeld en supabase sal daarvoor hef:

<figure><img src="../images/image (1) (1) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>

#### Auth: Server-side signup enforcement

Om die signup-knoppie in die frontend te verberg is nie genoeg nie. As die **Auth server steeds signups toelaat**, kan 'n aanvaller die API direk met die publieke `anon` key aanroep en willekeurige gebruikers skep.

Quick test (from an unauthenticated client):
```bash
curl -X POST \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
-H "Content-Type: application/json" \
-d '{"email":"attacker@example.com","password":"Sup3rStr0ng!"}' \
https://<PROJECT_REF>.supabase.co/auth/v1/signup

Expected hardening:

  • Skakel e-pos/wagwoord-registrasies in die Dashboard uit: Authentication → Providers → Email → Disable sign ups (invite-only), of stel die ekwivalente GoTrue-instelling.
  • Verifieer dat die API nou 4xx teruggee vir die vorige oproep en dat geen nuwe gebruiker geskep word nie.
  • As jy op invites of SSO staatmaak, maak seker dat alle ander providers gedeaktiveer is tensy dit uitdruklik nodig is.

RLS en Views: Skryf-omseiling via PostgREST

Die gebruik van ’n Postgres VIEW om “sensitiewe” kolomme te “versteek” en dit via PostgREST bloot te stel kan verander hoe voorregte geĂ«valueer word. In PostgreSQL:

  • Gewone views voer standaard uit met die voorregte van die view-eienaar (definer semantics). In PG ≄15 kan jy kies om security_invoker te gebruik.
  • Row Level Security (RLS) geld op basistabelle. Tabel-eienaars omseil RLS tensy FORCE ROW LEVEL SECURITY op die tabel gestel is.
  • Opdateerbare views kan INSERT/UPDATE/DELETE aanvaar wat dan op die basistabel toegepas word. Sonder WITH CHECK OPTION kan skryf-operasies wat nie by die view-predikaat pas steeds slaag.

Risikopatroon wat in die praktyk waargeneem is:

  • ’n Verminderde-kolom view word deur Supabase REST blootgestel en aan anon/authenticated toegestaan.
  • PostgREST laat DML toe op die opdateerbare view en die operasie word ge-evalueer met die view-eienaar se voorregte, wat effektief die beoogde RLS-beleid op die basistabel omseil.
  • Resultaat: kliĂ«nte met lae voorregte kan massaal rye wysig (bv. profiel-bios/avatars) wat hulle nie mag wysig nie.

Illustratiewe write via view (attempted from a public client):

curl -X PATCH \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
-H "Content-Type: application/json" \
-H "Prefer: return=representation" \
-d '{"bio":"pwned","avatar_url":"https://i.example/pwn.png"}' \
"https://<PROJECT_REF>.supabase.co/rest/v1/users_view?id=eq.<victim_user_id>"

Hardening checklist for views and RLS:

  • Voorkeur om base tables bloot te stel met eksplisiete, least-privilege grants en presiese RLS-beleid.
  • If you must expose a view:
  • Maak dit nie-opdateerbaar nie (bv. include expressions/joins) of weier INSERT/UPDATE/DELETE op die view aan alle onbetroubare rolle.
  • Enforce ALTER VIEW <v> SET (security_invoker = on) sodat die invoker se voorregte gebruik word in plaas van die eienaar se.
  • On base tables, use ALTER TABLE <t> FORCE ROW LEVEL SECURITY; sodat selfs eienaars aan RLS onderwerp is.
  • If allowing writes via an updatable view, add WITH [LOCAL|CASCADED] CHECK OPTION en aanvullende RLS op base tables om te verseker dat slegs toegelate rye geskryf/gewyzig kan word.
  • In Supabase, vermy om anon/authenticated enige write privileges op views te gee tensy jy end-to-end gedrag met toetse geverifieer het.

Detection tip:

  • From anon and an authenticated test user, probeer alle CRUD-operations teen elke blootgestelde table/view. Enige suksesvolle write waar jy weiering verwag het, dui op misconfiguration.

OpenAPI-driven CRUD probing from anon/auth roles

PostgREST exposes an OpenAPI document that you can use to enumerate all REST resources, then automatically probe allowed operations from low-privileged roles.

Fetch the OpenAPI (works with the public anon key):

curl -s https://<PROJECT_REF>.supabase.co/rest/v1/ \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
-H "Accept: application/openapi+json" | jq '.paths | keys[]'

Sondepatroon (voorbeelde):

  • Lees ’n enkele ry (verwag 401/403/200 afhangende van RLS):
curl -s "https://<PROJECT_REF>.supabase.co/rest/v1/<table>?select=*&limit=1" \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>"
  • Toets dat UPDATE geblokkeer is (gebruik ’n nie-bestaande filter om te voorkom dat data tydens toetsing verander word):
curl -i -X PATCH \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
-H "Content-Type: application/json" \
-H "Prefer: return=minimal" \
-d '{"__probe":true}' \
"https://<PROJECT_REF>.supabase.co/rest/v1/<table_or_view>?id=eq.00000000-0000-0000-0000-000000000000"
  • Toets INSERT is geblokkeer:
curl -i -X POST \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
-H "Content-Type: application/json" \
-H "Prefer: return=minimal" \
-d '{"__probe":true}' \
"https://<PROJECT_REF>.supabase.co/rest/v1/<table_or_view>"
  • Toets DELETE is geblokkeer:
curl -i -X DELETE \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>" \
"https://<PROJECT_REF>.supabase.co/rest/v1/<table_or_view>?id=eq.00000000-0000-0000-0000-000000000000"

Aanbevelings:

  • Outomatiseer die vorige probes vir beide anon en ’n minimaal authenticated gebruiker en integreer dit in CI om regressies op te spoor.
  • Behandel elke blootgestelde table/view/function as ‘first-class surface’. Moet nie aanvaar dat ’n view “inherits” dieselfde RLS-houding as sy basis-tabelle nie.

Wagwoorde & sessies

Dit is moontlik om die minimum wagwoordlengte aan te dui (per verstek), vereistes (nie per verstek nie) en te verhoed om leaked passwords te gebruik.
Dit word aanbeveel om die vereistes te verbeter aangesien die verstekvereistes swak is.

  • Gebruikersessies: Dit is moontlik om te konfigureer hoe gebruikersessies werk (timeouts, 1 sessie per gebruiker
)
  • Bot- en misbruikbeskerming: Dit is moontlik om Captcha te aktiveer.

SMTP-instellings

Dit is moontlik om ’n SMTP in te stel om e-posse te stuur.

Gevorderde instellings

  • Stel vervaltyd vir toegangstokens (3600 per verstek)
  • Skakel opsporing en herroeping van moontlik gekompromiteerde refresh tokens en time-outs in
  • MFA: Gee aan hoeveel MFA-faktore gelyktydig per gebruiker geregistreer kan word (10 per verstek)
  • Max Direct Database Connections: Maksimum aantal konneksies wat vir auth gebruik word (10 per verstek)
  • Max Request Duration: Maksimum tyd toegelaat vir ’n Auth-aanvraag om te duur (10s per verstek)

Stoor

Tip

Supabase laat toe om lĂȘers te stoor en dit via ’n URL toeganklik te maak (dit gebruik S3 buckets).

  • Stel die oplaai-lĂȘergrootte limiet (verstek is 50MB)
  • Die S3-verbinding word gegee met ’n URL soos: https://jnanozjdybtpqgcwhdiz.supabase.co/storage/v1/s3
  • Dit is moontlik om S3 access key aan te vra wat gevorm word deur ’n access key ID (bv. a37d96544d82ba90057e0e06131d0a7b) en ’n secret access key (bv. 58420818223133077c2cec6712a4f909aec93b4daeedae205aa8e30d5a860628)

Edge Functions

Dit is ook moontlik om geheime (secrets) te stoor in supabase wat deur edge functions toeganklik sal wees (hulle kan vanaf die web geskep en verwyder word, maar dit is nie moontlik om hul waarde direk te verkry nie).

References

Tip

Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Leer & oefen Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks