Translated ['', 'src/pentesting-ci-cd/supabase-security.md'] to tr

This commit is contained in:
Translator
2025-09-29 23:08:26 +00:00
parent a94e90cd14
commit ba8b46fd4f
+158 -50
View File
@@ -1,49 +1,48 @@
# Supabase Güvenliği
# Supabase Güvenlik
{{#include ../banners/hacktricks-training.md}}
## Temel Bilgiler
[**Ana sayfalarına**](https://supabase.com/) göre: Supabase, açık kaynaklı bir Firebase alternatifidir. Projenize bir Postgres veritabanı, Kimlik Doğrulama, anlık API'ler, Edge Fonksiyonları, Gerçek Zamanlı abonelikler, Depolama ve Vektör gömme ile başlayın.
As per their [**landing page**](https://supabase.com/): 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ı
### Alt alan adı
Temelde bir proje oluşturulduğunda, kullanıcı **`jnanozjdybtpqgcwhdiz.supabase.co`** gibi bir supabase.co alt alan adı alacaktır.
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 `https://supabase.com/dashboard/project/<project-id>/settings/database` gibi bir bağlantıdan erişilebilir.**
> **Bu verilere şu tarz bir linkten erişilebilir: `https://supabase.com/dashboard/project/<project-id>/settings/database`**
Bu **veritabanı**, bazı AWS bölgelerinde dağıtılacak ve ona bağlanmak için şu şekilde bağlanmak mümkün olacaktır: `postgres://postgres.jnanozjdybtpqgcwhdiz:[YOUR-PASSWORD]@aws-0-us-west-1.pooler.supabase.com:5432/postgres` (bu us-west-1'de oluşturuldu).\
Şifre, kullanıcının daha önce koyduğu bir **şifredir**.
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 **parola**dır.
Bu nedenle, alt alan adı bilinen bir alan adı olduğundan ve kullanıcı adı olarak kullanıldığından ve AWS bölgeleri sınırlı olduğundan, **şifreyi brute force denemek** mümkün olabilir.
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 şunları içermektedir:
Bu bölüm ayrıca şu seçenekleri içerir:
- Veritabanı şifresini sıfırlama
- Bağlantı havuzlamasını yapılandırma
- SSL yapılandırma: Düz metin bağlantılarını reddetme (varsayılan olarak etkin)
- 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
- Ağ kısıtlamaları ve yasakları uygulama
## API Yapılandırması
> [!TIP]
> **Bu verilere `https://supabase.com/dashboard/project/<project-id>/settings/api` gibi bir bağlantıdan erişilebilir.**
> **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 şöyle olacak: `https://jnanozjdybtpqgcwhdiz.supabase.co`.
Projenizdeki supabase API'sine erişim URL'si şu şekilde olacaktır: `https://jnanozjdybtpqgcwhdiz.supabase.co`.
### anon api anahtarları
### anon api keys
Ayrıca bir **anon API anahtarı** (`role: "anon"`) oluşturacaktır, örneğin: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTQ5OTI3MTksImV4cCI6MjAzMDU2ODcxOX0.sRN0iMGM5J741pXav7UxeChyqBE9_Z-T0tLA9Zehvqk` uygulamanın API anahtarını kullanabilmesi için gereklidir.
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.
Bu API ile iletişim kurmak için API REST'ini [**belgelerde**](https://supabase.com/docs/reference/self-hosting-auth/returns-the-configuration-settings-for-the-gotrue-server) bulmak mümkündür, ancak en ilginç uç noktalar şunlar olacaktır:
It's possible to find the API REST to contact this API in the [**docs**](https://supabase.com/docs/reference/self-hosting-auth/returns-the-configuration-settings-for-the-gotrue-server), but the most interesting endpoints would be:
<details>
<summary>Kaydol (/auth/v1/signup)</summary>
<summary>Kayıt (/auth/v1/signup)</summary>
```
POST /auth/v1/signup HTTP/2
Host: id.io.net
@@ -99,61 +98,170 @@ Priority: u=1, i
```
</details>
Bu nedenle, bir müşterinin kendilerine verilen alt alan adıyla supabase kullandığını keşfettiğinizde (şirketin bir alt alan adının supabase alt alan adlarına CNAME yönlendirmesi yapması mümkündür), **supabase API'sini kullanarak platformda yeni bir hesap oluşturmayı** deneyebilirsiniz.
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.
### gizli / hizmet_rolü api anahtarları
### secret / service_role api keys
**`role: "service_role"`** ile bir gizli API anahtarı da oluşturulacaktır. Bu API anahtarı gizli olmalıdır çünkü **Satır Seviyesi Güvenliği**'ni atlayabilecektir.
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ı şu şekilde görünür: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTcxNDk5MjcxOSwiZXhwIjoyMDMwNTY4NzE5fQ.0a8fHGp3N_GiPq0y0dwfs06ywd-zhTwsm486Tha7354`
API anahtarı şöyle görünür: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImpuYW5vemRyb2J0cHFnY3doZGl6Iiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTcxNDk5MjcxOSwiZXhwIjoyMDMwNTY4NzE5fQ.0a8fHGp3N_GiPq0y0dwfs06ywd-zhTwsm486Tha7354`
### JWT Gizli Anahtarı
### JWT Secret
Uygulamanın **özel JWT jetonları oluşturup imzalayabilmesi** için bir **JWT Gizli Anahtarı** da oluşturulacaktır.
Bir **JWT Secret** de oluşturulacak, böylece uygulama **özel JWT tokenları oluşturup imzalayabilir**.
## Kimlik Doğrulama
## Authentication
### Kayıtlar
### Signups
> [!TIP]
> **Varsayılan olarak** supabase, daha önce bahsedilen API uç noktalarını kullanarak projenizde **yeni kullanıcıların hesap oluşturmasına** izin verecektir.
> Varsayılan olarak supabase, önce bahsedilen API uç noktalarını kullanarak projenizde yeni kullanıcıların hesap oluşturmasına izin verir.
Ancak, bu yeni hesaplar varsayılan olarak, **giriş yapabilmek için e-posta adreslerini doğrulamaları** gerekecektir. İnsanların e-posta adreslerini doğrulamadan giriş yapabilmesi için **"Anonim girişlere izin ver"** seçeneğini etkinleştirmek mümkündür. Bu, **beklenmedik verilere** erişim sağlayabilir (kullanıcılar `public` ve `authenticated` rollerini alır).\
Bu çok kötü bir fikirdir çünkü supabase, aktif kullanıcı başına ücret alır, bu nedenle insanlar kullanıcı oluşturup giriş yapabilir ve supabase bu kullanıcılar için ücret alır:
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>
### Şifreler ve oturumlar
#### Auth: Server-side signup enforcement
Minimum şifre uzunluğunu belirtmek mümkündür (varsayılan olarak), gereksinimleri (varsayılan olarak yok) ve sızdırılmış şifrelerin kullanılmasını engellemek mümkündür.\
**Varsayılan gereksinimler zayıf olduğu için gereksinimleri geliştirmek** önerilir.
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.
- Kullanıcı Oturumları: Kullanıcı oturumlarının nasıl çalıştığını yapılandırmak mümkündür (zaman aşımı, kullanıcı başına 1 oturum...)
- Bot ve Kötüye Kullanım Koruması: Captcha etkinleştirmek mümkündür.
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.
### SMTP Ayarları
## RLS and Views: Write bypass via PostgREST
E-posta göndermek için bir SMTP ayarlamak mümkündür.
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.
### Gelişmiş Ayarlar
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.
- Erişim jetonları için sonlanma süresi ayarlayın (varsayılan 3600)
- Potansiyel olarak tehlikeye atılmış yenileme jetonlarını tespit etmek ve iptal etmek için ayarlayın
- MFA: Kullanıcı başına bir kerede kaç MFA faktörünün kaydedilebileceğini belirtin (varsayılan 10)
- Maksimum Doğrudan Veritabanı Bağlantıları: Kimlik doğrulama için kullanılan maksimum bağlantı sayısı (varsayılan 10)
- Maksimum İstek Süresi: Bir Kimlik Doğrulama isteğinin sürebileceği maksimum süre (varsayılan 10s)
Illustrative write via view (attempted from a public client):
```bash
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.
## Depolama
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):
```bash
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):
```bash
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):
```bash
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:
```bash
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ş:
```bash
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, **dosyaları depolamaya** ve bunları bir URL üzerinden erişilebilir hale getirmeye izin verir (S3 bucket'ları kullanır).
> Supabase allows **to store files** and make them accesible over a URL (it uses S3 buckets).
- Yükleme dosyası boyutu sınırını ayarlayın (varsayılan 50MB)
- S3 bağlantısı şu şekilde bir URL ile verilir: `https://jnanozjdybtpqgcwhdiz.supabase.co/storage/v1/s3`
- `access key ID` (örneğin, `a37d96544d82ba90057e0e06131d0a7b`) ve `secret access key` (örneğin, `58420818223133077c2cec6712a4f909aec93b4daeedae205aa8e30d5a860628`) ile oluşturulan **S3 erişim anahtarı** talep etmek mümkündür.
- 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 Fonksiyonları
## Edge Functions
Supabase'te **gizli anahtarları** depolamak da mümkündür ve bunlar **edge fonksiyonları tarafından erişilebilir** (web üzerinden oluşturulup silinebilir, ancak değerlerine doğrudan erişmek mümkün değildir).
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
- [Building Hacker Communities: Bug Bounty Village, getDiscloseds Supabase Misconfig, and the LHE Squad (Ep. 133) YouTube](https://youtu.be/NI-eXMlXma4)
- [Critical Thinking Podcast Episode 133 page](https://www.criticalthinkingpodcast.io/episode-133-building-hacker-communities-bug-bounty-village-getdisclosed-and-the-lhe-squad/)
- [Supabase: Row Level Security (RLS)](https://supabase.com/docs/guides/auth/row-level-security)
- [PostgreSQL: Row Security Policies](https://www.postgresql.org/docs/current/ddl-rowsecurity.html)
- [PostgreSQL: CREATE VIEW (security_invoker, check option)](https://www.postgresql.org/docs/current/sql-createview.html)
- [PostgREST: OpenAPI documentation](https://postgrest.org/en/stable/references/api.html#openapi-documentation)
{{#include ../banners/hacktricks-training.md}}