# SQL Server erişim denetimi ve sorgu onayı

> Geliştiricilere parola paylaşmadan SQL Server üretim erişimi nasıl verilir; QueryProxy neyi engeller ve onaylar, önce hangi sürücüyü eklemeniz gerekir.

- Kaynak: https://queryproxy.com/tr/sql-server-erisim-denetimi/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
SQL Server, hangi login'lerin ve kullanıcıların hangi nesnelere erişebileceğine
karar verir. Gece 3'te biri tarafından yazılan *bu özel ifadenin* çalışıp
çalışmaması gerektiğine karar vermez. QueryProxy bu kararı ekler: geliştiriciler
T-SQL gönderir, ifade kuyruğa girmeden önce parse edilip denetlenir, bir DBA
onaylar ve sonuç saklanmadan önce maskelenir. SQL Server parolası QueryProxy'nin
kasasında kalır ve hiçbir geliştiriciye verilmez.

## Önce neyi kurmanız gerekir?

SQL Server, varsayılan imajın erişemediği tek motordur. Docker imajı `pdo_pgsql`,
`pdo_mysql` ve `pdo_sqlite` ile gelir. SQL Server'ı proxy'lemek için:

1. Dockerfile'ı Microsoft'un ODBC sürücüsü ile `sqlsrv` ve `pdo_sqlsrv` PECL
   eklentileriyle genişletin.
2. Kendi imajınızı build edin ve `queryproxy/queryproxy` yerine onu çalıştırın.
3. Eklentilerin, hem web sürecini hem de kuyruk işçisini çalıştıran PHP build'inde
   olduğundan emin olun; çünkü onaylanan sorgular işçide çalışır.

Manuel kurulumda da aynısı geçerlidir: SQL Server hedefleri için `pdo_sqlsrv`
bulunmalıdır. Ayrıntılar
[yapılandırma rehberinde](/tr/docs/yapilandirma/#sql-server-hedefleri) var.
Bu yapılmadan bir SQL Server bağlantısı sorgu çalıştıramaz.

## Bir login'in izni neyi açık bırakır?

İzinler bir login'i veritabanlarına, şemalara ve nesnelere sınırlar ve önce
onları sıkılaştırmalısınız. Yine de boşluklar bırakırlar:

- Bir tabloyu `UPDATE` edebilen kullanıcı, `WHERE`'siz bir `UPDATE` çalıştırabilir.
- `users` tablosunu `SELECT` edebilen kullanıcı, içindeki her e-posta adresini
  maskesiz olarak bir dizüstü bilgisayara alır.
- İfade çalışmadan önce başka kimse onu görmez.

SQL Server'ın veritabanı motorunun dışına çıkan prosedürleri de vardır.
Microsoft'un dokümantasyonu,
[`xp_cmdshell`](https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/xp-cmdshell-transact-sql?view=sql-server-ver17)
prosedürünün bir Windows komut kabuğu başlattığını ve komutun SQL Server servis
hesabıyla aynı haklarla çalıştığını söyler. Varsayılan olarak kapalıdır ve
`sp_configure` ile açılır (2026-10-13 tarihinde okundu). QueryProxy hem `xp_*`
ailesini hem de `sp_configure`'u gönderim anında engeller; yani bir talep bunları
istemeye bile kalkışamaz.
[Veritabanı erişim denetiminin ne olduğu](/tr/veritabani-erisim-denetimi-nedir/)
yazısı, tek başına izinlerin bu boşlukları neden kapatmadığını açıklar.

## QueryProxy SQL Server'da neyi engeller?

Her gönderim onay kuyruğuna ulaşmadan önce parse edilir ve bir guard'ı çiğneyen
talep, gönderim anında açık bir mesajla reddedilir.
[SQL korumaları referansı](/tr/docs/sql-korumalari/) kuralları dialect'e göre
listeler. Burada en önemli olanlar:

- `WHERE`'siz ya da her zaman doğru olan bir `WHERE` ile (`WHERE 1 = 1`)
  yazılmış `UPDATE` ve `DELETE` reddedilir. `TOP`'suz üst düzey bir `SELECT`'e
  `TOP (1000)` eklenir, `10000`'in üzerindeki `TOP` ise `TOP 10000`'e düşürülür.
  CTE ve küme işlemi sorgularına `TOP` eklenmez; onları 10000 satırlık tavan
  sınırlar.
- `xp_*`, `sp_configure`, `sp_oa*`, `sp_addlinkedserver`, `sp_addlinkedsrvlogin`,
  `sp_serveroption`, `sp_addextendedproc` ve `sp_execute_external_script`, ister
  ifade olarak ister `EXEC`'ten sonra çağrılsın, engellenir.
- `OPENROWSET`, `OPENDATASOURCE`, `OPENQUERY` ve `BULK INSERT` engellenir.
- `GRANT`, `REVOKE`, `DENY` ve `SHUTDOWN` engellenir.
- `sp_prepare`, `sp_execute`, `sp_sqlexec`, `sp_msforeachtable` ve
  `sp_send_dbmail` gibi kendilerine verilen metni çalıştıran prosedürler,
  argümanları ne olursa olsun engellenir.
- `THROW`, `RECONFIGURE`, `KILL` ve `CHECKPOINT` yazma olarak sınıflandırılır;
  böylece onaydan geçerler.

```sql
DELETE FROM orders;                           -- rejected at submission
DELETE FROM orders WHERE id = 42;             -- allowed, still needs a DBA
EXEC xp_cmdshell 'dir';                       -- rejected at submission
SELECT 'xp_cmdshell';                         -- a plain read
```

Tablo adları örnektir; kararlar belgelenmiş kurallara göre verilir.

## Dinamik SQL nasıl ele alınır?

`EXEC('...')` ve `sp_executesql` SQL'i metin olarak alır; T-SQL guard'ları genellikle
tam burada kırılır. QueryProxy okuyabildiğini değerlendirir:

- `WHERE`'siz `EXEC('DELETE FROM t')` engellenir ve
  `EXEC('DELETE FROM t WHERE id = 1')` yazma olarak sınıflandırılır.
- `sp_executesql N'...'`, içindeki metne olağan kurallar uygulanarak değerlendirilir.
- `EXEC(@sql)`, `EXEC('a' + 'b')`, `EXEC(...) AT srv` ve `EXEC ... AS USER`,
  guard neyin çalışacağını bilemeyeceği için engellenir.
- `EXEC('EXEC xp_cmdshell ''dir''')` gibi iç içe bir literal engellenir.
- 3 seviyeden derin iç içe geçmiş dinamik SQL engellenir.

Guard şüphede katı davranır: `EXEC "quoted_name"` ve `WHERE exec = 1` de
engellenir.

## Bir SQL Server veritabanı nasıl bağlanır?

Yukarıdaki imaj değişikliğinden sonra bir DBA, veritabanını **Connections** altında
SQL Server sürücüsüyle (`sqlsrv`) kaydeder. Varsayılan port `1433`'tür
([`DbDriver.php`](https://github.com/QueryProxy/QueryProxy/blob/v0.2.5/app/Enums/DbDriver.php),
v0.2.5). Kimlik bilgileri AES-256 ile şifrelenerek saklanır ve geliştirici bir
bağlantıyı yalnızca bir DBA yetki verdikten sonra görür. [Paylaşılan parola olmadan
üretim veritabanı erişimi](/tr/blog/paylasilan-parola-olmadan-uretim-veritabani-erisimi/)
yazısı, parolanın neden QueryProxy'de kalması gerektiğini açıklar.

Salt okunur çalışan ekipler için, yalnızca `SELECT` izni olan bir login ile ayrı bir
bağlantı kaydedin ve mümkünse onu bir replikaya yöneltin.
[Üretim güvenliği rehberi](/tr/docs/uretim-guvenligi/) bunu önerir.

## Sonuca ne olur?

Satırlar, cursor'dan sonuç dosyasına akarken maskelenir; böylece maskesiz bir
kopya diskte hiç bulunmaz. Maskeleme kuralları bir kolon adıyla (`*email*` gibi)
ya da bir değerin içeriğiyle eşleşir; hiçbir kuralın eşleşmediği değer olduğu
gibi döner. [Dinamik veri maskeleme](/tr/dinamik-veri-maskeleme/) fikri anlatır,
[veri maskeleme dokümantasyonu](/tr/docs/veri-maskeleme/) ise kural türlerini ve
stratejileri listeler. Gönderimden indirmeye kadar her adım değiştirilemez bir
denetim günlüğüne yazılır.

## SQL Server'da sınırlar neler?

- **Sürücüyü eklemek size düşer.** Varsayılan imajda, yukarıda anlatıldığı gibi,
  SQL Server desteği yoktur.
- **Yasak listesi eksiktir.** Bugün bilinen tehlikeli sözdizimini adlandırır;
  adlandırmadığı bir yazım geçer. [SQL korumaları referansı](/tr/docs/sql-korumalari/)
  bunu kendisi söyler: bir ifadeyi yetkilendiren şey guard değil, DBA onayıdır.
- **`EXECUTE AS USER = 'x'` kapsanmaz.** Guard bu konuda hiçbir şey yapmaz.
- **Henüz canlı sunuculara karşı çalıştırılmadı.** Referans, SQL Server
  davranışının guard'ın unit testlerine karşı doğrulandığını ve bu dialect'in
  canlı bir sunucuya karşı çalıştırılmadığını belirtir.
- **Veritabanı tarafında henüz salt okunur transaction ve statement timeout yok.**
  İkisi de v0.3.0 için planlananlar arasında listelenir. O zamana kadar okuma
  bağlantıları için yalnızca `SELECT` yetkisi olan bir login kullanın.
- **Sunucuda saklanan kod kapsanmaz.** Veritabanında zaten var olan bir stored
  procedure, içindekini çalıştırır. `EXEC dbo.my_proc 1` yazma olarak
  sınıflandırılır ve onaya gider.
- **Maskeleme kural tabanlıdır.** Hiçbir kuralın eşleşmediği değer olduğu gibi
  döner; bu yüzden QueryProxy tüm kişisel verileri maskelediğini iddia etmez.

## QueryProxy'ye ne zaman ihtiyacınız yok?

Veritabanının sahibi tek kişiyse ve bağlanan yalnızca kendisiyse, onaylayacak
ikinci bir kişi yoktur; izinler artı salt okunur bir login yeterlidir. Gerçek veri
tutmayan bir geliştirme veritabanı için de aynısı geçerlidir. Ekibinizin yalnızca
daha iyi bir SQL istemcisine ihtiyacı varsa
[QueryProxy ile DBeaver ve DataGrip karşılaştırmasına](/tr/compare/dbeaver-datagrip/)
bakın. QueryProxy, insanların önemli verilere anlık erişmesi gerektiğinde ve ikinci
bir çift göz ile neyin çalıştığının kaydını istediğinizde yerini hak eder.

Bir talebin nasıl ilerlediği için [onay akışına](/tr/sql-sorgu-onay-akisi/) bakın
ya da [QueryProxy'yi bir atlama sunucusuyla karşılaştırın](/tr/compare/bastion-host/).
PostgreSQL ekipleri
[PostgreSQL erişim denetimi](/tr/postgresql-erisim-denetimi/) sayfasından
başlayabilir.

## Sık sorulanlar

### QueryProxy SQL Server'ı kutudan çıktığı gibi destekliyor mu?

Hayır. Varsayılan Docker imajı pdo_pgsql, pdo_mysql ve pdo_sqlite ile gelir. SQL Server'ı proxy'lemek için Dockerfile'ı Microsoft'un ODBC sürücüsü ile sqlsrv ve pdo_sqlsrv PECL eklentileriyle genişletir, ardından queryproxy/queryproxy yerine kendi imajınızı çalıştırırsınız. Eklentiler, hem web sürecini hem kuyruk işçisini (worker) çalıştıran PHP build'inde bulunmalıdır.

### Sürücü neden web sürecinde olduğu kadar işçide (worker) de olmak zorunda?

Onaylanan sorgular web sürecinde değil, kuyruk işçisinde çalışır. İşçinin PHP build'inde SQL Server eklentileri yoksa bir talep onaylanıp ardından çalışırken başarısız olabilir.

### QueryProxy xp_cmdshell'i engelliyor mu?

Evet. İster ifade olarak ister EXEC'ten sonra çağrılsın, her xp_* prosedürü sp_configure ve sp_oa* ile birlikte gönderim anında engellenir. Yalnızca bir string literal'in içinde geçen ad, örneğin SELECT 'xp_cmdshell', düz bir okumadır.

### Bir geliştirici çalışma anında kurulmuş bir SQL string'iyle EXEC çalıştırabilir mi?

Metin okunamıyorsa hayır. EXEC(@sql) ve EXEC('a' + 'b') engellenir. Literal bir string ile EXEC olağan kurallarla değerlendirilir; yani içindeki WHERE'siz bir DELETE engellenir, WHERE'li olan ise yazma olarak sınıflandırılır.

### Bir SQL Server SELECT kaç satır döndürür?

TOP'suz üst düzey bir SELECT'e TOP (1000) eklenir; CTE ve küme işlemi sorguları ise bunun yerine 10000 satırlık tavanla sınırlanır. 10000'in üzerindeki TOP, TOP 10000'e düşürülür. TOP (@v) ya da TOP 10 PERCENT gibi guard'ın hesaplayamadığı biçimler engellenir.
