# Üretimde WHERE'siz UPDATE ve DELETE nasıl engellenir

> Üretimde WHERE'siz UPDATE ve DELETE ifadeleri nasıl engellenir; MySQL safe updates'ten parse etmeye, onaya ve veritabanı yetkilerine kadar.

- Yayın: 2026-10-13
- Tags: sql koruması, erişim denetimi
- Kaynak: https://queryproxy.com/tr/blog/where-olmadan-update-delete-engelleme/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
Üretimde `WHERE`'siz bir `UPDATE` ya da `DELETE`'i, ifadeyi yazan kişinin fark
etmesini umarak değil, ifadeyi veritabanına ulaşmadan reddederek durdurursunuz.
Bunun için üç katman gerekir, çünkü her biri farklı biçimde başarısız olur: ifadeyi
reddeden bir parse adımı, geriye kalanı okuyan bir insan ve ilk ikisi kaçırdığında
hasarı sınırlayan veritabanı yetkileri.

## Kaza neye benzer?

```sql
DELETE FROM orders;
```

Bir veritabanı istemcisindeki editör bunu, `WHERE id = 42` olan ifadeyi
gönderdiği gibi gönderir. Veritabanı, doğru yetkiye sahip bir kullanıcıdan gelen
geçerli bir ifade görür ve çalıştırır. `DELETE` yetkisi olan bir rol, dikkatle
yapılmış tek satırlık bir değişiklikle tüm tabloyu etkileyen değişikliği
ayırt edemez; [veritabanı erişim denetiminin ne olduğunu](/tr/veritabani-erisim-denetimi-nedir/)
anlatan yazıda geçen "kim işlem yapabilir" ile "ifade ne yapar" arasındaki
boşluk budur.

## MySQL safe updates sorunu çözer mi?

Kısmen. MySQL 8.4 kılavuzu,
[`--safe-updates`'i](https://dev.mysql.com/doc/refman/8.4/en/mysql-tips.html)
"WHERE koşulunu unutarak bir UPDATE ya da DELETE ifadesi vermiş olabileceğiniz"
durumlarda yararlı olarak tanımlar. `sql_safe_updates` açıkken bu tür ifadeler
"WHERE koşulunda bir anahtar kısıtı belirtmezse ya da bir LIMIT koşulu
sağlamazsa, ya da ikisini birden" hata üretir. (2026-10-13'te okundu.)

Üretimde üç sınır önemlidir:

- Oturum bazında bir ayardır. Oturumunda açık olan kişiyi korur; bir betiğin ya
  da başka bir aracın onsuz açtığı bağlantıyı korumaz.
- Bir `LIMIT` onu tatmin eder. `DELETE FROM orders LIMIT 100000` kuralı geçer ve
  yine de yüz bin satırı siler.
- Kılavuz, `WHERE` koşulunda anahtar olsa bile optimizer indeksi kullanmamaya
  karar verirse ifadenin hata verebileceğini belirtir. Doğru ifadelerde tetiklenen
  bir kural kapatılır.

Terminalde çalışan kişiler için kullanın. Tek denetiminiz bu olmasın. Aynısı GUI
istemcilerindeki üretim ayarları için de geçerlidir;
[DBeaver ve DataGrip karşılaştırması](/tr/compare/dbeaver-datagrip/) bunların
neyi koruyup neyi açık bıraktığını ele alır.

## İfadeyi parse etmek ne katar?

Bağlantının önünde duran bir guard, kuralı hangi araç yazmış olursa olsun her
ifadeye uygulayabilir. QueryProxy her gönderimi, onay kuyruğuna girmeden önce
parse eder. [SQL korumaları referansının](/tr/docs/sql-korumalari/) ifadesiyle,
`WHERE`'siz bir `UPDATE` ya da `DELETE` gönderim anında reddedilir ve statik
olarak her zaman doğru olan bir `WHERE` koşulu eksik sayılır:

```sql
DELETE FROM users;                        -- rejected
DELETE FROM users WHERE 1 = 1;            -- rejected
DELETE FROM users WHERE true;             -- rejected
DELETE FROM users WHERE id = 1 OR 1 = 1;  -- rejected
DELETE FROM users WHERE id = 42;          -- allowed, still needs approval
```

Kural transaction'ların, CTE gövdelerinin, `EXPLAIN ANALYZE`'ın ve MariaDB
`ANALYZE`'ın içinde de geçerlidir. Geçersiz kılma imkânı yoktur: `WHERE`'siz ya
da her zaman doğru olan bir ifade bir gözden geçirene asla ulaşmaz (aşağıdaki
PostgreSQL `DO` blokları istisnadır).

Buna güvenmeden önce bilmeye değer iki ayrıntı var:

- **Birden fazla ifade açık bir transaction ister.** Bir istekteki iki çıplak
  `UPDATE` ifadesi reddedilir. `BEGIN … COMMIT` içinde atomik çalışırlar ve
  herhangi bir ifade başarısız olursa her şey geri alınır.
- **Kontrol statiktir.** Literalleri, karşılaştırmaları, `AND`, `OR`, `NOT` ve
  parantezleri değerlendirir. Bir kolon ya da fonksiyon gibi değerlendiremediği
  bir işlenen asla doğru sayılmaz. PostgreSQL `DO` blokları da bu kuraldan
  muaftır: yazma olarak sınıflandırılır ve her zaman, gövdenin tamamını gören
  bir DBA'ya gider.

## Guard neden yetmez?

Çünkü yasak listesi doğası gereği eksiktir. Aynı referans, listenin "yapısal
olarak eksik" olduğunu ve bir ifadeyi yetkilendirenin DBA onayı olduğunu söyler:
hazırlanmış SQL'i gören ve çalışıp çalışmaması gerektiğine karar veren bir kişi.
İkinci katman budur. Bir isteğin nasıl ilerlediğini
[SQL sorgu onay akışında](/tr/sql-sorgu-onay-akisi/) okuyabilirsiniz.

Üçüncü katman veritabanının kendisidir. QueryProxy'nin
[üretim güvenliği rehberi](/tr/docs/uretim-guvenligi/), yalnızca okuyanlar için
yalnızca `SELECT` yetkili ayrı bir bağlantıyı önerir ve salt okunur çalıştırmanın
henüz mevcut olmadığını belirtir (v0.3.0 için planlı).
[SQL korumaları kapsam tablosu](/tr/docs/sql-korumalari/#kapsam), veritabanı
tarafındaki bir ifade zaman aşımını da henüz kapsanmamış olarak listeler; o da
v0.3.0 için planlıdır. O zamana kadar veritabanı tarafındaki sınırınız
yetkilerdir. Motora özgü ayrıntılar
[PostgreSQL erişim denetiminde](/tr/postgresql-erisim-denetimi/) ve
[MySQL ve MariaDB erişim denetiminde](/tr/mysql-mariadb-erisim-denetimi/).

## Yine de olursa?

O zaman bir kurtarma sorunudur. PostgreSQL 18.6,
[sürekli arşivleme ve point-in-time recovery'yi](https://www.postgresql.org/docs/18/continuous-archiving.html)
belgeler: "temel yedeğiniz alındığından bu yana herhangi bir andaki duruma
veritabanını geri yüklemek mümkündür." Bu, yalnızca arşivleme hatadan önce
kurulmuşsa işe yarar. (2026-10-13'te okundu.)

## Bu ne zaman fazla gelir?

Küçük bir veritabanının tek sahibi varsa ve her değişiklik gözden geçirilmiş
migration'lardan geçiyorsa, bağlantının önündeki bir parse adımı pek bir şey
katmaz. Asıl gerekçesi, üretime erişimi olan çok sayıda kişi ve elle yazılan
ifadelerdir. Başlamak için [hızlı başlangıç](/tr/docs/hizli-baslangic/),
QueryProxy'yi tek bir `docker run` ile çalıştırır.
