Enkripsi SQlite DB sederhana

Kebetulan saya sangat suka menggunakan SQLite DBMS.


Saat pemrograman dalam assembler, saya terkadang membutuhkan DBMS yang lengkap. Program saya jarang melebihi beberapa ratus kilobyte. Jelas bahwa menggunakan DBMS beberapa ratus megabyte dengan itu setidaknya konyol, tetapi pada akhirnya sangat tidak nyaman - persyaratan perangkat keras dan kompleksitas instalasi dan konfigurasi segera meningkat, dan sebagai hasilnya, keandalan seluruh sistem menurun.


SQLite adalah masalah yang sangat berbeda. Pertama, ini kecil - hanya beberapa ratus kilobyte, tambahan yang bagus untuk program assembler kompak. Kedua, ini adalah sistem penyimpanan data yang sangat andal. Dia tidak membutuhkan pengaturan dan pengaturan khusus. Nah, seperti untuk kinerja - bukan yang terakhir.


Sebagai contoh, saya menggunakan SQLite di mesin forum AsmBB saya yang sudah saya tulis di HabrΓ©. (Ngomong-ngomong, setelah itu dia tidak jatuh ).


Sejak saat itu, proyek ini perlahan namun pasti berkembang. Fitur-fitur baru telah muncul, meningkatkan keamanan dan kinerja.


Dan kemudian suatu hari saya berpikir tentang bagaimana meningkatkan keamanan proyek yang sudah baik. Dan saya langsung berpikir bahwa akan menyenangkan untuk mengenkripsi basis data forum. Memang, bahkan jika database bocor, tidak ada yang akan mendapatkan akses ke data pribadi pengguna.


Pencarian cepat di Internet menunjukkan bahwa ada beberapa ekstensi SQLite untuk enkripsi basis data. Sayangnya, ekstensi SEE resmi tidak gratis dan umumnya dijual untuk mendapatkan uang.


Tapi, tentu saja, tempat suci tidak pernah kosong dan saya langsung menemukan ekstensi SQLeet . Dan di dalamnya aku benar-benar menyukai segalanya.


SQLeet menggunakan algoritma ChaCha20 untuk mengenkripsi basis data. Kunci enkripsi dihitung melalui PBKDF2-HMAC-SHA256 menggunakan garam 16-byte dan 12345 iterasi hash. Untuk otentikasi, Poly1305 digunakan.


Baik SQLeet dan SQLite didistribusikan di bawah domain publik (domain publik). Ini nyaman karena tidak meningkatkan kekacauan lisensi dalam proyek.


SQLeet masih sangat ringkas. Semua kode hanya membutuhkan sekitar satu setengah ribu baris dalam C dan tidak memiliki dependensi eksternal.


Proyek ini didukung secara aktif dan penulis segera menjawab pertanyaan dan memperbaiki bug, jika ada.


SQLeet didistribusikan dengan cara yang sama seperti SQLite - dalam bentuk file sumber C tunggal yang dapat Anda kompilasi dengan cara yang sama seperti yang dikompilasi oleh SQLite.


Selain itu, karena ekstensi tidak mengubah kode SQLite dengan cara apa pun, memperbarui DBMS utama dapat dilakukan dengan sangat sederhana - dengan mengganti file sqlite3.c dan menciptakan kembali sumber gabungan.


Karena saya menggunakan kompilasi tidak cukup standar di AsmBB (SQLite di AsmBB dikompilasi melalui MUSL libc ), dan saya bukan programmer C, bagi saya kesederhanaan kompilasi sangat penting.


Misalnya, inilah kode bash yang saya gunakan untuk mengunduh SQLeet versi terbaru dan membuat dan membangun sumber:


 wget -q -O - https://github.com/resilar/sqleet/archive/master.tar.gz | tar -xz cd ./sqleet-master script/amalgamate.sh < ./sqleet.c > ../sqlite3.c cd .. rm -rf ./sqleet-master/ 

Hasilnya adalah file sqlite3.c yang dapat dimasukkan di mana file SQLite asli dimasukkan sebelumnya dan digunakan dengan cara yang sama.


Menggunakan ekstensi juga tidak berbeda dengan menggunakan SQLite. Satu-satunya perbedaan adalah bahwa jika database dienkripsi, maka segera setelah membuka perlu untuk memanggil fungsi sqlite3_key (), di mana Anda menentukan kata sandi enkripsi. Baik, atau bahkan lebih baik, jalankan saja SQL pragma key='%%' . (Ini lebih baik karena API SQLite tidak berubah dan
Anda selalu dapat mengganti SQLeet dengan SQLite dan sebaliknya).


Enkripsi basis data awal, serta penggantian kata sandi, terjadi melalui fungsi atau pragma sqlite3_rekey() dengan pragma rekey='%NEW_PASSWORD%' .


Dan di sini saya punya pertanyaan seperti itu. Dari mana kata sandi itu berasal? Lagi pula, jika kata sandi disimpan di server dalam beberapa file, maka peretas potensial akan dapat membacanya.


Jadi saya memutuskan untuk melakukannya secara berbeda. Faktanya adalah bahwa AsmBB adalah aplikasi FastCGI yang berumur panjang. Setelah diluncurkan pada server, itu berjalan selama berbulan-bulan dan bahkan bertahun-tahun tanpa perlu reboot.


Dan jika demikian, maka administrator dapat memasukkan kata sandi melalui antarmuka web segera setelah memulai AsmBB. Dengan demikian, kata sandi hanya ada dalam RAM dan hanya selama pelaksanaan permintaan POST selama peluncuran aplikasi. (Tentu saja, jangan lupa untuk nol semua memori di mana kata sandi ada selama pelaksanaan permintaan POST.)


Dari kata sandi yang diset, SQLeet menghasilkan kunci enkripsi melalui PBKDF2-HMAC-SHA256, dan kunci ini juga disimpan hanya dalam RAM.


Tentu saja, keputusan seperti itu tidak sempurna. Kunci enkripsi mungkin dapat ditemukan dalam memori RAM, selama eksekusi AsmBB, jika penyerang memiliki hak administrator.


Namun demikian, sistem ini masih jauh lebih aman daripada tanpa enkripsi. Misalnya, sekarang cadangan basis data dapat disimpan di mana-mana dan dikirim melalui saluran terbuka tanpa takut kebocoran data.


Omong-omong, ada rake yang bisa Anda selangkahi menggunakan SQLeet (atau ekstensi kriptografis SQLite lainnya). Dan saya, tentu saja, menginjak mereka.


Masalahnya adalah ukuran halaman database. Dalam versi SQLite lebih awal dari 3.12.0 (Maret 2016), ukuran halaman default adalah 1024 byte. Di v3.12.0, 4096 byte membuatnya. Ukuran ini, pengguna database dapat berubah karena alasan kinerja, dan ukuran halaman ditulis dalam database itu sendiri.


Tetapi jika database dienkripsi, maka ukuran halaman tidak dapat dibaca, dan untuk dekripsi ukuran ini diperlukan, karena setiap blok dienkripsi secara terpisah.


Oleh karena itu, jika Anda mengenkripsi database dengan ukuran halaman non-standar (untuk SQLeet, standarnya adalah 4096 byte), maka Anda tidak akan dapat mendekripsi, bahkan jika Anda mengatur kata sandi yang benar.


Ini sudah diperbaiki - sebelum mengatur kata sandi melalui sqlite3_key() atau pragma key='%%' , Anda perlu mengatur ukuran halaman yang benar melalui pragma page_size=%% .


Masalah lain yang mungkin adalah bahwa setelah enkripsi, OS tidak akan lagi dapat mengenali bahwa file tersebut adalah database SQLite. Ini (sejauh yang saya baca) kadang-kadang menyebabkan beberapa masalah, khususnya di iOS. Ada solusi untuk masalah ini, hanya saja jangan mengenkripsi 32 byte pertama file, tapi saya tidak masuk ke rincian.


Dan akhirnya, tentang kinerja. SQLeet sangat cepat. Setelah enkripsi, saya tidak melihat adanya perlambatan dalam sistem dengan latar belakang fluktuasi normal dalam kinerja VPS. Pengukuran presisi mungkin menunjukkan beberapa jenis perlambatan, tetapi mungkin dalam waktu kurang dari 10% dari kecepatan database yang tidak terenkripsi.


Tentu saja, ada ekstensi SQLite gratis lainnya untuk enkripsi. Misalnya, SQLcipher . Itu tidak cocok untuk saya karena memiliki lisensi distribusi yang berbeda (BSD), kodenya jauh lebih besar dan ada dependensi eksternal.


Tetapi, di sisi lain, SQLcipher jauh lebih tua dan karenanya (mungkin) lebih stabil. Seseorang bisa berguna.

Source: https://habr.com/ru/post/id470295/


All Articles