SQLite'ı güvenli kullanmak için önce elinizdeki riskin türünü belirlemeniz gerekir: dışarıdan gelen SQL metnini mi çalıştırıyorsunuz, yoksa kaynağından emin olmadığınız bir veritabanı dosyasını mı açıyorsunuz? İlk durumda defensive bayrağı, girdi sınırları, yetkilendirme geri çağrısı ve zaman aşımı; ikinci durumda PRAGMA trusted_schema=OFF, açılışta bütünlük denetimi ve cell_size_check önerilir. Komut satırında bilinmeyen bir betiği denemek için ise sqlite3 -safe kipi vardır.
SQLite geliştiricileri, kütüphanenin bozuk ya da kötü niyetli girdilerle karşılaştığında çökmemesini, bellek taşırmamasını ve hatayı düzgünce bildirmesini temel hedef olarak tanımlar; bunun için yoğun fuzz testleri yapılır. Yine de hata olmayan yazılım yoktur. Bu yazıdaki ayarlar, henüz bilinmeyen bir açığa karşı ek bir savunma katmanı sağlar. Tüm örnekler sqlite3 komut satırı aracında çalıştırıldı; uygulama kodundan SQLite kullanıyorsanız aynı pragmaları bağlantıyı açtığınız anda çalıştırabilirsiniz.
İki ayrı tehdit: güvenilmeyen SQL ve güvenilmeyen dosya

Güvenlik belgesi önlemleri iki gruba ayırır. Birinci grup, uygulamanızın kullanıcıdan veya başka bir sistemden gelen SQL ifadelerini olduğu gibi çalıştırdığı durumlar içindir. Örneğin kullanıcıların kendi raporlarını yazabildiği bir panel, eğitim amaçlı bir SQL deneme alanı veya eklentilerin sorgu gönderebildiği bir uygulama bu gruba girer. İkinci grup ise veritabanı dosyasının kendisinin güvenilmez olduğu durumları kapsar: kullanıcının yüklediği bir .db dosyası, e-postayla gelen bir yedek ya da başka bir güvenlik alanındaki bir sürecin yazabildiği bir dosya.
Bu ayrım önemlidir, çünkü bir SQLite dosyası yalnızca veri taşımaz; şemanın içinde görünümler, tetikleyiciler, CHECK kısıtları, varsayılan değer ifadeleri ve ifade indeksleri de bulunur. Siz yalnızca SELECT çalıştırdığınızı düşünürken, dosyanın içine yerleştirilmiş bir görünüm veya tetikleyici sizin bağlantınızda fonksiyon çağırabilir. Belgeye göre, başka bir güvenlik alanındaki bir sürecin bir zamanlar yazabildiği her dosya şüpheli kabul edilmelidir.
Kullanıcı girdisini SQL metnine birleştirerek sorgu oluşturuyorsanız sorun bu yazının kapsamından önce gelir: o durumda çözüm parametreli sorgulardır ve SQL injection önleme yazımızda anlatılıyor. Bu sayfa, SQL metninin bilerek dışarıdan alındığı veya dosyanın kendisinin şüpheli olduğu senaryolara odaklanır.
Güvenilmeyen SQL için defensive bayrağı
Defensive bayrağı açıkken, sıradan SQL ifadelerinin veritabanı dosyasını bilerek bozmasına izin veren özellikler kapatılır. C arayüzündeki açıklamaya göre bu özellikler arasında PRAGMA writable_schema=ON, PRAGMA journal_mode=OFF, PRAGMA schema_version=N, sqlite_dbpage sanal tablosuna yazma ve gölge tablolara doğrudan yazma bulunur. Bayrak C tarafında sqlite3_db_config() ile ayarlanır; komut satırı aracında aynı ayara .dbconfig komutuyla erişebilirsiniz.
Aşağıdaki denemede bayrak açıkken şema tablosunu doğrudan değiştirme girişimi reddedildi. Dikkat edilmesi gereken ikinci nokta, journal_mode=OFF isteğinin hata vermeden yok sayılmasıdır: pragma, değişmeyen günlük kipini (delete) döndürdü. Yani uygulamanız pragmanın sonucunu okumadan değişikliğin yapıldığını varsaymamalıdır.
.dbconfig defensive on
-- çıktı: defensive on
CREATE TABLE t(a);
PRAGMA writable_schema = ON;
UPDATE sqlite_schema SET sql = 'bozuk' WHERE name = 't';
-- hata: table sqlite_master may not be modified
PRAGMA journal_mode = OFF;
-- çıktı: deleteAynı adımları bayrak kapalıyken çalıştırdığımızda şema metni bozuldu ve dosya yeniden açıldığında tabloya artık erişilemedi. Bu deneme, bayrağın neden önemli olduğunu gösterir: dışarıdan SQL kabul eden bir uygulamada tek bir ifade, veritabanını açılamaz hâle getirebilir. Bu örneği yalnızca deneme dosyalarında çalıştırın.
.dbconfig defensive off
-- çıktı: defensive off
CREATE TABLE t(a);
PRAGMA writable_schema = ON;
UPDATE sqlite_schema SET sql = 'bozuk' WHERE name = 't';
.open guv.db
SELECT count(*) FROM t;
-- hata: malformed database schema (t)Kullandığımız komut satırı aracında defensive bayrağı açık geldi; bu, derleme ve sürüme göre değişebilecek bir varsayılandır. Kendi kurulumunuzda .dbconfig komutunu argümansız çalıştırarak tüm bayrakların durumunu görebilirsiniz. Kütüphaneyi kendi uygulamanıza gömdüğünüzde bayrağı açıkça ayarlamak en güvenli yoldur.
Girdi sınırlarını düşürmek

SQLite, metin uzunluğu, sütun sayısı, ifade derinliği, bileşik SELECT terim sayısı ve bağlanabilecek veritabanı sayısı gibi değerler için üst sınırlar uygular. Varsayılan sınırlar çoğu uygulamanın ihtiyacının çok üzerindedir. Güvenlik belgesi, güvenilmeyen SQL çalıştıran uygulamaların bu sınırları ciddi biçimde düşürmesini önerir; böylece aşırı büyük girdilerle hizmet dışı bırakma denemelerinin ve derin özyinelemeyle yığın taşırma girişimlerinin önü kesilir. Sınırlar derleme sırasında -DSQLITE_MAX_... seçenekleriyle veya çalışma anında sqlite3_limit() ile değiştirilebilir. Komut satırında karşılığı .limit komutudur.
.limit attached
-- çıktı: attached 10
.limit attached 0
-- çıktı: attached 0
ATTACH ':memory:' AS ek;
-- hata: too many attached databases - max 0
.limit compound_select 3
-- çıktı: compound_select 3
SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4;
-- hata: too many terms in compound SELECTBelgede yer alan öneri tablosundan bazı satırlar aşağıda. Yüksek güvenlik değerleri bir başlangıç noktasıdır; kendi uygulamanızın gerçekten ihtiyaç duyduğu değerleri ölçerek belirlemelisiniz. Örneğin tablolarınızdan biri 120 sütun içeriyorsa sütun sınırını 100 yapamazsınız. 3.53.0 sürümüyle eklenen LIMIT_PARSER_DEPTH ve 3.54.0 ile eklenen LIMIT_SCHEMA da bu listede yer alır.
| Sınır | Varsayılan | Yüksek güvenlik önerisi |
|---|---|---|
| LIMIT_LENGTH | 1.000.000.000 | 1.000.000 |
| LIMIT_SQL_LENGTH | 1.000.000.000 | 100.000 |
| LIMIT_COLUMN | 2.000 | 100 |
| LIMIT_EXPR_DEPTH | 1.000 | 10 |
| LIMIT_PARSER_DEPTH | 2.500 | 100 |
| LIMIT_COMPOUND_SELECT | 500 | 3 |
| LIMIT_ATTACH | 10 | 0 |
| LIMIT_LIKE_PATTERN_LENGTH | 50.000 | 50 |
| LIMIT_VARIABLE_NUMBER | 999 | 10 |
| LIMIT_TRIGGER_DEPTH | 1.000 | 10 |
Belge ayrıca yığın alanı kısıtlı işlemcilerde LIMIT_EXPR_DEPTH ve LIMIT_TRIGGER_DEPTH değerlerinin 10 gibi küçük sayılara çekilmesini özellikle vurgular. Sınırların yanında, C arayüzünde birkaç önlem daha önerilir: şemayı değiştirmesi gerekmeyen bir uygulamada sqlite3_set_authorizer() ile CREATE ve DROP ifadelerini reddetmek, sqlite3_progress_handler() veya sqlite3_interrupt() ile çok uzun süren sorguları kesmek ve sqlite3_hard_heap_limit64() ile bellek tüketimine tavan koymak. Bunlar dil bağlayıcınızın sunduğu ölçüde kullanılabilir; Python, Node.js ve PHP tarafı için Python sqlite3, Node.js node:sqlite ve PHP PDO yazılarına bakabilirsiniz.
Güvenilmeyen dosyalar için trusted_schema
trusted_schema ayarı bağlantıya özeldir ve güvenlik denetiminden geçmemiş SQL fonksiyonlarının ve sanal tabloların şemanın içinden, yani görünümlerden, tetikleyicilerden, CHECK kısıtlarından, DEFAULT ifadelerinden, hesaplanan sütunlardan, ifade indekslerinden ve kısmi indekslerden çalıştırılıp çalıştırılamayacağını belirler. Geriye dönük uyumluluk nedeniyle kütüphanenin varsayılanı açıktır, ancak belge tüm uygulamaların bu ayarı her bağlantı açıldığında kapatmasını önerir; çoğu uygulama bundan etkilenmez. -DSQLITE_TRUSTED_SCHEMA=0 derleme seçeneği varsayılanı kapalıya çevirir.
Bizim denemelerimizde komut satırı aracı ayarı kapalı (0), standart derlemeyle çalışan 3.45.3 sürümü ise açık (1) olarak raporladı. Bu fark, varsayılan değere güvenmek yerine ayarı her bağlantıda açıkça yazmanız için iyi bir gerekçedir. Aşağıdaki örnekte komut satırına özgü writefile() fonksiyonunu çağıran bir görünüm, ayar kapalıyken reddedilirken aynı fonksiyonun doğrudan çağrılması çalıştı:
-- Kötü niyetli bir dosyada hazır bekleyen görünüm
CREATE VIEW tuzak AS SELECT writefile('tuzak.txt', 'gizli veri') AS n;
PRAGMA trusted_schema = OFF;
PRAGMA trusted_schema;
-- çıktı: 0
SELECT * FROM tuzak;
-- hata: unsafe use of writefile()
-- Aynı fonksiyonu doğrudan çağırmak serbesttir (yazılan bayt sayısı döner)
SELECT writefile('dogrudan.txt', 'abc');
-- çıktı: 3Bu davranış, kötü niyetli bir dosyanın içine gizlenmiş bir görünümün siz farkında olmadan dosya sistemine yazmasını engeller. Kendi uygulamanızda yan etkisi olan veya gizli bilgi döndüren özel SQL fonksiyonlarınız ya da sanal tablolarınız varsa belge şu yollardan en az birini önerir: trusted_schema ayarını kapatmak, bu fonksiyonları SQLITE_DIRECTONLY bayrağıyla, sanal tabloları SQLITE_VTAB_DIRECTONLY bayrağıyla kaydetmek ve şemadaki argümanlara göre SQL hazırlayan sanal tablolarda 3.53.0 ile gelen SQLITE_PREPARE_FROM_DDL seçeneğini kullanmak. Uygulamanız tetikleyici veya görünüm kullanmıyorsa bu özellikleri sqlite3_db_config() ile tamamen kapatmak da mümkündür.
Ek savunma katmanları: bütünlük denetimi, cell_size_check, mmap
Güvenlik açısından hassas uygulamalar için belge, performans maliyeti olan üç ek önlem sayar. Birincisi, dosyayı açtıktan hemen sonra ve başka hiçbir SQL çalıştırmadan önce PRAGMA integrity_check veya PRAGMA quick_check çalıştırmak ve hata bulunan dosyayı işlemeyi reddetmektir. İkincisi PRAGMA cell_size_check=ON ayarıdır: B-tree sayfaları diskten ilk okunduğunda ek tutarlılık denetimi yapılır, bozulma daha erken fark edilir ve yayılma olasılığı azalır. Küçük bir performans bedeli olduğu için varsayılan olarak kapalıdır. Üçüncüsü bellek eşlemeli G/Ç kullanmamak, yani PRAGMA mmap_size=0 ile çalışmaktır.
PRAGMA cell_size_check = ON;
PRAGMA cell_size_check;
-- çıktı: 1
PRAGMA quick_check;
-- çıktı: ok
PRAGMA query_only = ON;
CREATE TABLE t(a);
-- hata: attempt to write a readonly database
PRAGMA query_only = OFF;
CREATE TABLE t(a);Örnekteki query_only ayarı da sık sorulan bir araçtır: açıkken CREATE, DELETE, DROP, INSERT ve UPDATE girişimleri SQLITE_READONLY hatasıyla reddedilir. Ancak belge bu ayarın veritabanını gerçekten salt okunur yapmadığını belirtir; checkpoint ve COMMIT yine çalışabilir. Gerçek salt okunur erişim için dosyayı salt okunur kipte açmak daha doğrudur. Bütünlük denetiminin ayrıntıları bozuk veritabanı kurtarma yazısında, pragmaların genel kullanımı PRAGMA komutları yazısında anlatılıyor.
Komut satırında --safe kipi
Bilinmeyen bir kaynaktan büyük bir SQL betiği aldığınızı ve ne yaptığını görmek istediğinizi düşünün. --safe seçeneği, komut satırında belirttiğiniz veritabanı dosyası dışında ana makinede değişiklik yapabilecek özellikleri kapatmaya çalışır. Belgeye göre kapatılanlar arasında .open (yalnızca :memory: veya --hexdb ile izinli), ATTACH, edit(), load_extension(), readfile(), writefile() gibi yan etkili fonksiyonlar, .archive, .backup, .save, .import, .load, .log, .shell, .system, .excel, .once ve .output bulunur. Kısacası ana veritabanı dosyası dışındaki diskteki dosyaları okuyan veya yazan her şey engellenir.
sqlite3 -safe gelen.db < bilinmeyen_betik.sql
sqlite3 -readonly -safe gelen.db # dosyayı yalnızca okumak için aç
sqlite3 -nofollow uygulama.db # sembolik bağlantıyı reddetDenememizde, güvenli kipte yasaklı bir komuta gelindiğinde araç hata mesajı yazdı ve betiğin kalanını çalıştırmadan 1 çıkış koduyla sonlandı. Bu, betiğin yasaklı adımdan sonraki kısmının hiç denenmediği anlamına gelir; sonucu değerlendirirken bunu göz önünde bulundurun.
-- sqlite3 -safe :memory: < betik.sql ile çalıştırıldı
CREATE TABLE t(a);
INSERT INTO t VALUES (1);
SELECT count(*) FROM t;
-- çıktı: 1
ATTACH 'baska.db' AS b;
-- hata: cannot run ATTACH in safe mode
-- (betik burada durur, sonraki satırlar çalışmaz, çıkış kodu 1)Her yasaklı işlem kendine özgü bir mesaj üretir. Aşağıdaki satırları ayrı ayrı denediğimizde şu mesajları aldık:
.output sizinti.txt
-- hata: cannot run .output in safe mode
SELECT writefile('disari.txt', 'veri');
-- hata: cannot use the writefile() function in safe mode
.shell echo merhaba
-- hata: cannot run .shell in safe mode
.open baska.db
-- hata: cannot open disk-based database files in safe modeBazen şüpheli bir betiğin tek bir ek veritabanı bağlaması veya belirli bir eklentiyi yüklemesi gerekir. Bu durumda --nonce seçeneğiyle uzun ve rastgele bir değer verip, dikkatle incelediğiniz komutun hemen önüne aynı değerle .nonce yazabilirsiniz. İzin yalnızca bir sonraki SQL ifadesi veya nokta komutu için geçerlidir; denememizde ikinci ATTACH yine reddedildi. Belge bu mekanizmanın tehlikeli olabileceğini, yalnızca başka yol kalmadığında ve az sayıda komut için kullanılması gerektiğini vurgular.
-- sqlite3 -safe -nonce Kx93-uzun-rastgele-deger-7Qp :memory: < betik.sql
.nonce Kx93-uzun-rastgele-deger-7Qp
ATTACH ':memory:' AS ek;
SELECT name FROM pragma_database_list ORDER BY seq;
-- çıktı:
-- main
-- ek
ATTACH ':memory:' AS ek2;
-- hata: cannot run ATTACH in safe modeKomut satırı seçeneklerinin tamamı için SQLite kurulumu ve sqlite3 komut satırı, nokta komutlarının kuralları için CLI nokta komutları yazısına bakabilirsiniz.
Sunucuda dosya, dizin ve izinler
SQLite bir sunucu süreci değil, sıradan bir dosyadır; bu yüzden erişim denetiminin büyük kısmı işletim sisteminin dosya izinlerine kalır. Veritabanı dosyasını okuyabilen her süreç tüm veriyi okuyabilir, yazabilen her süreç dosyayı bozabilir. Belge, herhangi bir sürecin dosyayı açıp üzerine çöp yazabileceğini ve kütüphanenin buna karşı yapabileceği bir şey olmadığını açıkça söyler. Bu nedenle veritabanını yalnızca uygulamanızın kullanıcı hesabının erişebileceği bir dizinde tutun ve web sunucusunun dışarıya dosya olarak sunduğu klasörlere koymayın.
Yalnızca ana dosyayı düşünmek yetmez. Yazma işlemi sırasında aynı dizinde -journal veya WAL kipinde -wal ve -shm dosyaları oluşur. Süreç dizine dosya oluşturamıyorsa yazma SQLITE_READONLY_DIRECTORY ile başarısız olur. WAL kipinde salt okunur erişim için de belge üç koşuldan birinin sağlanmasını ister: -shm ve -wal dosyalarının zaten var ve okunabilir olması, dizinde yazma izni bulunması ya da bağlantının immutable parametresiyle açılması. Yardımcı dosyaların izinleri ana dosyayla tutarlı olmalıdır; aksi hâlde bir kullanıcı hesabıyla oluşan -shm dosyasını diğer hesap kullanamayabilir. Ayrıntılar WAL modu yazısında.
Son olarak veritabanını ağ dosya sistemine değil, yerel diske koyun. Ağ dosya sistemlerinde kilitleme ve senkronizasyon davranışı kurulumdan kuruluma değişir ve belge bunun bozulmaya yol açtığı vakaları anlatır. Uygulamanız kullanıcının seçtiği bir yolu açıyorsa sembolik bağlantılara dikkat edin: komut satırında -nofollow seçeneği sembolik bağlantı olan veritabanı dosyalarını açmayı reddeder; C arayüzünde SQLITE_OPEN_NOFOLLOW bayrağıyla açılan bir dosya sembolik bağlantıysa açılış SQLITE_CANTOPEN_SYMLINK koduyla başarısız olur.
Ayarların özeti
| Ayar | Ne işe yarar | Nerede ayarlanır |
|---|---|---|
| defensive | Sıradan SQL ile dosyayı bilerek bozmayı engeller | sqlite3_db_config, CLI .dbconfig |
| trusted_schema=OFF | Şemadaki görünüm ve tetikleyicilerin denetlenmemiş fonksiyon çağırmasını engeller | PRAGMA, her bağlantıda |
| Girdi sınırları | Aşırı büyük veya derin girdileri reddeder | sqlite3_limit, CLI .limit |
| cell_size_check=ON | Sayfa okunurken ek tutarlılık denetimi | PRAGMA |
| integrity_check / quick_check | Açılışta bozuk dosyayı yakalar | PRAGMA, ilk ifade olarak |
| mmap_size=0 | Bellek eşlemeli G/Ç kullanılmaz | PRAGMA |
| query_only=ON | Yazma ifadelerini reddeder, tam salt okunur değildir | PRAGMA |
| -safe | CLI betiklerinin ana dosya dışına dokunmasını engeller | sqlite3 komut satırı seçeneği |
Sık yapılan hatalar

- Varsayılanlara güvenmek: trusted_schema ve defensive değerleri derlemeye göre farklı gelebilir. Her bağlantıda açıkça ayarlayın ve gerekirse okuyarak doğrulayın.
- Pragmanın sonucunu okumamak: Defensive açıkken
journal_mode=OFFhata vermeden yok sayılır. Ayar pragmalarının döndürdüğü değeri kontrol edin. - Yalnızca SELECT çalıştırdığı için dosyayı güvenli saymak: Görünümler ve tetikleyiciler okuma sırasında da çalışır. Şüpheli dosyalarda trusted_schema kapalı olmalıdır.
- query_only ayarını izin sistemi sanmak: Bu ayar yalnızca bağlantı düzeyinde bir koruma sağlar; dosya izinlerinin yerini tutmaz.
- --safe çıktısını eksik okumak: Güvenli kip ilk yasaklı komutta betiği durdurur; geri kalan adımlar hiç çalışmamış olabilir.
- Veritabanını web kök dizinine koymak: Dosya doğrudan indirilebilir hâle gelir. Uygulama verisini sunulan klasörlerin dışında tutun.
Sık Sorulan Sorular
SQLite'ta kullanıcı ve parola tanımlanabilir mi?
SQLite bir istemci-sunucu veritabanı olmadığı için yerleşik kullanıcı hesabı sistemi sunmaz; erişim, dosyayı açabilen süreçle sınırlıdır. Yetkilendirme ihtiyacını işletim sistemi izinleri ve uygulamanızın kendi mantığıyla karşılarsınız. Genel mimari farklar için SQLite nedir yazısına bakabilirsiniz.
trusted_schema kapatılınca uygulamam bozulur mu?
Belgeye göre çoğu uygulama etkilenmez. Etkilenecek olanlar, şemanın içinden yan etkili özel fonksiyon veya sanal tablo çağıranlardır. Bu durumda ilgili fonksiyonları güvenli olarak işaretlemek ya da çağrıyı şemadan uygulama koduna taşımak gerekir.
--safe kipi bir betiği tamamen zararsız hâle getirir mi?
Hayır. Güvenli kip ana makinedeki diğer dosyaları korur, ancak komut satırında verdiğiniz veritabanı dosyası üzerinde betik istediği değişikliği yapabilir. Asıl dosyanızı korumak için betiği bir kopya üzerinde veya :memory: ile deneyin, yalnızca okumak istiyorsanız -readonly ekleyin.
Kullanıcının yüklediği bir .db dosyasını nasıl açmalıyım?
Dosyayı ayrı bir dizine kaydedin, bağlantıyı açar açmaz trusted_schema ayarını kapatın, ilk ifade olarak quick_check veya integrity_check çalıştırıp hata varsa reddedin, cell_size_check ayarını açın ve mmap_size değerini 0 bırakın. Bu adımlar belgedeki önerilerin doğrudan karşılığıdır.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: SQLite öğrenme rehberi · SQLite bozuk veritabanı kurtarma · SQLite PRAGMA komutları · SQLite CLI nokta komutları · SQLite ATTACH DATABASE · SQL injection önleme