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:
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]');| Mekanisme | Tingkat kerja | Berlaku untuk |
|---|---|---|
file:...?mode=ro (URI) | Pembukaan berkas oleh sistem operasi | Seluruh isi koneksi, sejak awal |
PRAGMA query_only = ON | Engine SQLite per koneksi | Semua usaha INSERT, UPDATE, DELETE, hingga CREATE |
URI mode=ro membuat open() berlangsung tanpa hak tulis — percobaan menulis langsung ditolak:
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:
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:
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;
1Di 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:
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:
( 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:
3
--- penulis menambah satu baris ---
3
--- pembaca normal membuka ulang ---
4Koneksi 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:
-- berkas SQL dari sumber tak dikenal
CREATE TABLE demo_t (x);
.shell echo perintah-sistem-berhasil-dijalankanLalu baca berkas itu dari CLI:
sqlite> .read berkas-tak-dipercaya.sql
perintah-sistem-berhasil-dijalankanSatu 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:
sqlite3 toko.db "PRAGMA trusted_schema;"Output yang Dihasilkan:
0Nilai 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:
| Item | Ringkasan |
|---|---|
| Izin berkas | 600 untuk berkas utama, audit pola toko.db* termasuk -wal dan -journal |
| Akun aplikasi | Akun sistem khusus; tidak pernah root; baca-saja bila aplikasinya hanya membaca |
| Lokasi | Di luar webroot; jauh dari folder sinkronisasi cloud |
| Injeksi | Parameter untuk semua input pengguna; ESCAPE untuk pola LIKE |
| Enkripsi | Putuskan berdasarkan model ancaman: disk, backup, atau database itu sendiri |
| Backup | Izin ketat, enkripsi untuk salinan yang keluar dari mesin |
| Berkas SQL luar | Tidak di-.read/.import tanpa peninjauan; berpotongan dengan .shell |
| PRAGMA | trusted_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?