Keamanan database bukan satu saklar besar, melainkan tumpukan kebiasaan konfigurasi yang kecil. Chapter penutup section ini mengumpulkan praktik yang bisa diterapkan langsung: menjalankan aplikasi dengan hak akses minimal, membuka database dalam mode baca-saja saat memungkinkan, mengutip URI filename dengan benar, dan memperlakukan berkas SQL dari luar sebagai kode yang tidak dipercaya.

Hak Akses Minimal: Baca-Saja Bila Bisa #

Prinsip pertama: aplikasi hanya butuh izin yang benar-benar dipakainya. Aplikasi pembaca laporan tidak perlu hak menulis, jadi jangan berikan. Ada dua mekanisme baca-saja pada SQLite — keduanya diuji pada toko.db baru (jalankan rm -f toko.db* lebih dulu bila melanjutkan dari chapter sebelumnya) dengan tabel pelanggan berikut:

sql
CREATE TABLE pelanggan (
  id INTEGER PRIMARY KEY,
  nama TEXT NOT NULL,
  email TEXT NOT NULL
);

INSERT INTO pelanggan VALUES
  (1, 'Budi', '[email protected]'),
  (2, 'Siti', '[email protected]'),
  (3, 'Ani', '[email protected]');
MekanismeTingkat kerjaBerlaku untuk
file:...?mode=ro (URI)Pembukaan berkas oleh sistem operasiSeluruh isi koneksi, sejak awal
PRAGMA query_only = ONEngine SQLite per koneksiSemua usaha INSERT, UPDATE, DELETE, hingga CREATE

URI mode=ro membuat open() berlangsung tanpa hak tulis — percobaan menulis langsung ditolak:

bash
sqlite3 'file:toko.db?mode=ro' "SELECT id, nama FROM pelanggan WHERE id = 1;"
sqlite3 'file:toko.db?mode=ro' "INSERT INTO pelanggan VALUES (5, 'Rina', '[email protected]');"

Output yang Dihasilkan:

text
1|Budi
Error: stepping, attempt to write a readonly database (8)

PRAGMA query_only dipasang setelah koneksi terbuka — cocok untuk sesi CLI yang sengaja dibatasi:

text
sqlite> PRAGMA query_only = ON;
sqlite> SELECT id, nama FROM pelanggan WHERE id = 1;
1|Budi
sqlite> INSERT INTO pelanggan VALUES (5, 'Rina', '[email protected]');
Runtime error: attempt to write a readonly database (8)
sqlite> PRAGMA query_only;
1

Di luar dua mekanisme itu, kebiasaan yang sama berlaku di tingkat sistem operasi: jalankan aplikasi dengan akun sistem khusus — bukan akun root dan bukan akun login Anda — lalu chown berkas database ke akun itu dengan izin 600, seperti dibahas pada Chapter Keamanan Berkas Database.

URI Filename Harus Dikutip #

URI filename menggabungkan parameter dengan karakter ? dan &, dan keduanya adalah karakter khusus shell. Tanpa tanda kutip, ? bisa ikut memicu globbing nama berkas; & lebih buruk lagi — shell memotong perintah di titik itu dan menjalankan sisanya sebagai perintah latar belakang. Selalu bungkus URI dalam satu pasang tanda kutip:

bash
sqlite3 'file:toko.db?mode=ro' "SELECT COUNT(*) FROM pelanggan;"

Parameter bisa dirangkai, misalnya 'file:toko.db?mode=ro&cache=private' — dengan syarat seluruh string tetap berada di dalam tanda kutip.

immutable=1 Menjanjikan yang Tak Bisa Ditepati #

Parameter URI immutable=1 menyatakan janji: “berkas ini tidak pernah berubah selama koneksi hidup”. Engine SQLite merespons dengan menghapus seluruh penguncian dan pengecekan — tidak ada lock, tidak ada pemeriksaan konsistensi terhadap perubahan. Bila janji itu dilanggar, pembaca mendapat data basi tanpa peringatan:

bash
( echo "SELECT COUNT(*) AS jumlah FROM pelanggan;";
  sleep 2
  echo "SELECT COUNT(*) AS jumlah FROM pelanggan;" ) | sqlite3 'file:toko.db?immutable=1' &
sleep 1
echo "--- penulis menambah satu baris ---"
sqlite3 toko.db "INSERT INTO pelanggan VALUES (4, 'Tono', '[email protected]');"
wait
echo "--- pembaca normal membuka ulang ---"
sqlite3 toko.db "SELECT COUNT(*) AS jumlah FROM pelanggan;"

Output yang Dihasilkan:

text
3
--- penulis menambah satu baris ---
3
--- pembaca normal membuka ulang ---
4

Koneksi immutable=1 membaca jumlah 3 dua kali — halaman-halaman berkas sudah dimuat di memori dan engine SQLite tidak pernah membacanya ulang. Koneksi normal yang membuka ulang melihat kenyataannya: 4 baris.

Batas Kepercayaan: .read dan .import #

Perintah .read berkas.sql di CLI menjalankan isi berkas itu sebagai SQL — dan isi berkas tersebut tidak terbatas pada query. Berkas SQL bisa memuat dot command, termasuk .shell yang menjalankan perintah sistem operasi. Simpan berkas berikut sebagai berkas-tak-dipercaya.sql:

sql
-- berkas SQL dari sumber tak dikenal
CREATE TABLE demo_t (x);
.shell echo perintah-sistem-berhasil-dijalankan

Lalu baca berkas itu dari CLI:

text
sqlite> .read berkas-tak-dipercaya.sql
perintah-sistem-berhasil-dijalankan

Satu baris .shell tadi menjalankan echo — pada berkas dari pihak tak dikenal, isinya bisa jadi bukan echo. Perlakukan berkas .sql seperti kode program: jangan di-.read atau .import dari sumber yang tidak Anda kendalikan, dan jalankan CLI dengan akun berhak minimal agar dampaknya terbatas.

trusted_schema dan Fungsi Berbahaya #

Skema database — view, trigger, generated columns — dapat memanggil fungsi SQL, dan sebagian fungsi itu berbahaya bila dijalankan dari dalam skema (misalnya fungsi yang menulis berkas). Sejak SQLite 3.31, pragma trusted_schema mengendalikan hal tersebut dan bawaannya sudah ketat:

bash
sqlite3 toko.db "PRAGMA trusted_schema;"

Output yang Dihasilkan:

text
0

Nilai 0 berarti fungsi berbahaya tidak boleh dipanggil dari dalam skema. Nilai bawaan ini sengaja aman; mengaktifkan trusted_schema = 1 hanya pantas untuk database lama yang skemanya memang membutuhkannya, dan sebaiknya dibatasi pada koneksi pemulihan saja.

Checklist Produksi #

Semua pembahasan section ini terangkum dalam daftar periksa berikut:

ItemRingkasan
Izin berkas600 untuk berkas utama, audit pola toko.db* termasuk -wal dan -journal
Akun aplikasiAkun sistem khusus; tidak pernah root; baca-saja bila aplikasinya hanya membaca
LokasiDi luar webroot; jauh dari folder sinkronisasi cloud
InjeksiParameter untuk semua input pengguna; ESCAPE untuk pola LIKE
EnkripsiPutuskan berdasarkan model ancaman: disk, backup, atau database itu sendiri
BackupIzin ketat, enkripsi untuk salinan yang keluar dari mesin
Berkas SQL luarTidak di-.read/.import tanpa peninjauan; berpotongan dengan .shell
PRAGMAtrusted_schema tetap 0; query_only untuk sesi baca-saja

Checklist ini bukan sekali jalan. Setiap kali aplikasi bertambah fitur — tabel baru, kolom sensitif, lokasi backup baru — jalankan ulang daftarnya dan tanyakan satu hal: bila berkas ini jatuh ke tangan yang salah, apa yang mereka dapat?