隨着移動互聯網的發展,手機使用越來越廣泛,sqlite作為手機端存儲的一種解決方案,使用也非常普遍。但是sqlite本身安全特性卻比較弱,比如不支持用戶權限,只要能獲取到數據庫文件就能進行訪問;另外也沒有加密功能,任何人獲取到文件后,就可以查到明文數據。這使得大家對於sqlite又愛又不敢用,畢竟用戶的隱私是非常重要的。Sqlite分為開源版本和收費版,收費的版本是支持加密的,只不過需要付2000刀的技術支持費。當然,由於sqlite本身是開源的,業內有很多產品對sqlite增加了加密功能,比如wxsqlite,sqlcipher等。因此想免費使用加密版本的sqlite也不是不可以,但前提是使用過程遇到問題,一定要能hold住,因為免費的東西不一定是穩定的。廢話少說,本文主要討論兩個問題, 1.自己如何實現sqlite的加密功能,2.如何使用加密的sqlite。
加密算法選擇
要實現加密,首先需要選擇一種主流、高效、安全的加密算法,對於手機端和嵌入式設備,還要加上一條簡單的原則。加密算法主要分為對稱加密算法和非對稱加密算法,對於文本加密一般采用對稱加密,而對於秘鑰的管理則采用非對稱加密。目前主流的對稱加密算法有DES,AES,RC系列,TEA系列, Blowfish等,非對稱加密算法有RSA、Diffie-Hellman等。本人對幾種常見的對稱加密算法進行了測試,綜合起來AES和XXTEA算法性能最好,XXTEA的優勢在於實現非常簡單,代碼不到100行,在端設備上也是一種優勢。另外,騰訊一直在使用TEA系列算法作為它的通訊加密和本地存儲加密,用實踐證明了TEA系列算法的可靠性和安全性。下圖是AES算法和XXTEA算法的一些測試數據,僅供參考。XXTEA-256和XXTEA-64,分別表示塊大小是256個INT和64個INT。通過測試讀寫200M數據的時間來評估算法的優劣,每個數據通過測試5次取平均值。
|
|
不加密 |
AES |
XXTEA-256 |
XXTEA-64 |
| 寫操作 |
7879.3ms |
10283.6ms |
10577.3ms |
10649.4ms |
| 讀操作 |
315.69ms |
3681.4ms |
3527ms |
3598ms |
上層應用加密
選擇好加密算法,那么要實現加密功能了。有童鞋會問,為啥一定要在sqlite內部實現加密,上層應用加密不是一樣OK嗎?這個確實可以。很多開發語言都自帶了加密庫函數,直接調用即可。寫入數據時進行加密,讀出數據時再進行解密。但這種方式主要有以下幾個缺點:
- 對於加密的數據列,無法使用索引,雖然可以用等值查詢,但對於范圍查詢則無能為力。而且所有類型需要設計為BLOB類型,來存儲密文。
- 雖然可以對數據列進行加密,但表的元數據無法加密。
所以,總地來說,應用層是一種解決方案,但對開發者不太友好。
sqlite自身加密
從原理上來看,加入加密模塊功能也相對簡單,在寫入數據塊前,調用加密模塊進行數據塊加密,然后寫入文件;而在讀取數據塊時,先調用加密模塊解密,然后加載到緩存。加密模塊(紅色標注)在整個sqlite實現框架的位置如下圖。
實現層面,我們要做的工作主要包括三部分,實現加密算法,然后將加密接口與sqlite關聯起來,最后在合適的位置(讀寫文件),調用加/解密接口完成加密解密工作。由於sqlite自身已經預留了加解密接口,因此第3部分的工作已經幫我們做了,我們只需要實現第1和第2部分工作。核心接口如下:
1.sqlite3CodecAttach
含義:調用sqlite3PagerSetCodec 將加密接口與sqlite的pager模塊關聯
2.xxxCodec
含義:自己定義的加密接口,輸入參數是(page_no,讀寫模式),將指定page加、解密。
3.sqlite3_key
含義:設置數據庫密鑰,sqlite3_open后調用該接口。對於非加密庫,若調用該接口,會導致后續訪問數據報錯。
Error: file is encrypted or is not a database
4.sqlite3_rekey
含義:修改數據庫密鑰,這個接口會遍歷數據庫中的所有頁,然后用新密鑰對頁進行加密,寫入文件。若將新密鑰設置為NULL,則可以將加密庫變為普通庫。
5.sqlite3_activate_see
sqlite3CodecGetKey
這兩個接口沒有實際作用,可以實現一個空函數,保證能編譯通過就行。
加密sqlite使用
如果順利,我們現在已經有了一個包含加密功能的sqlite了,那么如何使用?下面主要列了一些常見的場景。
1.如何判斷一個db文件是否加密
$sqlite3 ./data/test.db
sqlite> .tables Error: file is encrypted or is not a database
sqlite> pragma key='123456' ;
sqlite> .tables
Error: file is encrypted or is not a database
對於加密的db文件,如果沒有執行pragma key=xxx命令直接執行,則會報錯。假設密碼是 123456,報錯后,重新執行pragma key命令,然后執行.tables,這時候依舊報錯。這個主要是因為密鑰在連接創建時初始化,所以對於加密數據庫,需要執行的第一條命令是pragma key=xxx
2.導出加密文件數據
$sqlite3 ./data/test.db // 打開加密數據庫文件test.db
sqlite> pragma key='123456'; // 設置秘鑰
sqlite> .output aaa.sql //將輸出重定向到文件aaa.sql
sqlite> .dump //導出數據庫
sqlite> .exit 這樣aaa.sql中包含了test.db中數據庫的明文內容。
3.解密加密數據庫
$sqlite3 ./data/test.db
sqlite> pragma key='123456'
sqlite> pragma rekey=''; //設置密鑰為空,則將密文數據庫解密。
//解密后可以直接打開數據庫
$sqlite3 ./data/test.db
sqlite> .tables
- orders t1 user
sqlite> .exit
參考文檔
