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
LIMITyok 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 ONLYve T-SQLTOP nde aynı şekilde sınırlanır.- SQL Server hedeflerine
LIMITeklenmez (geçerli T-SQL değildir); guard bunun yerineTOPüzerinde çalışır. Mevcut birTOP n/TOP (n)üst sınıra (10000) çekilir;TOPiçermeyen bir üst düzey SELECT ise varsayılan değer olanTOP (1000)’i, varsaDISTINCT/ALL’dan sonra alır.TOP … PERCENT,TOP (@v), ifadeler ve ondalıklar reddedilir.WITH,OFFSET,UNION,EXCEPTveINTERSECTiçinTOPeklenmez; 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 SCHEMAGRANT,REVOKE,DENYCREATE USER/ALTER USER/DROP USER(veROLE/LOGINtürevleri)CREATE FUNCTION … SONAME— yüklenebilir UDF’ler (veCREATE AGGREGATE FUNCTIONkarşılığı)SHUTDOWN- Sunucu tarafı dosya / program IO:
SELECT … INTO OUTFILE/INTO DUMPFILE,LOAD DATA, PostgreSQLCOPY(COPY … TO PROGRAMdahil),LOAD_FILE()fonksiyonu ve PostgreSQL’in dosya fonksiyonlarıpg_read_file(),pg_read_binary_file(),pg_ls_dir(),lo_import()velo_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*veconnectby.
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
plpgsqlvesqldilleri kabul edilir.LANGUAGEmaddesi olmayan birDObloğu PostgreSQL varsayılanı olanplpgsqlile çalışır;CREATE FUNCTION/PROCEDUREise SQL-standard birRETURNgövdesi yoksa açık birLANGUAGE plpgsqlya dasqlgerektirir. 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ıylaLANGUAGE "PLPGSQL"reddedilir.CREATE LANGUAGEveALTER LANGUAGE … RENAMEde 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. TriggerEXECUTE FUNCTION|PROCEDUREmaddeleri bundan etkilenmez. BEGIN ATOMICgövdeleri ve gövdesizCREATE FUNCTION/CREATE PROCEDUREreddedilir.- Bir rutin (
CREATE/ALTER FUNCTION|PROCEDURE … SET), bir veritabanı (ALTER DATABASE … SET) ya da bir rol (ALTER ROLE|USER … SET) üzerindekiSETmaddesi 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,PERSISTvePERSIST_ONLY; hem anahtar kelimeli (SET GLOBAL x = …) hem de değişken yazımında (SET @@GLOBAL.x = …). BirSESSIONyazması,sql_modeve salt okunur anahtarı hariç (aşağıya bakın), korunmaz;@namebir 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_ESCAPESveANSI_QUOTESters eğik çizginin ve çift tırnağın ne anlama geldiğini değiştirir; guard bunu izleyemez, bu yüzdenSET sql_mode,SET SESSION sql_mode,SET @@sql_modeveset_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 MariaDBSET ROLE/SET DEFAULT ROLE, ayrıcaset_config('role', …)/set_config('session_authorization', …).rolevesession_authorizationkorunan ayarların yerleşik listesindedir. ALTER SYSTEM, PostgreSQL’de neyi ayarlarsa ayarlasın.- Sistem kataloğuna yazma. PostgreSQL’de
pg_catalog,pg_toastvepg_…tablolarınaINSERT,UPDATE,DELETEveMERGE; MySQL ve MariaDB’demysqlşemasına aynı ifadeler veREPLACE. Nitelikli ve tırnaklı yazımlar kapsanır. Kural yazma hedefine bakar; bu yüzdenUPDATE t SET … FROM pg_procveINSERT INTO t SELECT … FROM pg_procgeçer. MySQL ve MariaDB’de birmysql.*tablosunu yalnızca okuyan çok tabloluUPDATE/DELETEde 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’deUSE mysqlde reddedilir (PREPARE,EXECUTE IMMEDIATEveSET STATEMENT … FORiçinde de); şemasız bir ad katalogda çözülmesin diye. READ WRITE:SET TRANSACTION,SET SESSION CHARACTERISTICS,BEGINveSTART TRANSACTIONiçinde.READ ONLYgeçer.- MySQL / MariaDB salt okunur anahtarı.
transaction_read_onlyya datx_read_onlyyazmak her scope’ta ve her yazımda reddedilir (SESSION,GLOBAL,@@,@@session., backtick, liste içinde,SET STATEMENT).transaction_isolationveSET TRANSACTION READ ONLYgeçer. Bazı ifadeler bunun için denetlenmez; bkz. Bilinen sınırlar. - PostgreSQL
ALTER DATABASE|ROLE|USER … RESETile korunan bir ayarın ya daALL’un sıfırlanması; ayrıcaCREATE [OR REPLACE] RULE … DO [ALSO|INSTEAD] <eylem>kuralının eylemi, tek başına gönderilen bir ifadeyle aynı kurallarla değerlendirilir.DOeylemini guard’ın bulamadığı kural reddedilir. - SQL Server kimlik taklidi.
EXECUTE AS,EXEC AS,SETUSERveREVERT;EXEC('…')vesp_executesqliçinde de, ayrıca nesne tanımlarındakiWITH EXECUTE AS.execute_asadlı bir kolon ve string literal içindeki aynı sözcükler etkilenmez. - Varsayılan veritabanı
mysqlolan bir bağlantıda MySQL / MariaDB yazması. Şemasız bir tablo adı oturumun varsayılan veritabanına göre çözülür; varsayılanmysqliseUPDATE user SET …hesap tablosunu düzenlerdi. Executor, yazmanın ilk ifadesinden önce bağlantıdaDATABASE()değerini okur ve sonuçmysqlise 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 … */).mariadbdriver’ında gövde SQL olarak okunur ve 3 seviyeden derin iç içe geçme reddedilir.mysqldriver’ında/*M!düz bir yorum olarak kalır; bu yüzden bir MariaDB sunucusunumariadbdriver’ıyla bağlayın. Hedef veritabanı bilinmediğinde/*M!doğrudan reddedilir. mysqlvemariadbdriver’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_modedeğerini okur veNO_BACKSLASH_ESCAPESya daANSI_QUOTESiç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ı birsql_modeayarlar; 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çimliU&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_toastve şemasızpg_…adları katalog tablosu sayılır.pg_tempya 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,MERGEveREPLACEifadelerini değerlendirir. Katalog tablosu üzerindeTRUNCATE,DROPveALTERbu kuralın dışındadır. - MySQL ve MariaDB saklı kod.
CREATE PROCEDURE,CREATE TRIGGERya daCREATE EVENT … DOgövdelerindekiSETifadeleri denetlenmez. - MySQL ve MariaDB
SET PASSWORDlisteleri. YukarıdakiSETkurallarının hiçbiri (korunan değişkenler,sql_mode, salt okunur anahtarı) birSET PASSWORDifadesindeki diğer atamalara uygulanmaz. İfadeSETolarak 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.