# PostgreSQL erişim denetimi ve sorgu onayı

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

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

---
PostgreSQL, kimin hangi nesneleri okuyabileceğine ya da değiştirebileceğ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. PostgreSQL parolası QueryProxy'nin kasasında kalır ve
hiçbir geliştiriciye verilmez.

## GRANT ve satır düzeyi güvenlik neyi kapsar?

`GRANT`, bir role nesneler üzerinde yetki verir: tablolar, kolonlar, şemalar,
fonksiyonlar. Bir rolün neye erişebileceğini sınırlamak için doğru araçtır ve
her üretim kurulumu onu kullanmalıdır.

Satır düzeyi güvenlik daha da ileri gider. PostgreSQL 18.6 dokümantasyonu,
[satır güvenliği politikalarının](https://www.postgresql.org/docs/18/ddl-rowsecurity.html)
"normal sorgularla hangi satırların döndürülebileceğini ya da veri değiştirme
komutlarıyla hangi satırların eklenebileceğini, güncellenebileceğini veya
silinebileceğini" kısıtladığını söyler. Aynı sayfa, superuser'ların ve
`BYPASSRLS` özniteliğine sahip rollerin onu her zaman atladığını, tablo
sahiplerinin de normalde atladığını belirtir. (2026-10-13 tarihinde okundu.)

İkisinin de yapmadığı şey ifadeye bakmaktır. Bir tabloyu `UPDATE` edebilen rol,
`WHERE` cümlesiz bir `UPDATE` çalıştırabilir. `users` tablosunu `SELECT`
edebilen rol, içindeki her e-posta adresini maskesiz olarak bir dizüstü
bilgisayara alır. İkisinde de ikinci bir kişi yoktur. Bu boşluklar
[veritabanı erişim denetiminin ne olduğu](/tr/veritabani-erisim-denetimi-nedir/)
yazısının savıdır: roller kimin işlem yapabileceğini söyler, ifadeyi inceleyemez.
[`WHERE`'siz `UPDATE` ve `DELETE` nasıl engellenir](/tr/blog/where-olmadan-update-delete-engelleme/)
yazısı bu boşluğu ayrıntılı ele alır.

## QueryProxy PostgreSQL'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. PostgreSQL'de 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.
- `COPY`, `COPY ... TO PROGRAM` dahil, engellenir.
- Dosya fonksiyonları engellenir: `pg_read_file()`, `pg_read_binary_file()`,
  `pg_ls_dir()`, `lo_import()` ve `lo_export()`.
- `dblink*` ile `pg_terminate_backend`, `pg_cancel_backend`, `pg_reload_conf`,
  `pg_rotate_logfile`, `pg_promote` ve `pg_switch_wal` yönetim fonksiyonları
  engellenir.
- Kendilerine string olarak verilen SQL'i çalıştıran `query_to_xml`,
  `xpath_table`, `ts_stat` ve `crosstab*` gibi fonksiyonlar, guard içerideki
  ifadeyi okuyamadığı için engellenir.
- `CREATE EXTENSION` ada göre değerlendirilir. Güvenilmeyen prosedürel diller
  (`plpythonu`, `plperlu` ve `pl...u` kuralına uyan her ad) reddedilir;
  `pgcrypto`, `uuid-ossp` ya da `postgis` normal şekilde kurulur.
- `session_preload_libraries`, `dynamic_library_path` ya da
  `session_replication_role` gibi korunan bir ayarın `SET` ile değiştirilmesi her
  kapsamda reddedilir.

```sql
DELETE FROM customers;                      -- rejected at submission
DELETE FROM customers WHERE id = 42;        -- allowed, still needs a DBA
SELECT pg_read_file('/etc/passwd');         -- rejected at submission
```

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

## DO blokları nasıl ele alınır?

Bir `DO` bloğu, bir `CREATE FUNCTION` ya da bir `CREATE PROCEDURE` başka bir
dilde yazılmış bir gövde taşır. QueryProxy bu gövdeyi PostgreSQL'in kendi sözcük
kurallarıyla okur, engellenen fonksiyon ve korunan ayar kurallarını ona uygular
ve yalnızca `plpgsql` ile `sql` dillerini kabul eder.

`DO` bloğu yazma olarak sınıflandırılır ve her zaman insan onayından geçer; onay
veren kişi gövdenin tamamını görür. Dinamik SQL (`EXECUTE`) kullanan bir gövde,
çalıştıracağı ifade çalışma anında kurulduğu için doğrudan reddedilir. Bir
plpgsql bloğunun yapabileceği geri kalan her şeye parser değil, onay karar verir.

## Bir PostgreSQL veritabanı nasıl bağlanır?

Bir DBA, veritabanını **Connections** altında `pgsql` sürücüsüyle kaydeder.
Varsayılan port `5432`'dir
([`DbDriver.php`](https://github.com/QueryProxy/QueryProxy/blob/v0.2.5/app/Enums/DbDriver.php),
v0.2.5). Varsayılan Docker imajı `pdo_pgsql` ile gelir, dolayısıyla imajı
değiştirmek gerekmez; gerisini [yapılandırma rehberi](/tr/docs/yapilandirma/)
anlatır. Kimlik bilgileri AES-256 ile şifrelenerek saklanır. Geliştirici
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.

Maskeleme hataları da kapsar. `Failing row contains (...)` gibi bir PostgreSQL
hatası, kısıtı bozan satırı yankılayabilir; bu yüzden bağlantıda herhangi bir
maskeleme kuralı varsa, saklanan hata mesajında satırın tamamı maskelenir.
Gönderimden indirmeye kadar her adım değiştirilemez bir denetim günlüğüne yazılır.

## PostgreSQL'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.
- **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.
- **TLS henüz yapılandırılamıyor.** Bağlantı bugün `sslmode=prefer` kullanır ve
  bir TLS ayarı v0.3.0 için planlanmıştır. Aktarım katmanını kendiniz kontrol
  edin.
- **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.
- **`DO` gövdesi taraması yalnızca düz metni okur.** `plpgsql` ile yazılmış bir
  `DO` bloğu hâlâ keyfi sunucu tarafı koddur ve gövdesinde açıkça yazılmış
  `WHERE`'siz bir `DELETE` geçer, çünkü bloklara onayda karar verilir.

PostgreSQL için guard'ın kararları canlı bir sunucuya karşı da denetlenir
(`live-pgsql` test grubu). Referans, MySQL, MariaDB ve SQL Server'ın canlı
sunuculara karşı çalıştırılmadığını belirtir.

## 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 rol 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/).
MySQL ve MariaDB ekipleri
[MySQL ve MariaDB erişim denetimi](/tr/mysql-mariadb-erisim-denetimi/) sayfasından
başlamalı.

## Sık sorulanlar

### Parolayı paylaşmadan geliştiricilere üretim PostgreSQL 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.

### PostgreSQL'de kişisel verileri korumak için GRANT SELECT yeterli mi?

Hayır. GRANT SELECT, rolün yetki verilen her kolonu, e-posta adresleri ve telefon numaraları dahil, okumasına izin verir ve bunları istemciye maskesiz döndürür. Satır düzeyi güvenlik satırları gizleyebilir ama izin verdiği satırlardaki bir kolonu maskeleyemez. Maskeleme ayrı bir katmandır ve QueryProxy bunu sonuç yazılırken uygular.

### QueryProxy COPY ... TO PROGRAM'ı engelliyor mu?

Evet. SQL guard, PostgreSQL COPY'yi, COPY ... TO PROGRAM dahil, gönderim anında reddeder; talep hiçbir DBA'e ulaşmaz. Aynısı pg_read_file(), pg_read_binary_file(), pg_ls_dir(), lo_import() ve lo_export() için de geçerlidir.

### QueryProxy PostgreSQL'deki DO bloklarını nasıl ele alıyor?

DO bloğu yazma olarak sınıflandırılır ve her zaman tüm gövdesini gören bir DBA'e gider. Gövde, engellenen fonksiyonlar ve korunan ayarlar için taranır; dinamik SQL (EXECUTE) kullanan bir gövde, çalıştıracağı ifade önceden okunamadığı için reddedilir.

### QueryProxy, PostgreSQL rollerinin ve satır düzeyi güvenliğin yerini alıyor mu?

Hayır. Onların önüne bir katman ekler. QueryProxy bağlantısına yalnızca işin gerektirdiği yetkilere sahip bir veritabanı kullanıcısı verin; okuma bağlantıları için ideali yalnızca SELECT'tir, çünkü veritabanı tarafındaki salt okunur transaction ve statement timeout henüz mevcut değil.
