Supabase Güvenlik

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Temel Bilgiler

As per their landing page: Supabase is an open source Firebase alternative. Start your project with a Postgres database, Authentication, instant APIs, Edge Functions, Realtime subscriptions, Storage, and Vector embeddings.

Alt alan adı

Genel olarak bir proje oluşturulduğunda kullanıcı şu formatta bir supabase.co alt alan adı alır: jnanozjdybtpqgcwhdiz.supabase.co

Veritabanı yapılandırması

Tip

Bu verilere şu tarz bir linkten erişilebilir: https://supabase.com/dashboard/project/<project-id>/settings/database

Bu veritabanı belirli bir AWS bölgesinde dağıtılacaktır ve bağlanmak için şu bağlantı kullanılabilir: postgres://postgres.jnanozjdybtpqgcwhdiz:[YOUR-PASSWORD]@aws-0-us-west-1.pooler.supabase.com:5432/postgres (bu örnek us-west-1’de oluşturuldu). Parola, kullanıcının önceden belirlediği paroladır.

Bu nedenle, alt alan adı biliniyor, kullanıcı adı olarak kullanılıyor ve AWS bölgeleri sınırlı olduğundan, brute force the password denenebilir.

Bu bölüm ayrıca şu seçenekleri içerir:

  • Veritabanı parolasını sıfırlama
  • Connection pooling’i yapılandırma
  • SSL’i yapılandırma: plan-text bağlantılarını reddet (varsayılan olarak etkinler)
  • Disk boyutunu yapılandırma
  • Ağ kısıtlamaları ve yasakları uygulama

API Yapılandırması

Tip

Bu verilere şu tarz bir linkten erişilebilir: https://supabase.com/dashboard/project/<project-id>/settings/api

Projenizdeki supabase API’sine erişim URL’si şu şekilde olacaktır: https://jnanozjdybtpqgcwhdiz.supabase.co.

anon api keys

Ayrıca role: "anon" olan bir anon API key üretilir, örneğin: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTQ5OTI3MTksImV4cCI6MjAzMDU2ODcxOX0.sRN0iMGM5J741pXav7UxeChyqBE9_Z-T0tLA9Zehvqk — uygulamanın API ile iletişim kurmak için kullanması gerekir.

It’s possible to find the API REST to contact this API in the docs, but the most interesting endpoints would be:

Kayıt (/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>Giriş (/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>

Yani, bir müşterinin kendisine verilen alt alan adını kullanan bir supabase istemcisi keşfettiğinizde (şirketin bir alt alanının supabase alt alanlarına CNAME koymuş olması mümkün), **supabase API**'yi kullanarak platformda yeni bir hesap oluşturmayı deneyebilirsiniz.

### secret / service_role api keys

Bir gizli API anahtarı ayrıca **`role: "service_role"`** ile oluşturulacaktır. Bu API anahtarı gizli olmalıdır çünkü **Row Level Security**'yi atlayabilecektir.

API anahtarı şöyle görünür: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTcxNDk5MjcxOSwiZXhwIjoyMDMwNTY4NzE5fQ.0a8fHGp3N_GiPq0y0dwfs06ywd-zhTwsm486Tha7354`

### JWT Secret

Bir **JWT Secret** de oluşturulacak, böylece uygulama **özel JWT tokenları oluşturup imzalayabilir**.

## Authentication

### Signups

> [!TIP]
> Varsayılan olarak supabase, önce bahsedilen API uç noktalarını kullanarak projenizde yeni kullanıcıların hesap oluşturmasına izin verir.

Bununla birlikte, bu yeni hesaplar varsayılan olarak **oturum açabilmek için e-posta adreslerini doğrulamak zorunda olacaklardır**. İnsanların e-posta adreslerini doğrulamadan giriş yapmalarına izin vermek için **"Allow anonymous sign-ins"** etkinleştirmek mümkündür. Bu, **beklenmeyen verilere** erişim sağlayabilir (altyapı kullanıcıları `public` ve `authenticated` rollerini alır).\ Bu çok kötü bir fikirdir çünkü supabase aktif kullanıcı başına ücretlendirir; insanlar kullanıcı oluşturup giriş yaparsa supabase bunlar için ücret alacaktır:

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

#### Auth: Server-side signup enforcement

Frontend'de kayıt butonunu gizlemek yeterli değildir. Eğer **Auth server hala kayıtlara izin veriyorsa**, bir saldırgan public `anon` anahtarıyla doğrudan API'yi çağırıp rastgele kullanıcılar oluşturabilir.

Hızlı test (kimliği doğrulanmamış bir istemciden):
```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:

  • Dashboard’ta email/password kayıtlarını devre dışı bırakın: Authentication → Providers → Email → Disable sign ups (invite-only), veya eşdeğer GoTrue ayarını yapın.
  • API’nin önceki çağrıya artık 4xx döndürdüğünü ve yeni bir kullanıcı oluşturulmadığını doğrulayın.
  • Eğer davetler veya SSO’ya güveniyorsanız, açıkça gerekmedikçe diğer tüm providers’ın devre dışı olduğundan emin olun.

RLS and Views: Write bypass via PostgREST

Duyarlı sütunları “gizlemek” için bir Postgres VIEW kullanmak ve bunu PostgREST üzerinden açığa çıkarmak, ayrıcalıkların nasıl değerlendirildiğini değiştirebilir. In PostgreSQL:

  • Ordinary views varsayılan olarak view sahibinin ayrıcalıklarıyla çalışır (definer semantics). PG ≥15’te security_invoker’a geçiş yapabilirsiniz.
  • Row Level Security (RLS) temel tablolarda uygulanır. Tablo sahipleri, tabloya FORCE ROW LEVEL SECURITY ayarı yapılmadıkça RLS’yi atlar.
  • Updatable views INSERT/UPDATE/DELETE kabul edebilir ve bunlar daha sonra base tabloya uygulanır. WITH CHECK OPTION yoksa, view predicate’ine uymayan yazma işlemleri yine de başarılı olabilir.

Risk pattern observed in the wild:

  • Azaltılmış sütunlu bir view Supabase REST üzerinden açığa çıkarılır ve anon/authenticated’a yetki verilir.
  • PostgREST, updatable view üzerinde DML’e izin verir ve işlem view sahibinin ayrıcalıklarıyla değerlendirilir; bu da base tablodaki amaçlanan RLS politikalarını fiilen atlatır.
  • Sonuç: düşük ayrıcalıklı istemciler, değiştirmemeleri gereken satırları (ör. profile bios/avatars) topluca düzenleyebilir.

Illustrative 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:

  • Tabloları doğrudan, açıkça belirtilmiş asgari ayrıcalık izinleri ve hassas RLS politikalarıyla açığa çıkarmayı tercih edin.
  • Bir görünümü açığa çıkarmanız gerekiyorsa:
  • Güncellenemez yapın (ör. expressions/joins içerecek şekilde) veya tüm güvensiz rollere görünümde INSERT/UPDATE/DELETE’i reddedin.
  • ALTER VIEW <v> SET (security_invoker = on) uygulanmasını sağlayın; böylece invoker’ın ayrıcalıkları owner’ınkiler yerine kullanılır.
  • Temel tablolarda ALTER TABLE <t> FORCE ROW LEVEL SECURITY; kullanın; böylece sahipler bile RLS’e tabi olur.
  • Eğer updatable bir görünüm aracılığıyla yazılara izin veriyorsanız, WITH [LOCAL|CASCADED] CHECK OPTION ekleyin ve temel tablolarda tamamlayıcı RLS ile yalnızca izin verilen satırların yazılabileceğinden/değiştirilebileceğinden emin olun.
  • Supabase’de, end-to-end davranışı testlerle doğrulamamışsanız, view’lar üzerinde anon/authenticated rollerine herhangi bir yazma ayrıcalığı vermekten kaçının.

Detection tip:

  • anon ve bir authenticated test kullanıcısı ile her açığa çıkarılmış tablo/görünüm üzerinde tüm CRUD işlemlerini deneyin. Reddedilmesini beklediğiniz halde başarılı olan herhangi bir yazma, bir yanlış yapılandırmaya işaret eder.

OpenAPI-driven CRUD probing from anon/auth roles

PostgREST, tüm REST kaynaklarını numaralandırmak ve ardından düşük ayrıcalıklı rollerden izin verilen işlemleri otomatik olarak probe etmek için kullanabileceğiniz bir OpenAPI belgesi sunar.

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[]'

Probe deseni (örnekler):

  • Tek bir satırı oku (beklenen 401/403/200, RLS’e bağlı olarak):
curl -s "https://<PROJECT_REF>.supabase.co/rest/v1/<table>?select=*&limit=1" \
-H "apikey: <SUPABASE_ANON_KEY>" \
-H "Authorization: Bearer <SUPABASE_ANON_KEY>"
  • UPDATE testi engellenmiş (test sırasında verileri değiştirmemek için var olmayan bir filtre kullanın):
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"
  • Test INSERT engellendi:
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>"
  • Test DELETE engellenmiş:
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"

Öneriler:

  • Önceki taramaları hem anon hem de minimum düzeyde authenticated kullanıcı için otomatikleştir ve regresyonları yakalamak için CI’ye entegre et.
  • Her açık tablo/görünüm/fonksiyonu birinci sınıf bir yüzey olarak ele al. Bir görünümün “inherits” ile base tablolarıyla aynı RLS duruşunu varsayma.

Parolalar & oturumlar

It’s possible to indicate the minimum password length (by default), requirements (no by default) and disallow to use leaked passwords.
Varsayılan gereksinimler zayıf olduğu için gereksinimleri geliştirmeniz önerilir.

  • User Sessions: Kullanıcı oturumlarının nasıl çalışacağını yapılandırmak mümkün (zaman aşımı, kullanıcı başına 1 oturum…)
  • Bot and Abuse Protection: Captcha’yı etkinleştirmek mümkün.

SMTP Settings

E-posta göndermek için bir SMTP ayarlamak mümkün.

Advanced Settings

  • Set expire time to access tokens (3600 by default)
  • Potansiyel olarak ele geçirilmiş refresh token’ları tespit edip iptal etmek ve timeout ayarlamak mümkün
  • MFA: Bir kullanıcının aynı anda kaç MFA faktörü kaydedebileceğini belirt (varsayılan 10)
  • Max Direct Database Connections: Kimlik doğrulama için kullanılacak maksimum bağlantı sayısı (varsayılan 10)
  • Max Request Duration: Bir Auth isteğinin sürebileceği maksimum süre (varsayılan 10s)

Storage

Tip

Supabase allows to store files and make them accesible over a URL (it uses S3 buckets).

  • Yükleme dosya boyutu limitini ayarla (varsayılan 50MB)
  • The S3 connection is given with a URL like: https://jnanozjdybtpqgcwhdiz.supabase.co/storage/v1/s3
  • S3 access key talep etmek mümkün; bunlar bir access key ID (e.g. a37d96544d82ba90057e0e06131d0a7b) ve bir secret access key (e.g. 58420818223133077c2cec6712a4f909aec93b4daeedae205aa8e30d5a860628) şeklinde oluşur

Edge Functions

Supabase içinde gizli bilgileri saklamak de mümkün olup bunlar edge functions tarafından erişilebilir (web üzerinden oluşturulup silinebilirler, ancak değerlerine doğrudan erişim mümkün değildir).

References

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin