1.21SQLCipher 简介
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;`);
这些选项可以根据安全需求进行调整,但需要注意不同的设置可能会影响兼容性和性能。