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