Android SQLite數(shù)據(jù)庫加密的操作方法
一、前言
SQLite是一個輕量級的、跨平臺的、開源的嵌入式數(shù)據(jù)庫引擎,也是一個關(guān)系型的的使用SQL語句的數(shù)據(jù)庫引擎,
讀寫效率高、資源消耗總量少、延遲時間少,使其成為移動平臺數(shù)據(jù)庫的最佳解決方案(如Android、iOS)
但是Android上自帶的SQLite數(shù)據(jù)庫是沒有實現(xiàn)加密的,我們可以通過Android Studio直接導出應(yīng)用創(chuàng)建的數(shù)據(jù)庫文件,然后通過如SQLite Expere Personal 這種可視化工具打開數(shù)據(jù)庫文件進行查看數(shù)據(jù)庫的表結(jié)構(gòu),以及數(shù)據(jù),這就導致存儲在SQLite中的數(shù)據(jù)可以被任何人查看,如果是一些賬號密碼,或者聊天數(shù)據(jù)等,那么我們的應(yīng)用就面臨著嚴重的安全漏洞隱患;
二、數(shù)據(jù)庫加密方法
因為Android自帶的SQLite數(shù)據(jù)庫本身是沒有實現(xiàn)加密的,那我們?nèi)绾螌崿F(xiàn)對數(shù)據(jù)庫的加密呢?
(1)對SQLite數(shù)據(jù)庫的數(shù)據(jù)進行加密
我們可以在程序中對保存到數(shù)據(jù)庫中的數(shù)據(jù) 進行加密后保存,然后查詢數(shù)據(jù)的時候,對查詢的數(shù)據(jù)進行解密后使用,如果還不希望別人看到數(shù)據(jù)庫的表結(jié)構(gòu),我們可以對數(shù)據(jù)庫名字,表名,表中的字段名字使用MD5等加密手段加密后再進行操作;
這種方法是可以達到數(shù)據(jù)庫加密的目的的,但是相對來說操作就比較繁瑣了
(2)使用SQLCipher對SQLite數(shù)據(jù)庫加密
SQLCipher是基于SQLite基礎(chǔ)之上實現(xiàn)了數(shù)據(jù)庫加密的開源庫,可以采用第三方的開源框架SQLCipher,SQLCipher是基于原生SQlite數(shù)據(jù)庫進行擴展,實現(xiàn)數(shù)據(jù)庫整體加密(數(shù)據(jù)庫文件加密),提供的數(shù)據(jù)庫的操作接口,和原生的SQLite數(shù)據(jù)庫操作接口基本一樣的;我們創(chuàng)建或者打開數(shù)據(jù)庫都需要密碼,我們打開數(shù)據(jù)庫時的密碼,需要和創(chuàng)建數(shù)據(jù)庫時的密碼保護一致,否則打開數(shù)據(jù)庫時會報錯,提示打開的文件不是一個數(shù)據(jù)庫文件
net.sqlcipher.database.SQLiteException: file is not a database;
我們導出的數(shù)據(jù)庫文件,通過SQLite Expere Personal這類可視化工具也是無法直接打開的;但是可以使用DB Browser for Sqlite這個數(shù)據(jù)庫查看工具進行查看,查看的時候輸入創(chuàng)建數(shù)據(jù)庫時使用的加密密碼
SQLCipher的特點:
SQLCipher 占用空間小,性能好,因此非常適合保護嵌入式應(yīng)用程序數(shù)據(jù)庫,非常適合移動開發(fā)。
(1)極快的性能,加密開銷低至 5-15%
(2)數(shù)據(jù)庫文件中的數(shù)據(jù) 100% 已加密,是對所有數(shù)據(jù)文件,包括數(shù)據(jù)文件和緩存、結(jié)構(gòu)文件等等進行加密。
(3)使用良好的安全實踐(CBC 模式、密鑰派生),加密算法是256位 AES 在 CBC 模式
(4)使用 OpenSSL 加密庫提供的算法
在Android中集成SQLiteCipher:
-添加SQLiteCipher的依賴
implementation 'net.zetetic:android-database-sqlcipher:4.4.3@aar' implementation "androidx.sqlite:sqlite:2.0.1"
-使用SQLiteCipher提供的相關(guān)接口操作
SQLiteDatabase.loadLibs(this) val databaseFile = getDatabasePath("demo.db") if (databaseFile.exists()) databaseFile.delete() databaseFile.mkdirs() databaseFile.delete() val database = SQLiteDatabase.openOrCreateDatabase(databaseFile, "test123", null) database.execSQL( "CREATE TABLE " + DatabaseHelper.TABLE_MUSIC_TYPE + " (type_id integer primary key autoincrement not null," + "type_no integer,type_name text)" ) database.execSQL( "insert into " + DatabaseHelper.TABLE_MUSIC_TYPE + " (type_no,type_name) " + "values ('" + 1 + "','" + "送餐音樂" + "')" )
上面的代碼在調(diào)用時,會創(chuàng)建數(shù)據(jù)庫demo.db,傳入了數(shù)據(jù)庫密碼,并且創(chuàng)建了一個表music_type,并且向表中插入了一條數(shù)據(jù);
注意代碼中的數(shù)據(jù)庫相關(guān)的操作,都是使用SQLIteCipher中的相關(guān)接口即net.sqlcipher.database包名下的相關(guān)接口,不要使用成了原生SQLite的相關(guān)接口
SQLiteDatabase.loadLibs(this) val databaseFile = getDatabasePath("demo.db") val database = SQLiteDatabase.openOrCreateDatabase(databaseFile, "test123", null) val cursor = database.rawQuery( "select * from " + DatabaseHelper.TABLE_MUSIC_TYPE, null ) var musicTypeList: MutableList<MusicTypeBean> = mutableListOf(); while (cursor.moveToNext()) { var musicTypeBean = MusicTypeBean(); musicTypeBean.id = cursor.getInt(cursor.getColumnIndex("type_no")) musicTypeBean.name = cursor.getString(cursor.getColumnIndex("type_name")) musicTypeList.add(musicTypeBean) } cursor.close() Log.e(TAG, "onClick: " + musicTypeList.size)
上述代碼就是查詢demo.db數(shù)據(jù)庫中的music_type表中的數(shù)據(jù),獲取數(shù)據(jù)庫對象的時候,注意傳入的密碼和創(chuàng)建數(shù)據(jù)庫時要保持一致;
上面使用SQLiteCipher創(chuàng)建數(shù)據(jù)庫和表,以及向表中插入數(shù)據(jù),查詢表中的數(shù)據(jù),除了創(chuàng)建數(shù)據(jù)庫獲取可讀寫數(shù)據(jù)庫對象和原生SQLite API有些區(qū)別一樣,其他執(zhí)行SQL語句,查詢表中數(shù)據(jù)的API 和原生 SQlite API是完全一樣的;
SQLiteCipher結(jié)合Room框架使用
我們知道在使用SQLite數(shù)據(jù)庫的時候,我們往往會使用一些比較方便的ORM(對象關(guān)系映射)框架來幫助我們操作數(shù)據(jù)庫,如GreenDAO,Room(Jetpack組件)等,那如何將SQLiteCipher結(jié)合這些ORM框架使用;我們這里介紹一下Google Jetpack組件中的ORM框架 Room結(jié)合SQLiteCipher使用;
其實Room結(jié)合SQLiteCipher使用,就是在創(chuàng)建數(shù)據(jù)庫時候,需要先創(chuàng)建一個SupportFactory
,SupportFactory中會傳入通過SQLiteCipher中的SQLiteDatabase獲取的密碼字節(jié)數(shù)據(jù)
SQLiteDatabase.loadLibs(this) val passphrase = SQLiteDatabase.getBytes("test123".toCharArray()) val factory = SupportFactory(passphrase, object : SQLiteDatabaseHook { override fun preKey(database: SQLiteDatabase?) { LogUtil.e(TAG, "preKey") } override fun postKey(database: SQLiteDatabase?) { LogUtil.e(TAG, "postKey") } }, true)
然后在創(chuàng)建數(shù)據(jù)庫的時候,通過Room自帶的openHelperFactory()方法傳入創(chuàng)建的SupportFactory即可,這樣就能創(chuàng)建加密數(shù)據(jù)庫了;其他操作,就按照Room正常的操作即可
var mInstance= Room .databaseBuilder( context.applicationContext, AppDatabase::class.java, DB_NAME ).addCallback(object : RoomDatabase.Callback() { override fun onCreate(db: SupportSQLiteDatabase) { super.onCreate(db) Log.e(TAG, "onCreate: ") initMusicTypeData(context, db) } }).openHelperFactory(factory) .build()
查看并導出加密數(shù)據(jù)庫文件
-導出數(shù)據(jù)庫文件
我們手機通過USB連接電腦之后,打開開發(fā)者模式,然后在Android Studio菜單欄中的View->
Tool Windows->Device File Explorer
然后在Device File Explorer中進入 data/data/應(yīng)用包名/databases中找到我們創(chuàng)建的數(shù)據(jù)庫文件demo.db,然后我們可以右鍵改文件Save As 導出該數(shù)據(jù)庫文件
-查看加密數(shù)據(jù)庫文件
前面我們已經(jīng)提到過,可以通過DB Browser for SQLite來查看加密的數(shù)據(jù)庫文件
下載地址:https://sqlitebrowser.org/dl/
下載安裝之后,我們打開安裝目錄下的DB Browser for SQLCipher.exe程序,然后通過菜單欄中的文件->打開數(shù)據(jù)庫->打開導出的加密數(shù)據(jù)庫文件,然后輸入數(shù)據(jù)庫文件的加密密碼,就是我們在程序中SQLiteCipher加密數(shù)據(jù)庫文件時使用的密碼,輸入正確密碼后,可以正常打開數(shù)據(jù)庫文件
右鍵表名,選擇瀏覽數(shù)據(jù),即可查看表中的數(shù)據(jù)
到此這篇關(guān)于Android SQLite數(shù)據(jù)庫加密的操作方法的文章就介紹到這了,更多相關(guān)Android SQLite數(shù)據(jù)庫加密內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Flutter檢查連接網(wǎng)絡(luò)connectivity_plus實現(xiàn)步驟
這篇文章主要為大家介紹了Flutter檢查連接網(wǎng)絡(luò)connectivity_plus實現(xiàn)步驟,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06Android仿微信滑動彈出編輯、刪除菜單效果、增加下拉刷新功能
這篇文章主要介紹了Android仿微信滑動彈出編輯、刪除菜單效果、增加下拉刷新功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-01-01Android ViewPager實現(xiàn)智能無限循環(huán)滾動回繞效果
這篇文章主要為大家詳細介紹了Android ViewPager實現(xiàn)智能無限循環(huán)滾動回繞效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07Android 讀取assets和raw文件內(nèi)容實例代碼
這篇文章主要介紹了Android 讀取assets和raw文件內(nèi)容的相關(guān)資料,并附簡單實例代碼,需要的朋友可以參考下2016-10-10