# Tehdit modeli

> QueryProxy'nin neyi kimden koruduğu, güven sınırlarının nerede olduğu ve hangi risklerin sizde kaldığı. Operatörler için yayımlanan ilk tehdit modeli.

- Dokümantasyon: Referans
- Güncelleme: 2026-10-25
- Kaynak: https://queryproxy.com/tr/docs/tehdit-modeli/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
Bu, QueryProxy tehdit modelinin ilk sürümüdür. Mevcut sürümün (v0.3.0) neye
dayanacak şekilde kurulduğunu ve aynı açıklıkla neye dayanmadığını anlatır.
Bir deployment'ı gözden geçirmek için kullanın; bir sertifikasyon değildir ve
kendi ortamınızın incelenmesinin yerini tutmaz.

QueryProxy, veriye ihtiyacı olan insanlarla o veriyi tutan veritabanları
arasında durur. Ürünün işi, bir kişinin üretim veritabanında çalıştırdığı her
ifadenin guard'lar tarafından görülmesini, başka biri tarafından onaylanmasını,
sınırlı yetkilerle çalıştırılmasını, çıkarken maskelenmesini ve yeniden
yazılması zor bir kayda yazılmasını sağlamaktır.

## Varlıklar

| Varlık | Nerede durur | Koruma | Geriye kalan |
| :-- | :-- | :-- | :-- |
| Hedef veritabanı kimlik bilgileri | Uygulama veritabanı, şifreli | `APP_KEY` ile AES-256; kaydedildikten sonra bir daha gösterilmez; saklanan hata mesajlarında, denetim metadata'sında, bildirimlerde ve arayüzde redakte edilir | `APP_KEY`'e ve veritabanına sahip olan herkes bunların şifresini çözebilir. Uygulama logu ham driver hata mesajını alır; bu mesaj kullanıcı adlarını, host'ları ve satır değerlerini içerebilir. O logu veritabanı gibi koruyun. `php artisan config:cache`, `*_FILE`'dan alınan secret'ları `bootstrap/cache/config.php` içine düz metin olarak yazar |
| `APP_KEY` | Ortam, `APP_KEY_FILE` ya da data volume'deki bir anahtar dosyası | Nerede duracağını siz seçersiniz; SQLite veritabanıyla aynı volume'ü paylaştığında `queryproxy:doctor` uyarır | O volume'ün yedeği anahtarı verinin yanında tutar |
| Sonuç dosyaları | Sonuç diski | Yazılırken maskelenir (fail closed), yalnızca özel disk, indirmeler talep politikasından geçer, saklama süresi sonunda temizlenir | Maskeleme kural tabanlıdır; hiçbir kuralın eşleşmediği veri olduğu gibi saklanır |
| Denetim kayıtları | Uygulama veritabanı | Hash zinciri, `UPDATE` ve `DELETE`'e karşı trigger'lar, SIEM'e isteğe bağlı dışa aktarım | Harici bir kopya tutmazsanız veritabanı sahibi geçmişi yeniden yazabilir |
| Chat secret'ları, maskeleme anahtarları, TLS sertifikaları | Uygulama veritabanı, şifreli | Kimlik bilgileriyle aynı anahtar; imzalama secret'ını yalnızca bir sistem yöneticisi ayarlayabilir | Kimlik bilgileriyle aynı |
| Gönderilen SQL | Uygulama veritabanı | Varsayılan olarak Auditor'lara ve chat'te redakte edilmiş gösterilir; ham SQL denetim ekranında, CSV'de ya da SIEM dışa aktarımında yoktur | Talep sahipleri, takımın DBA'leri ve yöneticiler SQL'i gönderildiği haliyle görür |

## Aktörler

| Aktör | Başlangıç noktası | Amaç |
| :-- | :-- | :-- |
| Kötü niyetli geliştirici | Developer rolüyle bir QueryProxy hesabı | Görmemesi gereken veriyi okumak, onaysız veri değiştirmek, sunucuda tehlikeli bir şey çalıştırmak |
| Ele geçirilmiş DBA hesabı | DBA rolüyle çalınmış ya da kötüye kullanılmış bir hesap | Zararlı talepleri onaylamak, korumaları zayıflatmak, maskelenmemiş veriyi okumak |
| Ağdaki saldırgan | Tarayıcı, QueryProxy, chat ve hedef veritabanları arasındaki ağ konumu | Bir kullanıcının ya da chat onaylayıcısının kimliğine bürünmek, trafiği okumak veya değiştirmek, iç servislere ulaşmak |

Yönetici güvenilirdir: yöneticiler onayları override edebilir, imzalama
secret'larını ayarlayabilir ve kullanıcıları yönetebilir. Host'ta root olan ya da
hem veritabanına hem `APP_KEY`'e sahip olan biri modelin dışındadır.

## Güven sınırları

```
Browser ──HTTPS──▶ reverse proxy ──HTTP──▶ QueryProxy (web, worker, scheduler)
Slack / Teams ◀──HTTPS webhook── QueryProxy ◀──signed callbacks── Slack / Teams
QueryProxy ──TLS──▶ target databases
QueryProxy ──▶ application database, result disk
QueryProxy ──▶ SIEM (stdout, syslog, signed webhook), Prometheus (scrape)
```

1. **Tarayıcıdan QueryProxy'ye.** Konteyner `7432` üzerinde düz HTTP sunar; TLS
   sonlandırıcı sizindir. `TRUSTED_PROXIES` ve `TRUSTED_HOSTS`, kimin
   `X-Forwarded-*` başlıklarının ve hangi host adlarının geçerli sayılacağına
   karar verir.
2. **Chat'ten QueryProxy'ye.** Callback'ler imzalıdır (Slack imzası, Teams
   HMAC), beş dakika sonra sona erer ve tek bir talebe bağlı, tek kullanımlık
   bir action token taşır. Onaylayıcı, entegrasyonun takımındaki bir QueryProxy
   kullanıcısına eşlenir.
3. **QueryProxy'den hedef veritabanlarına.** v0.3.0'dan itibaren oluşturulan ağ
   bağlantıları TLS ister. Okumalar timeout'lu, salt okunur bir oturumda çalışır.
   Bağlantının veritabanı kullanıcısının yetkileri son savunma hattıdır.
4. **QueryProxy'den dışarıya.** Webhook'lar yalnızca allowlist'teki host'lara
   gider ve asla yönlendirilmez. Denetim sink'leri ve `/metrics`, yapılandırılana
   kadar kapalıdır.

## Her aktörün deneyebilecekleri

### Kötü niyetli geliştirici

- *Onaysız yazma çalıştırmak.* Yazmalar `pending` olarak kuyruğa girer ve bir
  DBA'i bekler; talep sahibi kendi talebini onaylayamaz. Okumalar veritabanında
  salt okunur bir oturumda çalışır.
- *Guard'ları sözdizimiyle atlatmak.* Inspector yorumları normalleştirir ve
  ifadeleri anahtar kelimeye değil tehlikeli kısmına göre değerlendirir; sınıflandırılamayan
  girdi yazma sayılır. Yine de bir denylist'tir: henüz adını anmadığı bir yazım
  geçebilir. Bir ifadeyi yetkilendiren denylist değil, onaydır.
- *Maskelenmemiş veriyi okumak.* Maskeleme sonuç yazılırken uygulanır; bu yüzden
  maskelenmemiş satırlar sonuç deposuna hiç ulaşmaz. Maskelenmiş bir sütuna göre
  filtreleyen bir ifade, değeri yine de çıkarımla sızdırabilir (aday değerleri
  deneyen bir `WHERE` ifadesi). Sensitive-filter rozeti, bir talep maskeleme
  kuralı olan bir sütuna göre filtrelediğinde onaylayıcıyı uyarır; talebi
  engellemez. Sütun takma adlarını, CTE'leri ya da türetilmiş tabloları izlemez
  ve regex ile validator kurallarını yok sayar.
- *Kaynakları tüketmek.* Sert bir `LIMIT` tavanı, bir statement timeout, bir lock
  timeout ve bağlantı başına bir slot sınırı uygulanır. MySQL'de uzun bir yazma
  veritabanı timeout'u tarafından kesilmez.
- *Bağlantılar ya da webhook'lar üzerinden iç host'lara ulaşmak.* Bağlantı
  host'ları reddedilebilir (`QUERYPROXY_CONNECTION_HOST_DENYLIST`), SQLite
  dosyaları sabitlenir (`QUERYPROXY_SQLITE_ALLOWED_DIR`) ve giden webhook'lar
  SSRF korumalıdır.

### Ele geçirilmiş DBA hesabı

- *Kendi talebini onaylamak.* Reddedilir. Başka bir DBA'in ya da kuralı denetim
  günlüğüne düşen yazılı bir gerekçeyle override eden bir yöneticinin karar
  vermesi gerekir.
- *Bir chat onayını taklit etmek.* HMAC tek başına yalnızca çağıranın secret'ı
  bildiğini kanıtlar; bu yüzden secret'ı yalnızca bir yönetici ayarlayabilir,
  callback canlı bir tek kullanımlık token ister ve onaylayıcı takımın eşlenmiş
  bir kullanıcısı olmalıdır.
- *Korumaları zayıflatmak.* Bir DBA maskeleme kurallarını ve bağlantıları yönetir
  ve bir kuralı kapatabilir ya da erişim tanımlayabilir. Bu değişiklikler
  denetlenir. Bunları denetim günlüğünde inceleyin ve onu okuyabilen Auditor'lar
  bulundurun; bir DBA okuyamaz.
- *Takma adlandırılmış değerleri geri çıkarmak.* `hmac` maskeleme bir değeri,
  takım içinde sabit olan anahtarlı bir token ile değiştirir. ulusal kimlik
  numarası ya da telefon numarası gibi düşük entropili tanımlayıcılar, aynı
  kuraldan bir aday geçirebilen herkes tarafından (maskeleme playground'u ya da
  adayları döndüren onaylı bir sorgu) token'a karşı denenebilir. `hmac`'i
  anonimleştirme değil, takım içinde takma adlandırma olarak görün. Anahtarı
  döndürmek eski ve yeni token'ların eşleşmemesine yol açar.
- *Kanıtı silmek.* Denetim kayıtları uygulama üzerinden güncellenemez ya da
  silinemez ve veritabanı bunu trigger'lar aracılığıyla reddeder (MySQL ve
  MariaDB'de trigger'lar `TRUNCATE`'i engelleyemez). Veritabanını uygulamanın
  dışında değiştirebilen kişi bir sonraki aktördür.

### Ağdaki saldırgan

- *QueryProxy'ye giden trafiği okumak veya değiştirmek.* Önüne TLS koyun,
  `SESSION_SECURE_COOKIE=true` ayarlayın ve `TRUSTED_PROXIES`'i yalnızca
  vekilinize ayarlayın.
- *İstemci adreslerini taklit etmek.* `TRUSTED_PROXIES` yalnızca vekillerinizi
  adlandırdığı sürece mümkün değildir. `10.0.0.0/8` gibi geniş bir aralık,
  içindeki her host'un `X-Forwarded-For` ayarlamasına izin verir;
  `queryproxy:doctor` yalnızca `*` ve hepsini-kapsar aralıklarda başarısız olur.
- *Bir chat callback'ini yeniden oynatmak.* Beş dakika sonra ve ilk karardan
  sonra reddedilir.
- *QueryProxy ile bir hedef veritabanı arasına girmek.* Yeni bağlantılar TLS
  ister, bu yüzden düz metne düşürme başarısız olur. Şifreleme tek başına
  karşı tarafta kimin olduğunu kanıtlamaz: PostgreSQL için `verify-ca` ya da
  `verify-full` seçin, MySQL ve MariaDB için "Verify the server certificate"
  kutusunu işaretleyin, SQL Server için `TrustServerCertificate`'i kapalı
  bırakın. v0.3.0 öncesinden gelen mevcut bağlantılar siz düzenleyene kadar eski
  davranışlarını korur. SQL Server için, şifreleme sunmayan bir sunucuyu
  reddetmek ODBC driver'ının belgelenmiş davranışıdır; QueryProxy'nin test
  ettiği bir şey değildir.
- *`/metrics`'i scrape etmek.* Varsayılan olarak kapalı; bir token ya da izinli bir
  adres gerekir.

## Guard'ın kapsamadıkları

Guard bir derinlemesine savunma katmanıdır, güvenlik sınırı değildir. Tam liste
[SQL korumaları](/tr/docs/sql-korumalari/#bilinen-sınırlar) sayfasındadır. Riski
değerlendirirken en çok önem taşıyanlar:

- Sunucuda zaten bulunan kod (fonksiyonlar, prosedürler, trigger'lar), bir talep
  onu çağırdığında incelenmez.
- MySQL ve MariaDB saklı kod gövdeleri ve `SET PASSWORD` listeleri `SET`
  ifadesi olarak incelenmez.
- SQLite ve SQL Server'ın katalog tablolarına yazmalar ile katalog tablolarında
  `TRUNCATE`, `DROP` ve `ALTER`, katalog kuralının dışındadır.
- SQL Server'da engine düzeyinde salt okunur oturum yoktur. Ayrı bir okuma
  kimlik bilgisi olmadan bir okuma yalnızca guard'a dayanır.
- Chat ve denetim görünümleri için redaksiyon birkaç biçimi görünür bırakır;
  örneğin SQL Server dışında `$12.50` gibi bir para literal'i ve PostgreSQL ya da
  SQL Server'da çift tırnakla yazılmış bir değer (tanımlayıcı olarak okunur ve
  çalıştırıldığında başarısız olur).

Her bağlantıya, takıma uyan en az yetkiye sahip bir veritabanı kullanıcısı ve
veritabanı sunuyorsa ayrı bir salt okunur kimlik bilgisi verin.

## Sizde kalan riskler

- `APP_KEY`'i güvende ve yedeklerden ayrı tutmak.
- QueryProxy'nin önündeki TLS ve doğru `TRUSTED_PROXIES`.
- QueryProxy'nin bağlandığı veritabanı kullanıcılarının yetkileri.
- Veritabanı erişimi olan biri tarafından logun yeniden yazılmadığını
  kanıtlamanız gerekiyorsa, denetim logunun harici bir kopyası (bir SIEM sink'i).
- Kimin yönetici olduğu ve kimin hangi takımın DBA'i olduğu.
- Host, konteyner runtime'ı ve çalıştırdığınız image. Release image'ları
  imzalıdır; bkz. [Yükseltme ve geri alma](/tr/docs/yukseltme/#image-doğrulama).

## Sonraki adımlar

- [Üretim güvenliği](/tr/docs/uretim-guvenligi/)
- [Denetim zinciri ve SIEM dışa aktarımı](/tr/docs/denetim-kaydi-ve-siem/)
- [Yedekleme ve geri yükleme](/tr/docs/yedekleme-ve-geri-yukleme/)
