SQLCipher 是一個基于 SQLite 的擴展,提供了透明的數據庫加密功能。與普通 SQLite 不同,SQLCipher 在數據寫入磁盤前自動加密,讀取時自動解密,無需開發者手動處理加密邏輯。這使得它非常適合移動應用、桌面應用等需要本地數據加密的場景。
特性 | SQLCipher |
---|---|
開發語言 | C(原生 SQLite 擴展) |
加密方式 | 內置 AES-256 加密,透明化處理 |
API 兼容性 | 完全兼容 SQLite API |
跨平臺支持 | 原生支持多平臺(iOS、Android、Web) |
Node.js 操作 SQLCipher 的實現
在 Node.js 環境中操作 SQLCipher,我們可以使用sqlcipher
包,它是 SQLCipher 的 Node.js 綁定。下面詳細介紹如何在 Node.js 中使用 SQLCipher:
1. 安裝依賴
首先需要安裝sqlcipher
包:
npm install sqlcipher
2. 基本操作示例
以下是一個完整的示例,展示了如何在 Node.js 中使用 SQLCipher 進行數據庫操作:
const sqlcipher = require('sqlcipher');
sqlcipher.verbose();// 打開或創建數據庫
const db = new sqlcipher.Database('encrypted.db');// 數據庫操作封裝為Promise
const execute = (db, sql, params = []) => {return new Promise((resolve, reject) => {db.run(sql, params, function(err) {if (err) {reject(err);} else {resolve(this);}});});
};const get = (db, sql, params = []) => {return new Promise((resolve, reject) => {db.get(sql, params, (err, row) => {if (err) {reject(err);} else {resolve(row);}});});
};const all = (db, sql, params = []) => {return new Promise((resolve, reject) => {db.all(sql, params, (err, rows) => {if (err) {reject(err);} else {resolve(rows);}});});
};// 初始化數據庫
async function initDatabase() {try {// 打開數據庫連接await new Promise((resolve, reject) => {db.open((err) => {if (err) {reject(err);} else {resolve();}});});// 設置加密密鑰(非常重要!)await execute(db, `PRAGMA key = 'your-strong-password-here';`);await execute(db, `PRAGMA cipher_compatibility = 4;`);// 創建表await execute(db, `CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY,username TEXT NOT NULL,email TEXT UNIQUE NOT NULL,created_at DATETIME DEFAULT CURRENT_TIMESTAMP)`);console.log('數據庫初始化完成');} catch (error) {console.error('數據庫初始化失敗:', error);throw error;}
}// 插入數據示例
async function insertUser(username, email) {try {const result = await execute(db, 'INSERT INTO users (username, email) VALUES (?, ?)', [username, email]);console.log(`插入用戶成功,ID: ${result.lastID}`);return result.lastID;} catch (error) {console.error('插入用戶失敗:', error);throw error;}
}// 查詢數據示例
async function getUsers() {try {const users = await all(db, 'SELECT * FROM users');return users;} catch (error) {console.error('查詢用戶失敗:', error);throw error;}
}// 更新數據示例
async function updateUserEmail(userId, newEmail) {try {await execute(db, 'UPDATE users SET email = ? WHERE id = ?', [newEmail, userId]);console.log(`更新用戶郵箱成功,ID: ${userId}`);} catch (error) {console.error('更新用戶郵箱失敗:', error);throw error;}
}// 刪除數據示例
async function deleteUser(userId) {try {await execute(db, 'DELETE FROM users WHERE id = ?', [userId]);console.log(`刪除用戶成功,ID: ${userId}`);} catch (error) {console.error('刪除用戶失敗:', error);throw error;}
}// 關閉數據庫
async function closeDatabase() {try {await new Promise((resolve, reject) => {db.close((err) => {if (err) {reject(err);} else {resolve();}});});console.log('數據庫已關閉');} catch (error) {console.error('關閉數據庫失敗:', error);throw error;}
}// 使用示例
async function runExample() {try {// 初始化數據庫await initDatabase();// 插入數據const userId = await insertUser('john_doe', 'john@example.com');// 查詢數據const users = await getUsers();console.log('所有用戶:', users);// 更新數據await updateUserEmail(userId, 'john.doe@example.com');// 再次查詢數據const updatedUsers = await getUsers();console.log('更新后的用戶:', updatedUsers);// 刪除數據await deleteUser(userId);// 最后查詢數據const finalUsers = await getUsers();console.log('刪除后的用戶:', finalUsers);} catch (error) {console.error('操作失敗:', error);} finally {// 關閉數據庫連接await closeDatabase();}
}// 執行示例
runExample();
關鍵操作說明
1. 數據庫加密設置
// 設置加密密鑰
await execute(db, `PRAGMA key = 'your-strong-password-here';`);// 設置加密兼容性(版本4是最新的加密算法)
await execute(db, `PRAGMA cipher_compatibility = 4;`);
這兩行代碼非常關鍵,必須在打開數據庫后立即執行。如果密鑰不正確,后續的數據庫操作將失敗。
2. 安全注意事項
-
密鑰管理:不要在代碼中硬編碼密鑰,尤其是在生產環境中。可以使用環境變量、配置文件或密鑰管理服務來存儲密鑰。
-
防止 SQL 注入:始終使用參數化查詢(如上面示例中的
?
占位符),避免直接拼接 SQL 字符串。 -
數據庫文件權限:確保數據庫文件的訪問權限設置正確,避免未授權訪問。
3. 性能考慮
SQLCipher 的加密操作會帶來一定的性能開銷,通常比普通 SQLite 慢 10-20%。在性能敏感的應用中,可以考慮:
- 使用批量操作減少加密 / 解密次數
- 優化查詢以減少不必要的數據處理
- 在內存中緩存頻繁訪問的數據
1. 備份加密數據庫
async function backupDatabase() {try {const backupDb = new sqlcipher.Database('backup.db');await new Promise((resolve, reject) => {backupDb.open((err) => {if (err) {reject(err);} else {resolve();}});});// 設置備份數據庫的密鑰(必須與源數據庫相同)await execute(backupDb, `PRAGMA key = 'your-strong-password-here';`);// 執行備份const backup = db.backup(backupDb);backup.step(1, (err, state) => {if (err) {console.error('備份失敗:', err);} else if (state === 1) {console.log('備份完成');}backup.finish();backupDb.close();});} catch (error) {console.error('備份數據庫失敗:', error);throw error;}
}
2. 自定義加密選項
// 設置加密算法(默認是 AES-256-CBC)
await execute(db, `PRAGMA cipher = 'aes-256-cfb';`);// 設置加密迭代次數(影響密鑰派生)
await execute(db, `PRAGMA kdf_iter = 64000;`);
這些選項可以根據安全需求進行調整,但需要注意不同的設置可能會影響兼容性和性能。