QueryProxy
Doküman menüsü

SQL korumaları

AST denetleyicisinin her gönderimde uyguladığı kurallar — WHERE zorunluluğu, LIMIT enjeksiyonu, transaction'lar ve yasaklı komutlar.

Güncelleme:

Her gönderim, onay kuyruğuna girmeden önce parse edilip denetlenir. Kural ihlal eden talep, açık bir mesajla gönderim anında reddedilir — DBA’e bile ulaşmaz, veritabanına hiç ulaşmaz.

Kurallar

UPDATE / DELETE için WHERE zorunlu

DELETE FROM users;                    -- ✗ reddedilir
DELETE FROM users WHERE id = 42;      -- ✓ kabul (yine de onay gerekir)

Bu kural transaction içinde de geçerlidir. Statik olarak her zaman doğru olan bir WHERE eksik sayılır:

DELETE FROM users WHERE 1 = 1;        -- ✗ reddedilir
DELETE FROM users WHERE true;         -- ✗ reddedilir
DELETE FROM users WHERE id = 1 OR 1 = 1;  -- ✗ reddedilir

Denetim; sabit değerleri (sayılar, düz string’ler, TRUE, FALSE, NULL), karşılaştırmaları, IS [NOT] NULL|TRUE|FALSE, AND, OR, NOT ve parantezleri değerlendirir. Değerlendiremediği bir operand (bir kolon, bir fonksiyon) hiçbir zaman doğru sayılmaz: tespit statiktir ve en iyi çabayla (best-effort) çalışır. Değerlendirilemeyecek kadar derin iç içe geçmiş ya da çok büyük bir WHERE de reddedilir (… with a WHERE clause too complex to verify is not allowed). Bu kural geçersiz kılınamaz. Tespit statik olduğu için yaygın hataları durdurur; bir yazmanın yalnızca birkaç satırı etkilediğini kanıtlamaz.

Kural; EXPLAIN ANALYZE ve MariaDB ANALYZE içindeki ifade, CTE gövdeleri, T-SQL batch’leri ve dinamik SQL için de geçerlidir. PostgreSQL DO blokları istisnadır: bu kural için denetlenmezler, yazma olarak sınıflandırılırlar ve her zaman insan onayından geçerler; incelemeci gövdenin tamamını görür. Bir DO gövdesindeki dinamik SQL (PL/pgSQL EXECUTE) ise bu pazarlığın öbür yüzüdür: çalıştırdığı ifade çalışma anında oluşturulur ve okunamaz, bu yüzden doğrudan reddedilir (bkz. Anahtar kelimeye değil, tehlikeli kısma bakılan kurallar).

SELECT’e LIMIT eklenir

  • LIMIT yok mu? Varsayılan (1000) otomatik eklenir — kendi satırında, ki sondaki bir satır yorumu onu yutamasın.
  • LIMIT üst sınırın (10000) üzerinde mi? Aşağı çekilir.
  • LIMIT ALL (PostgreSQL) sınırsız sayılır ve sınırlanır.
  • Offset korunur: LIMIT 10, 20000 → LIMIT 10, 10000, LIMIT 99999 OFFSET 4 → LIMIT 10000 OFFSET 4.
  • FETCH FIRST n ROWS ONLY ve T-SQL TOP n de aynı şekilde sınırlanır.
  • SQL Server hedeflerine LIMIT eklenmez (geçerli T-SQL değildir); guard bunun yerine TOP üzerinde çalışır. Mevcut bir TOP n / TOP (n) üst sınıra (10000) çekilir; TOP içermeyen bir üst düzey SELECT ise varsayılan değer olan TOP (1000)’i, varsa DISTINCT / ALL’dan sonra alır. TOP … PERCENT, TOP (@v), ifadeler ve ondalıklar reddedilir. WITH, OFFSET, UNION, EXCEPT ve INTERSECT için TOP eklenmez; bunları işçinin satır tavanı (üst sınır) sınırlar ve sonuç “kırpıldı” olarak işaretlenir.
  • Guard’ın düz bir satır sayısı olarak anlayamadığı bir LIMIT (aritmetik — LIMIT 100*100000 —, ifadeler, yer tutucular) sınırlanmak yerine reddedilir: doğrulanamayan bir limit uygulanamaz.
  • Alt sorgu LIMIT’lerine dokunulmaz; yalnızca dış sorgu denetlenir. Kilitleme ifadeleri gözetilir — eklenen LIMIT, FOR UPDATE’ten önce yerleşir.

Bunun üstüne işçi, sonuçları akıtırken SQL’den bağımsız mutlak bir satır tavanı (üst sınır) uygular — yani cümle düzeyindeki guard’ı atlayan bir sorgu bile (dialect tuhaflıkları, SHOW, EXPLAIN) tavandan fazlasını döndüremez; saklanan sonuç “kırpıldı” olarak işaretlenir.

İki sayı da yapılandırılabilir — bkz. Yapılandırma. Hazırlanan SQL (eklenen LIMIT ile) gönderimden önce geliştiriciye, incelemede DBA’e gösterilir; onayladığınız şey birebir çalışan şeydir.

Çoklu ifadeler açık transaction ister

UPDATE a SET x = 1 WHERE id = 1;
UPDATE b SET y = 2 WHERE id = 2;      -- ✗ reddedilir: iki çıplak ifade
BEGIN;
UPDATE a SET x = 1 WHERE id = 1;
UPDATE b SET y = 2 WHERE id = 2;
COMMIT;                               -- ✓ kabul, atomik çalışır

İşçi ifadeleri gerçek bir transaction içinde çalıştırır: herhangi biri başarısız olursa tamamı geri alınır. Gönderimde ROLLBACK reddedilir — başarısızlıkta geri alma otomatiktir, elle yazılacak bir şey değildir. İç içe transaction desteklenmez.

Her zaman yasak

Bu komutlar sunucu düzeyinde kod çalıştırma ya da dosya erişimi verir ve bir sorgu portalı üzerinden gündelik bir karşılıkları yoktur. Rolden bağımsız olarak, koşulsuz reddedilirler:

  • DROP DATABASE / DROP SCHEMA
  • GRANT, REVOKE, DENY
  • CREATE USER / ALTER USER / DROP USER (ve ROLE / LOGIN türevleri)
  • CREATE FUNCTION … SONAME — yüklenebilir UDF’ler (ve CREATE AGGREGATE FUNCTION karşılığı)
  • SHUTDOWN
  • Sunucu tarafı dosya / program IO: SELECT … INTO OUTFILE / INTO DUMPFILE, LOAD DATA, PostgreSQL COPY (COPY … TO PROGRAM dahil), LOAD_FILE() fonksiyonu ve PostgreSQL’in dosya fonksiyonları pg_read_file(), pg_read_binary_file(), pg_ls_dir(), lo_import() ve lo_export() — şema nitelikli çağrılar (pg_catalog.pg_read_file(…)) dahil. Yalnızca çağrı biçimi yakalanır; aynı ada sahip bir kolon ya da takma ad engellenmez.
  • Kendilerine string olarak verilen SQL’i çalıştıran ve guard’ın okuyamadığı PostgreSQL fonksiyonları: query_to_xml, query_to_xmlschema, query_to_xml_and_xmlschema, xpath_table, ts_stat, ts_rewrite, crosstab* ve connectby.

Bu denetimler ifadenin yorumdan arındırılmış biçimi üzerinde çalışır; yani DROP/**/DATABASE ya da baştaki bir /* … */ yorumu gibi hileler yasak bir ifadeyi denetimden geçiremez.

DROP TABLE, TRUNCATE ve ALTER doğrudan yasak değildir — onay gerektiren yazma olarak çalışırlar, ancak DDL içeren bir talep gönderim anında işaretlenir: onay kuyruğunda ve talep detay sayfasında DDL rozeti görünür, Slack ve Teams’e giden gönderim bildirimleri de DDL ibaresi taşır (sonraki onaylandı/reddedildi bildirimleri taşımaz). DDL içermeyen talepte işaret yoktur.

Veritabanı yönetimi altyapı araçlarınızın işidir, bir sorgu portalının değil.

Anahtar kelimeye değil, tehlikeli kısma bakılan kurallar

Üç ifade yalnızca içlerindekine bakılarak reddedilir; çünkü sözdizimleri, guard’ın elinden almaması gereken sıradan DBA işini de kapsar.

CREATE EXTENSION — extension adına göre. Untrusted prosedürel diller tanımları gereği veritabanı superuser’ı olarak çalışır ve reddedilir: plpythonu, plpython2u, plpython3u, plperlu, pltclu, plsh, plr, plluau, plrubyu, plphpu, pljavau — ve ayrıca PostgreSQL’in untrusted dil için kullandığı pl…u adlandırma konvansiyonuna uyan her ad; yani henüz kimsenin listelemediği bir bağlama (plpython4u) görüldüğü yerde reddedilir. Geri kalan her şey normal biçimde kurulur: pg_stat_statements, pgcrypto, uuid-ossp, postgis, plv8, plpgsql. Adı okunamayan bir CREATE EXTENSION reddedilir.

DO blokları ve rutin gövdeleri. Bir PostgreSQL DO bloğu, CREATE FUNCTION ya da CREATE PROCEDURE başka bir dilde bir gövde taşır; bu yüzden guard gövdeyi MySQL’in değil PostgreSQL’in kendi sözcüksel kurallarıyla (yorumlar, '…', E'…', U&'…', tırnaklı tanımlayıcılar ve iç içe dollar-quoted string’ler) okur ve üst düzey SQL’e uygulanan yasaklı fonksiyon ve korunan ayar kurallarını aynen uygular. Böylece DO $$ BEGIN DROP DATABASE prod; END $$ ve bir ters eğik çizgi ya da yorumun ardına saklanmış bir pg_read_file(…) çağrısı geçemez. Bunun üstüne:

  • Yalnızca plpgsql ve sql dilleri kabul edilir. LANGUAGE maddesi olmayan bir DO bloğu PostgreSQL varsayılanı olan plpgsql ile çalışır; CREATE FUNCTION / PROCEDURE ise SQL-standard bir RETURN gövdesi yoksa açık bir LANGUAGE plpgsql ya da sql gerektirir. Başka her dil, trusted olsun olmasın, reddedilir; guard’ın düz bir ad olarak okuyamadığı dil de öyle. Tırnaklı bir ad büyük/küçük harfini korur, dolayısıyla LANGUAGE "PLPGSQL" reddedilir. CREATE LANGUAGE ve ALTER LANGUAGE … RENAME de reddedilir.
  • Dinamik SQL (EXECUTE) kullanan bir gövde, trigger fonksiyonları dahil, çalıştırdığı ifade çalışma anında oluşturulduğu için reddedilir. Trigger EXECUTE FUNCTION|PROCEDURE maddeleri bundan etkilenmez.
  • BEGIN ATOMIC gövdeleri ve gövdesiz CREATE FUNCTION / CREATE PROCEDURE reddedilir.
  • Bir rutin (CREATE/ALTER FUNCTION|PROCEDURE … SET), bir veritabanı (ALTER DATABASE … SET) ya da bir rol (ALTER ROLE|USER … SET) üzerindeki SET maddesi aşağıdaki korunan ayar kuralından geçer. Ayar çözümlenemezse ifade reddedilir.

SET — değişken adına göre. Reddedilenler; bir dosya yolu belirleyen, kodu sunucu sürecine yükleyen ya da bir korumayı kapatan değişkenlerdir.

  • MySQL ve MariaDB: general_log, general_log_file, slow_query_log, slow_query_log_file, log_error, init_file, init_connect, plugin_dir, plugin_load, plugin_load_add, secure_file_priv, local_infile. Yalnızca kalıcı scope’lar değerlendirilir — GLOBAL, PERSIST ve PERSIST_ONLY; hem anahtar kelimeli (SET GLOBAL x = …) hem de değişken yazımında (SET @@GLOBAL.x = …). Bir SESSION yazması, sql_mode ve salt okunur anahtarı hariç (aşağıya bakın), korunmaz; @name bir kullanıcı değişkenidir, asla bir sunucu ayarı değil. SET STATEMENT … FOR <statement> (MariaDB) iki kez değerlendirilir: atamaları yukarıdaki kuralla, FOR’dan sonraki ifade ise tek başına gönderilmiş gibi.
  • PostgreSQL: session_preload_libraries, local_preload_libraries, dynamic_library_path, default_transaction_read_only, transaction_read_only, session_replication_role, allow_system_table_mods, lo_compat_privileges, zero_damaged_pages, ignore_checksum_failure, role, session_authorization. Bunlar her scope’ta reddedilir — SET x, SET LOCAL x, SET SESSION x, SET x TO … — çünkü kötüye kullanımları tam da oturum düzeyindeki değişikliktir. Hedef veritabanı bilinmediğinde de aynısı geçerlidir.
  • Her driver: set_config('<name>', …) listedeki her ad için, üçüncü argümanın her iki değerinde de reddedilir.
  • Her driver, her scope: sql_mode. NO_BACKSLASH_ESCAPES ve ANSI_QUOTES ters eğik çizginin ve çift tırnağın ne anlama geldiğini değiştirir; guard bunu izleyemez, bu yüzden SET sql_mode, SET SESSION sql_mode, SET @@sql_mode ve set_config('sql_mode', …) reddedilir. Okumak geçer. Çalıştırma anındaki karşılık gelen denetim için bkz. sonraki bölüm.

Eşleme tam ad üzerinden ve büyük/küçük harf duyarsızdır; joker yoktur, bu yüzden max_connections, wait_timeout, time_zone ve PostgreSQL’de work_mem ile search_path geçer.

Bu iki liste kurulumunuz için QUERYPROXY_EXTRA_UNTRUSTED_LANGUAGES ve QUERYPROXY_EXTRA_DANGEROUS_VARIABLES ile genişletilebilir. Fonksiyon, prosedür ve SQLite pragma listelerinin kendi QUERYPROXY_EXTRA_* ayarları var. Bkz. Yapılandırma. Yalnızca ekleme yapabilirler: yerleşik girdiler tabandır, yapılandırma onları kısaltamaz.

Kimlik, katalog ve salt okunur korumaları

Kimliğini değiştirebilen, sunucunun kendi tablolarını yeniden yazabilen ya da salt okunur durumunu kaldırabilen bir oturum buradaki diğer tüm kuralları geri alabilir. Bunlar guard’ın SQL okuduğu her konumda reddedilir: üst düzeyde, DO ve rutin gövdelerinde, PREPARE ve EXECUTE IMMEDIATE metninde, CTE gövdelerinde, EXPLAIN ANALYZE, MariaDB ANALYZE ve SET STATEMENT … FOR içinde. Bunun kapsamadığı ifadeler Bilinen sınırlar bölümünde listelenir. Aşağıdaki son madde istisnadır: gönderimde değil, talep çalışırken denetlenir.

  • Rol ve kullanıcı geçişleri. SET [SESSION|LOCAL] ROLE, RESET ROLE, SET … SESSION AUTHORIZATION, RESET SESSION AUTHORIZATION (RESET "role" gibi tırnaklı adlar dahil), MySQL ve MariaDB SET ROLE / SET DEFAULT ROLE, ayrıca set_config('role', …) / set_config('session_authorization', …). role ve session_authorization korunan ayarların yerleşik listesindedir.
  • ALTER SYSTEM, PostgreSQL’de neyi ayarlarsa ayarlasın.
  • Sistem kataloğuna yazma. PostgreSQL’de pg_catalog, pg_toast ve pg_… tablolarına INSERT, UPDATE, DELETE ve MERGE; MySQL ve MariaDB’de mysql şemasına aynı ifadeler ve REPLACE. Nitelikli ve tırnaklı yazımlar kapsanır. Kural yazma hedefine bakar; bu yüzden UPDATE t SET … FROM pg_proc ve INSERT INTO t SELECT … FROM pg_proc geçer. MySQL ve MariaDB’de bir mysql.* tablosunu yalnızca okuyan çok tablolu UPDATE / DELETE de reddedilir; çünkü guard hangi tabloya yazıldığını ayırt edemez. Kataloğu okumak (SELECT * FROM pg_proc, SELECT rolname FROM pg_roles) etkilenmez. MySQL ve MariaDB’de USE mysql de reddedilir (PREPARE, EXECUTE IMMEDIATE ve SET STATEMENT … FOR içinde de); şemasız bir ad katalogda çözülmesin diye.
  • READ WRITE: SET TRANSACTION, SET SESSION CHARACTERISTICS, BEGIN ve START TRANSACTION içinde. READ ONLY geçer.
  • MySQL / MariaDB salt okunur anahtarı. transaction_read_only ya da tx_read_only yazmak her scope’ta ve her yazımda reddedilir (SESSION, GLOBAL, @@, @@session., backtick, liste içinde, SET STATEMENT). transaction_isolation ve SET TRANSACTION READ ONLY geçer. Bazı ifadeler bunun için denetlenmez; bkz. Bilinen sınırlar.
  • PostgreSQL ALTER DATABASE|ROLE|USER … RESET ile korunan bir ayarın ya da ALL’un sıfırlanması; ayrıca CREATE [OR REPLACE] RULE … DO [ALSO|INSTEAD] <eylem> kuralının eylemi, tek başına gönderilen bir ifadeyle aynı kurallarla değerlendirilir. DO eylemini guard’ın bulamadığı kural reddedilir.
  • SQL Server kimlik taklidi. EXECUTE AS, EXEC AS, SETUSER ve REVERT; EXEC('…') ve sp_executesql içinde de, ayrıca nesne tanımlarındaki WITH EXECUTE AS. execute_as adlı bir kolon ve string literal içindeki aynı sözcükler etkilenmez.
  • Varsayılan veritabanı mysql olan bir bağlantıda MySQL / MariaDB yazması. Şemasız bir tablo adı oturumun varsayılan veritabanına göre çözülür; varsayılan mysql ise UPDATE user SET … hesap tablosunu düzenlerdi. Executor, yazmanın ilk ifadesinden önce bağlantıda DATABASE() değerini okur ve sonuç mysql ise talebi hiçbir şey çalıştırmadan başarısız kılar. Bağlantıyı uygulama veritabanına yönlendirin. Tek ifadeli okuma ve varsayılan veritabanı olmayan bağlantı denetlenmez.

Guard’ın sunucudan farklı okuduğu metin

Bazı metinleri guard’ın lexer’ı ile veritabanı farklı okur. Tahmin yürütmek yerine guard bunları ya reddeder ya da her iki okuma altında inceler:

  • Geçerli UTF-8 olmayan SQL (SQL must be valid UTF-8.) ya da lexer’ın içinde hiçbir ifade bulamadığı SQL (QueryProxy could not read this SQL: …).
  • String sabitlerinin, tırnaklı tanımlayıcıların ve yorumların dışında kalan bir byte-order mark ya da Unicode boşluk (U+FEFF, U+0085, U+00A0, U+1680, U+180E, U+2000–U+200B, U+2028, U+2029, U+202F, U+205F, U+3000) — her driver’da ve dinamik SQL içinde. Lexer böyle bir karakteri komşu sözcüğe yapıştırırken sunucu onu ayraç sayabilir.
  • MariaDB çalıştırılabilir yorumları (/*M!100000 … */). mariadb driver’ında gövde SQL olarak okunur ve 3 seviyeden derin iç içe geçme reddedilir. mysql driver’ında /*M! düz bir yorum olarak kalır; bu yüzden bir MariaDB sunucusunu mariadb driver’ıyla bağlayın. Hedef veritabanı bilinmediğinde /*M! doğrudan reddedilir.
  • mysql ve mariadb driver’larında sürüm koşullu yorumlar (/*!NNNNN … */). Böyle bir yorum iki kez denetlenir: bir kez sunucu gövdeyi çalıştırıyormuş, bir kez de atlıyormuş gibi; okumalardan biri reddedilirse ya da iki okuma ifade sayısı, transaction durumu, tür veya hazırlanan metin bakımından farklıysa ifade reddedilir. Şunlar da reddedilir (önceki sürümlere göre bir değişiklik): tek talepte farklı sürümler (SELECT /*!40101 1 */, /*!50503 2 */ bir örnektir), 5 haneli olmayan bir sürüm (MariaDB’de 5 ya da 6), başka bir yorumun içine yerleşmiş ya da başka bir yorum barındıran sürümlü yorum ve gövdesinde bir string ya da satır yorumu içinde */ geçen yorum.
  • MySQL ve MariaDB’de sql_mode. Ona yazmayı reddetmenin (yukarıda) yanı sıra executor, SQL’i çalıştırmadan önce @@SESSION.sql_mode değerini okur ve NO_BACKSLASH_ESCAPES ya da ANSI_QUOTES içeriyorsa hiçbir şey çalıştırmadan talebi başarısız kılar. QueryProxy açtığı her bağlantıda sunucunun varsayılanının yerine geçen katı bir sql_mode ayarlar; bu yüzden denetim bugün yalnızca bu ayar değişirse ya da aradaki bir şey modu değiştirirse devreye girer; bu bayraklardan birine sahip kalan bir bağlantı, bayrak kaldırılana dek reddedilir. Diğer driver’larda böyle bir denetim yoktur.
  • PostgreSQL ters eğik çizgileri ve #. Ters eğik çizgiye yalnızca yorumlarda, dollar-quoted gövdelerde, E'…' string’lerinde ve düzgün biçimli U& string’lerinde izin verilir; başka her yerde ('a\' gibi düz bir string dahil) reddedilir, çünkü PostgreSQL ile MySQL bunun ne anlama geldiği konusunda anlaşamaz. #, sabitlerin, tırnaklı tanımlayıcıların ve yorumların dışında reddedilir. Hedef veritabanı bilinmediğinde de aynı kurallar geçerlidir; MySQL ve MariaDB etkilenmez.

Yasak listesi ne değildir

Bu liste yapısal olarak eksiktir ve öyle kalacaktır. Bugün, birkaç lehçe genelinde bilinen tehlikeli sözdizimini sayar; adını koymadığı bir yazım — bir üretici eklentisi, bir fonksiyon takma adı, sunucunun gelecekteki bir özelliği — listeden geçer. Yukarıdaki her girdi, birinin daha önceki bir kuralı aşmanın yolunu bulması yüzünden vardır ve bu süreç bitmez.

Dolayısıyla onu derinlemesine savunmanın bir katmanı sayın, asla yetkilendirme sınırı değil. Bir ifadeyi gerçekte yetkilendiren DBA onayıdır: hazırlanan SQL’i görüp çalışıp çalışmaması gerektiğine karar verebilen bir insan. Yasak listesi yalnızca en bariz kötüye kullanım taleplerini o kişiye ulaşmadan eler. (Yeni bir boşluk yine de geçerli bir güvenlik bildirimidir; bkz. güvenlik politikası.)

Bu, DO gövdesi taraması için iki kat geçerlidir. Düz metin olarak yazılmış SQL’i okur; bloğun çalışma anında bir araya getirdiği SQL’i okuyamaz; bir DO ya da rutin gövdesindeki dinamik SQL’in (EXECUTE) taranmak yerine reddedilmesinin nedeni budur. Erişimi dışında kalan, bir bloğun yapabildiği geri kalan her şeydir: plpgsql ile yazılmış bir DO bloğu yine de sunucu tarafında serbest koddur ve gövdesinde düz yazılmış WHERE’siz bir DELETE geçer; çünkü bloklar bu kuraldan muaftır ve karar onayda verilir. Taramanın kazandırdığı şey, doğrudan superuser kod çalıştırma yollarının ve düz yazılmış yasak ifadenin elenmesidir; verilmemesi gereken bir onayın altındaki son ağdır, onaylanmış bir bloğun ne yapabileceğine konan bir sınır değil.

Kapsam

Guard’ın her yapıyla dialect bazında ne yaptığı. Reddedilir, talebin reddedildiği anlamına gelir. Yazma olarak sınıflandırılır, reddedilmediği ama onay gerektiren bir yazma olarak çalıştığı anlamına gelir (bir DELETE / UPDATE yine WHERE ister). Okuma düz bir okumadır. Kapsanmaz, guard’ın bugün bu konuda hiçbir şey yapmadığı anlamına gelir. Davranış, guard’ın birim testlerine karşı doğrulanır. PostgreSQL için karar ve sunucudaki etkisi ayrıca canlı bir sunucuya karşı da denetlenir (live-pgsql test grubu); MySQL, MariaDB ve SQL Server canlı sunuculara karşı çalıştırılmamıştır.

PostgreSQL

Yapı Durum
EXPLAIN ANALYZE DELETE FROM t / WHERE’siz UPDATE reddedilir
EXPLAIN (ANALYZE, BUFFERS) UPDATE t SET a=1 WHERE id=1 (ayrıca ANALYSE, ANALYZE true/on/1) yazma olarak sınıflandırılır
EXPLAIN ANALYZE SELECT 1 okuma
EXPLAIN DELETE FROM t WHERE id=1, EXPLAIN (ANALYZE false) DELETE FROM t okuma
EXPLAIN ANALYZE DROP DATABASE prod reddedilir
EXPLAIN (ANALYZE (kapatılmamış), ANALYZE maybe, boş seçenek, tırnaklı ya da bilinmeyen seçenek reddedilir
3 seviyeden derin iç içe EXPLAIN ANALYZE reddedilir
SELECT * INTO t2 FROM t (ayrıca SELECT*INTO, parantez içinde, bir CTE içinde) yazma (DDL) olarak sınıflandırılır, LIMIT eklenmez
SELECT * INTO TEMP t2 FROM t yazma (DDL) olarak sınıflandırılır
nextval, setval, pg_advisory_lock*, pg_advisory_xact_lock*, pg_try_advisory_*, pg_advisory_unlock* yazma olarak sınıflandırılır
pg_sleep, pg_sleep_for, pg_sleep_until yazma olarak sınıflandırılır
pg_terminate_backend, pg_cancel_backend, pg_reload_conf, pg_rotate_logfile, pg_promote, pg_switch_wal reddedilir
dblink* (önek: dblink ile başlayan bir kullanıcı fonksiyonu da reddedilir) reddedilir
pg_read_file, pg_read_binary_file, pg_ls_dir, lo_import, lo_export (tırnaklı ve U& yazımlar dahil) reddedilir
set_config('literal', …) yazma olarak sınıflandırılır
set_config(<not a literal>, …) (sabit olmayan argüman) reddedilir
set_config('session_preload_libraries', …) ve listedeki diğer PostgreSQL ayarları reddedilir
Listedeki bir PostgreSQL ayarının SET / SET LOCAL / SET SESSION ile yazılması her scope’ta reddedilir
SET sql_mode, set_config('sql_mode', …) reddedilir
SET work_mem, set_config('search_path', …) ve listede olmayan diğer ayarlar yazma olarak sınıflandırılır
ALTER SYSTEM … reddedilir
SET [SESSION|LOCAL] ROLE, RESET ROLE, RESET "role", SET SESSION AUTHORIZATION, RESET SESSION AUTHORIZATION, set_config('role', …) reddedilir
pg_catalog, pg_toast ya da pg_… tablosuna INSERT / UPDATE / DELETE / MERGE (CTE, DO gövdesi, PREPARE içinde de) reddedilir
SELECT * FROM pg_proc, SELECT rolname FROM pg_roles okuma
UPDATE t SET … FROM pg_proc WHERE …, INSERT INTO t SELECT … FROM pg_proc yazma olarak sınıflandırılır; yazma hedefi belirleyicidir
SET TRANSACTION READ WRITE, SET SESSION CHARACTERISTICS … READ WRITE, BEGIN READ WRITE, START TRANSACTION READ WRITE reddedilir
SET TRANSACTION READ ONLY geçer
ALTER DATABASE|ROLE|USER … RESET <listedeki ayar> ya da RESET ALL reddedilir
CREATE RULE … DO [ALSO|INSTEAD] <eylem> eylem olağan kurallarla değerlendirilir; DO’su bulunamayan kural reddedilir
DELETE FROM t WHERE 1 = 1, WHERE true, WHERE id = 1 OR 1 = 1 reddedilir (her zaman doğru WHERE)
WHERE’siz DELETE FROM t içeren DO bloğu yazma olarak sınıflandırılır; WHERE kuralından muaftır, karar onayda verilir
PREPARE n AS <statement> yazma olarak sınıflandırılır; ifade kendi kurallarıyla değerlendirilir
WITH x AS (DELETE FROM t) SELECT … (WHERE yok) reddedilir
WITH x AS (UPDATE t SET a=1 WHERE id=1 RETURNING …) SELECT … yazma olarak sınıflandırılır
WITH … DELETE FROM t (WITH’ten sonraki ifade) WHERE kuralı uygulanır
3 seviyeden derin iç içe ya da okunamayan WITH reddedilir
Bir CTE içindeki INSERT / MERGE gövdesi yazma olarak sınıflandırılır; gövdeye ayrı bir WHERE denetimi yapılmaz (kapsanmaz)
EXECUTE (dinamik SQL) içeren DO bloğu, CREATE FUNCTION / CREATE PROCEDURE, trigger fonksiyonları dahil reddedilir
plpgsql ya da sql dışında bir dilde DO / CREATE FUNCTION / CREATE PROCEDURE; BEGIN ATOMIC gövdesi; gövdesiz CREATE FUNCTION; CREATE LANGUAGE reddedilir
Yasaklı bir fonksiyonu çağıran ya da korunan bir ayarı yazan DO / rutin gövdesi (PERFORM pg_read_file(…)) reddedilir; gövde PostgreSQL’in sözcüksel kurallarıyla okunur
Listedeki bir ayarın CREATE/ALTER FUNCTION … SET, ALTER DATABASE … SET, ALTER ROLE … SET ile yazılması reddedilir
query_to_xml, query_to_xmlschema, query_to_xml_and_xmlschema, xpath_table, ts_stat, ts_rewrite, crosstab*, connectby reddedilir
Bir DO / rutin gövdesinde yukarıdakiler dışındaki düz plpgsql metni yazıldığı gibi taranır (bunun ötesi kapsanmaz)
Sabit, tırnaklı tanımlayıcı ya da yorum dışında # reddedilir
Yorum, dollar-quoted gövde, E'…' ya da düzgün biçimli U& string dışında ters eğik çizgi reddedilir
SELECT … FOR UPDATE okuma (satırları kilitler)
DENY reddedilir (; ile ayrılmış ya da tek başına biçimleri)
Veritabanı tarafında salt okunur transaction kapsanmaz (v0.3.0 için planlandı)
Veritabanı tarafında statement timeout kapsanmaz (v0.3.0 için planlandı)
TLS: bağlantı sslmode=prefer kullanır kapsanmaz (ayar v0.3.0 için planlandı)

MySQL / MariaDB

Yapı Durum
EXPLAIN ANALYZE UPDATE t SET a=1 WHERE id=1 yazma olarak sınıflandırılır
EXPLAIN ANALYZE DELETE FROM t (WHERE yok) reddedilir
ANALYZE’sız EXPLAIN okuma
MariaDB ANALYZE UPDATE t SET a=1 WHERE id=1 (ayrıca ANALYZE FORMAT=JSON …) yazma olarak sınıflandırılır
MariaDB ANALYZE DELETE FROM t (WHERE yok) reddedilir
MariaDB ANALYZE SELECT … içindeki SELECT olarak değerlendirilir
MariaDB ANALYZE DROP TABLE t, ANALYZE TRUNCATE …, ANALYZE SET …, (ANALYZE …) reddedilir
ANALYZE TABLE t (ve NO_WRITE_TO_BINLOG / LOCAL biçimleri) yazma olarak sınıflandırılır, değişmedi
/*M!100000 DELETE FROM t */ (mariadb driver’ı) gövde denetlenir; mysql driver’ında düz yorum
Sürümlü /*!NNNNN … */ yorumları gövde her iki okuma altında denetlenir; karışık sürümler ve tuhaf hane sayıları reddedilir (bkz. yukarısı)
SET SESSION sql_mode = …, SET GLOBAL sql_mode = …, SET @@sql_mode = …, SET @@SESSION.sql_mode = … her scope’ta reddedilir
SELECT @@sql_mode, SHOW VARIABLES LIKE 'sql_mode' okuma
SET [SESSION|GLOBAL] transaction_read_only = …, tx_read_only, SET @@session.transaction_read_only = …, SET STATEMENT transaction_read_only=0 FOR … her scope’ta reddedilir
SET TRANSACTION READ WRITE, START TRANSACTION READ WRITE, BEGIN READ WRITE reddedilir
SET ROLE …, SET DEFAULT ROLE … reddedilir
USE mysql (PREPARE, EXECUTE IMMEDIATE, SET STATEMENT … FOR içinde de) reddedilir
mysql.… tablosuna INSERT / UPDATE / DELETE / REPLACE (yalnızca okuyan çok tablolu UPDATE / DELETE de reddedilir) reddedilir
Varsayılan veritabanı mysql olan bağlantıda yazma SQL çalışmadan talep başarısız olur; tek ifadeli okumalar geçer
Çalıştırma anında NO_BACKSLASH_ESCAPES ya da ANSI_QUOTES içeren oturum sql_mode’u SQL çalışmadan talep başarısız olur
MariaDB SET STATEMENT … FOR <statement> FOR’dan sonraki ifade kendi kurallarıyla değerlendirilir (WHERE, yasak listesi, …); ifade yoksa reddedilir
SET GLOBAL general_log := 1 (:= öncesinde boşluk) reddedilir
SELECT … INTO @var okuma
SELECT … INTO OUTFILE / INTO DUMPFILE reddedilir
get_lock, release_lock yazma olarak sınıflandırılır
sleep, benchmark yazma olarak sınıflandırılır
load_file reddedilir
PREPARE s FROM '<DML without WHERE>' (WHERE’siz DML) reddedilir
PREPARE s FROM '<DML with WHERE>' (WHERE’li DML) yazma olarak sınıflandırılır
PREPARE s FROM @q (değişken) reddedilir
WHERE’siz WITH x AS (DELETE …) reddedilir
WHERE’siz WITH … DELETE FROM t reddedilir
SELECT 1 DENY … okuma (DENY bir MySQL ifadesi değildir; ; ile ayrılmış ve tek başına biçimleri reddedilir)
Veritabanı tarafında salt okunur transaction kapsanmaz (v0.3.0 için planlandı)
Veritabanı tarafında statement timeout kapsanmaz (v0.3.0 için planlandı)

SQL Server

Yapı Durum
xp_*, sp_configure, sp_oa*, sp_addlinkedserver, sp_addlinkedsrvlogin, sp_serveroption, sp_addextendedproc, sp_execute_external_script (ifade olarak ya da EXEC’ten sonra çağrılan) reddedilir
OPENROWSET, OPENDATASOURCE, OPENQUERY reddedilir
BULK INSERT reddedilir
sp_prepare, sp_prepexec, sp_prepexecrpc, sp_execute, sp_cursoropen, sp_cursorprepare, sp_cursorprepexec, sp_msforeachtable, sp_msforeachdb, sp_msforeach_worker, sp_sqlexec, sp_send_dbmail, sp_add_jobstep, sp_update_jobstep argümanlar ne olursa olsun reddedilir
WHERE’siz EXEC('DELETE FROM t') / EXEC(N'…') reddedilir
EXEC('DELETE FROM t WHERE id = 1') yazma olarak sınıflandırılır
EXEC(@sql), EXEC('a' + 'b'), EXEC(…) AT srv, EXEC … AS USER reddedilir
sp_executesql N'…' (EXEC ile ya da onsuz, ya da @stmt = ile) SQL metni olağan kurallarla değerlendirilir; değişken reddedilir
EXEC('') zararsız, geçer
EXEC('EXEC xp_cmdshell ''dir''') (iç içe sabit) reddedilir
SELECT 'xp_cmdshell' (ad bir string sabitinin içinde) okuma
EXEC dbo.my_proc 1 yazma olarak sınıflandırılır
EXEC "quoted_name", WHERE exec = 1 reddedilir (guard katı tarafta yanılır)
Dinamik SQL içinde BEGIN / COMMIT / ROLLBACK reddedilir
3 seviyeden derin iç içe dinamik SQL reddedilir
SELECT … INTO t2 FROM t yazma (DDL) olarak sınıflandırılır, TOP eklenmez
SELECT * FROM t okuma; TOP (1000) alır
SELECT TOP 99999 … / TOP (99999) okuma, TOP 10000’e çekilir
SELECT TOP 10 PERCENT …, TOP (@v), TOP (5 + 5), TOP (1.5) reddedilir
SELECT * FROM #t WHERE id = 1 (geçici tablolar) okuma
SELECT 1 DELETE FROM t (;’siz batch) reddedilir
SELECT 1 DROP DATABASE x reddedilir
DENY reddedilir
SHUTDOWN reddedilir
THROW, CHECKPOINT, RECONFIGURE, KILL yazma olarak sınıflandırılır
EXECUTE AS …, EXEC AS …, SETUSER, REVERT, EXEC('SETUSER …'), sp_executesql N'EXECUTE AS …' reddedilir
Tanımda WITH EXECUTE AS OWNER|CALLER|SELF|'user' reddedilir
execute_as adlı kolon ya da string literal içinde EXECUTE AS okuma
Veritabanı tarafında salt okunur transaction kapsanmaz (v0.3.0 için planlandı)
Veritabanı tarafında statement timeout kapsanmaz (v0.3.0 için planlandı)

SQLite

Yapı Durum
ATTACH, DETACH reddedilir
VACUUM … INTO reddedilir
VACUUM (tek başına) yazma olarak sınıflandırılır
load_extension( reddedilir
PRAGMA table_info(t) ve izin verilen diğer salt okunur pragma’lar (table_xinfo, index_list, index_info, index_xinfo, foreign_key_list, database_list, table_list, collation_list, function_list, compile_options) okuma
PRAGMA x = …, bir ayar için PRAGMA x(v), listede olmayan her pragma reddedilir
QUERYPROXY_EXTRA_SQLITE_PRAGMAS ile eklenen bir pragma yalnızca çıplak biçimde izinli
EXPLAIN VACUUM INTO '/tmp/x' reddedilir
QUERYPROXY_SQLITE_ALLOWED_DIR dışındaki dosyalar ayar doluyken reddedilir. Ayar boşken uygulama dizini dışındaki her yol kabul edilir ve bağlantı biçimi uyarı gösterir
Uygulama dizini içindeki dosyalar (QueryProxy’nin varsayılan SQLite veritabanı oradadır) ayardan bağımsız olarak her zaman reddedilir
Salt okunur transaction ve statement timeout kapsanmaz (v0.3.0 için planlandı)

Tüm dialect’ler

Yapı Durum
Bir string sabitinin, yorumun ya da dollar-quoted gövdenin içindeki listelenmiş fonksiyon ya da prosedür adı (SELECT 'pg_sleep(1)', SELECT 1 -- dblink() etkilenmez
DESC analyze (adı analyze olan bir tablo) reddedilir (aşırı engelleme)
Sunucuda tanımlı fonksiyonların ve prosedürlerin içindeki kod kapsanmaz
EXECUTE IMMEDIATE '<DML without WHERE>' (WHERE’siz DML) reddedilir
EXECUTE IMMEDIATE '<DML with WHERE>' (WHERE’li DML) yazma olarak sınıflandırılır
EXECUTE IMMEDIATE <variable, expression or concatenation> (değişken, ifade ya da birleştirme) reddedilir
Bilinmeyen bir anahtar kelimeyle başlayan ifade yazma olarak sınıflandırılır

Bilinen sınırlar

Guard her şeyi kapsamaz. Aşağıdaki durumlar bilinir ve olduğu gibi bırakılmıştır. Guard, onayın ya da veritabanı yetkilerinin yerini tutmaz.

  • PostgreSQL katalog adları. Yalnız pg_catalog, pg_toast ve şemasız pg_… adları katalog tablosu sayılır. pg_temp ya da başka bir şemadaki (public.pg_x) tablo kullanıcı tablosu olarak ele alınır.
  • SQLite ve SQL Server. Katalog tablolarına (sqlite_master, sys.…) yazma, katalog kuralının kapsamında değildir.
  • Katalog DDL’i. Katalog kuralı INSERT, UPDATE, DELETE, MERGE ve REPLACE ifadelerini değerlendirir. Katalog tablosu üzerinde TRUNCATE, DROP ve ALTER bu kuralın dışındadır.
  • MySQL ve MariaDB saklı kod. CREATE PROCEDURE, CREATE TRIGGER ya da CREATE EVENT … DO gövdelerindeki SET ifadeleri denetlenmez.
  • MySQL ve MariaDB SET PASSWORD listeleri. Yukarıdaki SET kurallarının hiçbiri (korunan değişkenler, sql_mode, salt okunur anahtarı) bir SET PASSWORD ifadesindeki diğer atamalara uygulanmaz. İfade SET olarak denetlenmez.

Bu sınırlar yüzünden guard tek başına bir güvenlik sınırı değildir. QueryProxy’nin bağlandığı veritabanı kullanıcısına yalnız gereken yetkileri verin (en az yetki ilkesi).

Lehçeler ve temkinli geri düşüş

Parser önce MySQL lehçesini bilir. Tam parse edemediği ifadeler (PostgreSQL ::jsonb cast’leri, sürücüye özgü operatörler) yine anahtar kelime bazında korunur: parse edilemeyen WHERE’siz bir UPDATE yine reddedilir, parse edilemeyen bir SELECT’e yine LIMIT eklenir — sınıflandırılamayan her şey ise yazma sayılır, yani tam onay incelemesinden geçer. QueryProxy tereddütte her zaman katı taraftadır.

Gezinmek için ok tuşları, açmak için Enter.