# Üretim verisine erişim: parolayı paylaşmak tek seçenek değil

> Üretim veritabanına giden ad-hoc SQL'i onaya, maskelemeye ve değiştirilemez bir ize bağlayan self-hosted portal; QueryProxy ürününe dönüştü.

- Şu an ne yapıyor: Geliştiricinin yazdığı SQL'i üretim veritabanında doğrudan değil, bir onaydan geçirerek çalıştırıyor; sonuçlar diske yazılırken maskeleniyor ve her istek değiştirilemez bir kayda düşüyor. Prod erişimi tek kişide toplanmış ekipler kurabilir.
- Tür: Açık kaynak, Web uygulaması
- Durum: Ürün oldu
- Odak: Erişim yönetişimi & veri koruma
- Başlangıç: 2026-09-06
- Labs’tan çıkış: 2026-09-08
- Teknolojiler: PHP, Laravel, Livewire, Tailwind CSS, Vite, PostgreSQL, MySQL, Docker
- Etiketler: #sql, #erisim-denetimi, #maskeleme, #guvenlik
- Kaynak kodu: https://github.com/QueryProxy/QueryProxy
- Web sitesi: https://queryproxy.com
- Bu iş ürüne dönüştü: QueryProxy (https://www.muhammetsafak.com.tr/portfolyo/queryproxy/)
- Kaynak: https://www.muhammetsafak.com.tr/labs/queryproxy-lab/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
Bir hata üretimde görünüyorsa teşhisi de orada. Ama üretim parolasını dağıtmak
bir çözüm değil; onu tek kişide tutmak da, o kişi izne çıktığı anda çözüm
olmaktan çıkıyor.

## Parolayı paylaşmadan veriye bakmak

Denenen şey şuydu: geliştirici üretim verisine bakabilsin, ama kimlik
bilgisini hiç görmesin. Bağlantı künyesi uygulamada şifreli duruyor, sorguyu
çalıştıran da geliştiricinin makinesi değil, portalın kendisi. Geliştiricinin
elinde kalan tek şey yazdığı SQL.

Bunun bedeli, kabul edilen bir dolaylılık: sorgu artık anında çalışmıyor.
Karşılığında üretim parolası hiçbir zaman bir insanın eline geçmiyor ve bir
kişinin takvimi ekibin teşhis hızını belirlemiyor.

## Sorgu okunuyor, aranmıyor

Portalın kapısı desen eşleştirmesiyle kurulsaydı ilk gün aşılırdı — araya
yorum sıkıştırmak, dizeyi bölmek, alt sorguya saklanmak yeterdi. Bunun yerine
gelen SQL ayrıştırılıyor: ifadenin ne olduğu metinden değil, çözümlenmiş
yapısından okunuyor.

Pratik sonucu şu: `WHERE`'i olmayan bir `UPDATE` ya da `DELETE` geri çevriliyor,
limitsiz bir `SELECT` varsayılan bir satır sınırıyla dönüyor, veritabanı ya da
kullanıcı yönetimine dokunan ifadeler koşulsuz reddediliyor. Yorum ve dize
sabitleri normalize edildiği için `DROP/**/DATABASE` yazmak kapıyı açmıyor.

Kapının anlamadığı bir limit ifadesi ise kırpılmıyor, **reddediliyor** —
anlaşılmayan bir sınır, zorlanamayan bir sınırdır. Ayrıca çalıştırıcı tarafında
SQL ne derse desin geçerli olan mutlak bir satır tavanı duruyor; kapıdan bir
şekilde sızan sorgu bile sonuç deposunu dolduramıyor.

## Onay tek servisten geçiyor

Onay üç kanaldan geliyor — web arayüzü, Slack, Teams — ama üçü de aynı servise
iniyor. Kural tek yerde yazılı olduğu için kanal eklemek kuralı çoğaltmıyor:
bir DBA'nın kendi isteğini onaylaması her kanalda kapalı — sistem admini
aşabiliyor ve aşma denetim kaydına düşüyor — iki kanal aynı isteği aynı anda
onaylarsa koşullu güncelleme ikincisini düşürüyor. Sohbet geri çağrılarında
eylemi yapan kişi, isteğin beyan ettiği adresten değil yöneticinin kurduğu
eşlemeden çözülüyor — paylaşılan bir imza anahtarı, başkası adına onay vermeye
yetmiyor.

## Maskeleme sonradan değil, yazarken

Son karar maskelemenin nerede durduğuyla ilgili. Sonucu önce kaydedip
gösterirken maskelemek kolay yoldu; o tasarımda maskesiz veri diske bir kez
yazılıyor ve oradan sonrası temenniye kalıyor.

Bunun yerine sonuç akışı satır satır okunuyor ve her satır **dosyaya
yazılmadan önce** maskeleniyor. Sonuç deposuna maskesiz bir hücre hiç girmiyor;
indirme ve görüntüleme de zaten maskelenmiş dosyayı okuyor. Aynı disiplin
kuralların kendisinde de var: bir düzenli ifade kaydedilirken uzun bir prob
dizesiyle sınanıyor, çalışma anında değerlendirilemezse değer açıkta
bırakılmıyor, maskeleniyor.

Labs aşaması üç günde kapandı — ihtiyaç o kadar netti. QueryProxy artık kendi
alan adı ve sürümleri olan bir ürün; ayrıntısı portfolyoda.
