使用 SQLite 加密擴充功能
SQLite 加密擴充功能 (SEE) 提供了建立、讀取和寫入加密資料庫檔案的簡便方法。它可以與 SQLite Android 綁定搭配使用,為任何應用程式新增加密資料庫功能。
1. 建置啟用 SEE 的版本
除非您使用預先建置的 aar 檔案,否則若要將 SEE 擴充功能與 SQLite Android 綁定搭配使用,您需要建置自訂版本,可以是自訂 aar 檔案,也可以直接整合程式碼到應用程式中。
請按照上面連結的說明操作。但在執行 ndk-build
命令來建置原生程式庫之前,
- 請將
sqlite3.c
和sqlite3.h
檔案替換為啟用 SEE 的版本(即 sqlite3.c 和 see.c 的合併版本 - 詳細資訊請參閱上面的連結)。 - 編輯 Android.mk 檔案,取消註釋下面兩行中的第二行
# If using SEE, uncomment the following: # LOCAL_CFLAGS += -DSQLITE_HAS_CODEC
2. 應用程式程式碼注意事項
2.1. 開啟加密的資料庫
開啟現有加密資料庫或建立新資料庫的最佳方法,是在SQLite URI 資料庫識別碼中指定加密金鑰。例如,不要使用 "DatabaseName.db",而是使用下列其中一種:
file:DatabaseName.db?key=secret file:DatabaseName.db?hexkey=0123ABCD
以上第一種形式指定文字金鑰,需要 SQLite 3.19.0 或更高版本。
或者,在開啟或建立加密資料庫後,應用程式可以立即執行 PRAGMA 來設定加密金鑰。這必須在呼叫任何其他資料庫方法之前完成。例如:
import org.sqlite.database.sqlite.SQLiteDatabase; ... SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase("my.db", null); db.execSQL("PRAGMA key = 'secretkey'");
或者,如果您使用的是 SQLiteOpenHelper 輔助類別,則 PRAGMA 必須是在 onConfigure() 回呼中執行的第一個動作。例如:
import org.sqlite.database.sqlite.SQLiteDatabase; import org.sqlite.database.sqlite.SQLiteHelper; ... class MyHelper extends SQLiteOpenHelper { ... void onConfigure(SQLiteDatabase db){ db.execSQL("PRAGMA key = 'secretkey'"); } ... }
請注意,**使用 PRAGMA 指定加密金鑰(如上所述)與 WAL 模式不相容**。在 Android 中,啟用 WAL 模式也會在底層啟用連線池。這會增加多執行緒應用程式的並行性,但也使得使用 PRAGMA 直接在 SQLite 中設定加密金鑰變得不安全(因為 Android 可能會建立和使用尚未設定的新的 SQLite 連線)。
有關加密金鑰的更多詳細資訊,請參閱 SEE 說明文件。
2.2. 加密現有資料庫或變更加密金鑰
可以使用「PRAGMA rekey」或「PRAGMA rehexkey」命令加密未加密的資料庫,或變更現有資料庫的加密金鑰,如 SEE 說明文件中「使用「key」PRAGMA」下所述。
如果使用 WAL 模式,這會遇到與「PRAGMA key」相同的問題 - 在(重新)加密資料庫後,它只會修改連線池中一個連線內部使用的金鑰。這表示當 Android 嘗試使用不同的連線來存取資料庫時,它會擲出「檔案已加密或不是資料庫」的例外狀況 (SQLITE_NOTADB)。因此,需要修改 WAL 模式資料庫加密金鑰的應用程式,應該在執行「PRAGMA rekey」後,立即建立一個新的 SQLiteDatabase(或 SQLiteOpenHelper)物件來存取資料庫,並在新 URI 識別碼中指定新的金鑰。
2.3. 與非 SEE 版本的其他差異
除了支援加密資料庫外,啟用 SEE 的版本在另外兩個方面也有不同的行為
-
在 Android 中,如果遇到資料庫損毀,或嘗試開啟非 SQLite 資料庫的檔案,預設行為是刪除該檔案,並在其位置建立一個空的資料庫檔案。在啟用 SEE 的版本中,預設行為是擲出例外狀況。
之所以如此,是因為提供錯誤的加密金鑰與開啟一個並非資料庫檔案的情況難以區分。在這種情況下直接刪除檔案似乎太危險了。
可以使用 DatabaseErrorHandler 介面覆蓋預設行為。 -
在此模組的早期版本中,針對啟用 SEE 的建置版本,完全停用了 WAL 模式連線池。這一點在 3.19.0 開發週期中已在此處更改。