# MySQL ve MariaDB erişim denetimi ve sorgu onayı

> Geliştiricilere parola paylaşmadan MySQL ya da MariaDB üretim erişimi nasıl verilir; QueryProxy yol boyunca neyi engeller, onaylar ve maskeler.

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

---
MySQL ve MariaDB, hangi hesapların hangi şemalara ve tablolara 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
SQL gönderir, ifade kuyruğa girmeden önce parse edilip denetlenir, bir DBA onaylar
ve sonuç saklanmadan önce maskelenir. Veritabanı parolası QueryProxy'nin kasasında
kalır ve hiçbir geliştiriciye verilmez.

## GRANT neyi açık bırakır?

`GRANT` bir hesabı şemalara, tablolara ve kolonlara sınırlar ve sıkılaştırmanız
gereken ilk şey olmalıdır. Yine de üretimde önem taşıyan üç boşluk bırakır:

- Bir tabloyu `UPDATE` edebilen hesap, `WHERE`'siz bir `UPDATE` çalıştırabilir
  (bkz. [`WHERE`'siz `UPDATE` ve `DELETE` nasıl engellenir](/tr/blog/where-olmadan-update-delete-engelleme/);
  yazı MySQL safe updates'i de kapsar).
- `users` tablosunu `SELECT` edebilen hesap, içindeki her e-posta adresini
  maskesiz olarak bir dizüstü bilgisayara alır.
- İfade çalışmadan önce başka kimse onu görmez.

MySQL 8.4 referansı, tek bir yetkinin ne kadar ileri gidebileceğini gösterir.
[`FILE` yetkisi](https://dev.mysql.com/doc/refman/8.4/en/privileges-provided.html),
bir hesabın sunucu makinesindeki dosyaları `LOAD DATA`,
`SELECT ... INTO OUTFILE` ve `LOAD_FILE()` ile okuyup yazmasına izin verir ve
`secure_file_priv` bunun nerede olabileceğini sınırlar (2026-10-13 tarihinde
okundu). QueryProxy'nin doğrudan reddettiği ifadeler bunlardır.
[Veritabanı erişim denetiminin ne olduğu](/tr/veritabani-erisim-denetimi-nedir/)
yazısı, tek başına rollerin bu boşlukları neden kapatmadığını açıklar.

## QueryProxy MySQL'de 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. `LIMIT`'siz bir `SELECT`'e
  `LIMIT 1000` eklenir, `10000`'in üzerindeki limit ise düşürülür.
- `SELECT ... INTO OUTFILE`, `INTO DUMPFILE`, `LOAD DATA` ve `LOAD_FILE()`
  engellenir. `SELECT ... INTO @var` düz bir okumadır.
- Paylaşımlı bir kütüphaneden UDF yükleyen `CREATE FUNCTION ... SONAME`
  engellenir; `CREATE USER`, `ALTER USER`, `DROP USER` ve `SHUTDOWN` da öyle.
- `general_log`, `plugin_dir`, `secure_file_priv` ve `local_infile` gibi korunan
  ayarlar üzerinde `SET GLOBAL`, `SET PERSIST` ve `SET PERSIST_ONLY` reddedilir.
  Bu ayarlara `SESSION` yazımı korunmaz.
- `get_lock`, `release_lock`, `sleep` ve `benchmark` yazma olarak sınıflandırılır;
  böylece okuma gibi geçmek yerine onaydan geçerler.
- `PREPARE s FROM '<DML without WHERE>'` engellenir ve `PREPARE s FROM @q` de
  engellenir, çünkü metin bir değişkenin içindedir.
- Her kapsamda `SET sql_mode` reddedilir.

```sql
DELETE FROM orders;                           -- rejected at submission
DELETE FROM orders WHERE id = 42;             -- allowed, still needs a DBA
SELECT * FROM users INTO OUTFILE '/tmp/u';    -- rejected at submission
```

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

## sql_mode neden önemli?

Guard tırnakları ve ters eğik çizgileri varsayılan şekilde okur. Bir oturumun
`sql_mode` değeri `NO_BACKSLASH_ESCAPES` ya da `ANSI_QUOTES` içeriyorsa sunucu
aynı metni farklı okur ve guard'ın zararsız gördüğü bir string kod olabilir. Bu
yüzden QueryProxy, bir `mysql` ya da `mariadb` bağlantısında SQL çalıştırmadan
önce `@@SESSION.sql_mode` değerini okur; bayraklardan biri varsa talep başarısız
olur, hiçbir şey çalışmaz ve mesajda bayrağın adı geçer. QueryProxy bağlanırken
katı bir `sql_mode` ayarlar; kontrol yine de devreye giriyorsa bağlantıdan sonra
modu değiştiren bir şey arayın, örneğin aradaki bir proxy.
[Yapılandırma rehberi](/tr/docs/yapilandirma/) bunu anlatır.

## MariaDB'de ne farklı?

Bir MariaDB sunucusunu `mysql` sürücüsüyle değil `mariadb` sürücüsüyle kaydedin.
[SQL korumaları referansı](/tr/docs/sql-korumalari/) nedenini verir: çalıştırılabilir
yorumların nasıl okunacağına sürücü karar verir.

- **Çalıştırılabilir yorumlar.** `/*M!100000 ... */` MariaDB'de koddur.
  `mariadb` sürücüsünde guard gövdeyi SQL olarak okur; `mysql` sürücüsünde ise
  düz bir yorumdur. Hedef bilinmediğinde `/*M!` doğrudan reddedilir.

İki MariaDB'ye özgü ifade biçimi her iki sürücüde de denetlenir; yani biri ya da
öteki sürücüyü seçmenin nedeni değildir:

- **`ANALYZE` ifadeleri.** MariaDB'nin `ANALYZE UPDATE ...` ifadesi yazma olarak
  sınıflandırılır ve `WHERE`'siz `ANALYZE DELETE FROM t` engellenir; `ANALYZE SELECT ...`
  ise içindeki `SELECT` olarak değerlendirilir. `ANALYZE DROP TABLE`,
  `ANALYZE TRUNCATE` ve `ANALYZE SET` engellenir.
- **`SET STATEMENT ... FOR <statement>`.** `FOR`'dan sonraki ifade kendi kurallarıyla
  değerlendirilir. İfade yoksa talep engellenir.

Önceki bölümdeki geri kalan her şey MariaDB için de geçerlidir.

## Bir MySQL ya da MariaDB veritabanı nasıl bağlanır?

Bir DBA, veritabanını **Connections** altında `mysql` ya da `mariadb` sürücüsüyle
kaydeder. Varsayılan port `3306`'dır
([`DbDriver.php`](https://github.com/QueryProxy/QueryProxy/blob/v0.2.5/app/Enums/DbDriver.php),
v0.2.5). Varsayılan Docker imajı `pdo_mysql` ile gelir, dolayısıyla imajı
değiştirmek gerekmez. 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.

Salt okunur çalışan ekipler için, yalnızca `SELECT` yetkisi olan bir veritabanı
kullanıcısıyla 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. Hata mesajları da maskelemeden geçer, çünkü
`Duplicate entry '...'` gibi mesajlar bir değeri yankılayabilir. Gönderimden
indirmeye kadar her adım değiştirilemez bir denetim günlüğüne yazılır.

## MySQL ve MariaDB'de sınırlar neler?

- **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.
- **Henüz canlı sunuculara karşı çalıştırılmadı.** Referans, MySQL ve MariaDB
  davranışının guard'ın unit testlerine karşı doğrulandığını ve bu dialect'lerin
  canlı sunuculara 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 veritabanı kullanıcısı
  kullanın.
- **Sunucuda saklanan kod kapsanmaz.** Veritabanında zaten var olan bir stored
  procedure ya da fonksiyon, içindekini çalıştırır.
- **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; `GRANT` artı salt okunur bir hesap yeterlidir. Gerçek veri
tutmayan bir geliştirme veritabanı için de aynısı geçerlidir. Sorununuz yalnızca
uygulamaların parolaları yapılandırma dosyalarında tutması ise, bir secrets
manager ya da
[IAM veritabanı kimlik doğrulaması](/tr/compare/aws-iam-database-authentication/)
bunu bir onay kuyruğu olmadan çözer. 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

### Parolayı paylaşmadan geliştiricilere üretim MySQL veritabanına erişimi nasıl veririm?

Veritabanını QueryProxy'ye bir kez kaydedin; kimlik bilgisi orada AES-256 ile şifrelenmiş olarak saklanır. Geliştiricilere parolayı değil bağlantıyı verin. SQL gönderirler, bir DBA onaylar ve bir işçi (worker) bunu saklanan kimlik bilgisiyle çalıştırır. Geliştiriciler parolayı hiç görmez.

### QueryProxy MySQL'in yanı sıra MariaDB'yi de destekliyor mu?

Evet. MariaDB sunucusunu mariadb sürücüsüyle, MySQL sunucusunu mysql sürücüsüyle kaydedin. Sürücüler, guard'ın çalıştırılabilir yorumları (/*M!100000 ... */) nasıl okuduğu bakımından ayrılır; ANALYZE UPDATE ve SET STATEMENT ... FOR gibi MariaDB ifadelerini guard her iki sürücüde de denetler.

### Bir geliştirici QueryProxy üzerinden bir tabloyu dosyaya aktarabilir mi?

Guard'ın tanıdığı SQL ile hayır. SELECT ... INTO OUTFILE, INTO DUMPFILE, LOAD DATA ve LOAD_FILE() gönderim anında reddedilir. Sonuçlar portal üzerinden, maskelenmiş olarak, görüntüleyici ya da CSV indirme olarak döner.

### Bir talep neden sql_mode mesajıyla başarısız oluyor?

mysql ya da mariadb bağlantısında SQL çalıştırmadan önce QueryProxy oturumun sql_mode değerini okur. İçinde NO_BACKSLASH_ESCAPES ya da ANSI_QUOTES varsa guard tırnakları sunucudan farklı okurdu; bu yüzden talep başarısız olur ve hiçbir şey çalışmaz.

### MySQL ve MariaDB bağlantıları için veritabanı tarafında salt okunur transaction var mı?

Henüz yok. Veritabanı tarafındaki salt okunur transaction ve statement timeout, kapsanmayanlar arasında listelenir ve v0.3.0 için planlanmıştır. O zamana kadar okuma bağlantılarına yalnızca SELECT yetkisi olan bir veritabanı kullanıcısı verin.
