Electron中通过 safeStorage 来实现加密存储
我之前写了个note类应用后,由于在项目中涉及到了key的明文存储,查了资料后发现safeStorage存储API,故记录一下。
在 Electron 应用中,使用 safeStorage API 加密存储 API Key 是官方推荐的安全加密手段,本质是利用操作系统提供的原生加密系统(如 macOS 的钥匙串、Windows 的 DPAPI)来保护敏感数据。
需要注意的是,safeStorage 仅可在主进程(Main Process)中使用。
🔐 平台支持与安全说明
safeStorage 的安全性取决于底层操作系统:
- macOS:密钥存储在你的应用专属的钥匙串中,可防止其他应用和用户访问。
- Windows:使用 DPAPI 加密,通常只有加密时登录的同一用户才能解密。但无法防止同一用户下的其他应用访问。
🛠️ 基本用法
safeStorage API 提供了三个核心方法:
-
safeStorage.isEncryptionAvailable()- 检查当前平台是否支持加密。调用任何加密方法前,务必先调用此方法进行检查。
- 在 Windows 上通常返回
true,macOS 需钥匙串可用。
-
safeStorage.encryptString(plainText)- 加密明文字符串,返回一个
Buffer对象。
- 加密明文字符串,返回一个
-
safeStorage.decryptString(encrypted)- 解密由
encryptString生成的Buffer,返回明文字符串。解密失败会抛出错误。
- 解密由
💻 在 Electron 应用中的实践
1. 存储与检索 API Key
下面是一个结合 electron-store(用于持久化存储)的 SecretStore 类实现,演示了完整的加密存储与解密读取流程。
// 在主进程 (main.ts) 中
import { safeStorage } from 'electron';
import Store from 'electron-store';
const store = new Store();
const ENCRYPTED_KEY = 'encryptedApiKey';
class SecretStore {
// 加密并存储 API Key
setApiKey(apiKey: string): void {
// 1. 检查加密是否可用
if (!safeStorage.isEncryptionAvailable()) {
throw new Error('当前环境不支持安全存储');
}
// 2. 加密字符串
const encryptedBuffer = safeStorage.encryptString(apiKey.trim());
// 3. 将 Buffer 转为 Base64 字符串后存储
store.set(ENCRYPTED_KEY, encryptedBuffer.toString('base64'));
}
// 解密并获取 API Key
getApiKey(): string | null {
// 1. 从存储中读取 Base64 字符串
const encryptedBase64 = store.get(ENCRYPTED_KEY) as string | undefined;
if (!encryptedBase64) {
return null;
}
try {
// 2. 将 Base64 字符串转回 Buffer
const encryptedBuffer = Buffer.from(encryptedBase64, 'base64');
// 3. 解密 Buffer
return safeStorage.decryptString(encryptedBuffer);
} catch (error) {
// 4. 解密失败(可能数据已损坏),删除无效数据
store.delete(ENCRYPTED_KEY);
return null;
}
}
// 其他方法:删除、检查是否存在等
deleteApiKey(): void {
store.delete(ENCRYPTED_KEY);
}
hasApiKey(): boolean {
return store.has(ENCRYPTED_KEY);
}
}
代码参考了相关实现。
2. Linux环境下,处理无密钥库的情况
为增强应用健壮性,建议在 Linux 上检测后端存储类型:
import { safeStorage } from 'electron';
// 检查当前使用的存储后端
const backend = safeStorage.getSelectedStorageBackend();
if (backend === 'basic_text') {
// 提示用户当前环境不支持安全存储,加密是无效的
console.warn('警告:当前 Linux 环境未检测到安全密钥库,API Key 将以明文形式存储!');
}
getSelectedStorageBackend() 的返回值可参考官方文档。
3. 进程隔离与安全实践
为确保安全,切勿将明文 API Key 发送到渲染进程,应遵循以下架构:
- 主进程 (Main):负责所有加密、解密和持久化存储操作。
- 预加载脚本 (Preload):通过
contextBridge向渲染进程暴露安全的、受限制的 API。 - 渲染进程 (Renderer):通过预加载脚本暴露的 IPC 桥接器,请求主进程执行操作(如保存、获取 Key),仅接收操作结果或脱敏后的 Key(如
sk-...ab12)。
📦 第三方库:genai-key-storage-lite
若不想从零实现加密存储,也可以使用封装好的库,如 genai-key-storage-lite。它基于 safeStorage 提供了更便捷的 API,并内置了进程隔离方案,无需考虑细节,直接调用就可以了。
核心用法:
// 1. 主进程:初始化服务并注册 IPC 处理器
// main.ts
import { ApiKeyServiceMain, registerSecureApiKeyIpc } from 'genai-key-storage-lite';
const apiKeyService = new ApiKeyServiceMain(app.getPath('userData'));
registerSecureApiKeyIpc(apiKeyService);
// 2. 预加载脚本:创建安全桥接器
// preload.ts
import { createApiKeyManagerBridge } from 'genai-key-storage-lite/preload';
contextBridge.exposeInMainWorld('electronBridge', {
secureApiKeyManager: createApiKeyManagerBridge(),
});
// 3. 渲染进程:通过桥接器调用
// renderer.ts
const bridge = window.electronBridge.secureApiKeyManager;
await bridge.setApiKey('your-api-key-here'); // 保存
const key = await bridge.getApiKey(); // 获取明文 (仅在主进程解密)
const masked = await bridge.getApiKeyMasked(); // 获取脱敏Key
💎 总结
使用 Electron 的 safeStorage 加密存储 API Key 的核心步骤是:
- 检查环境:调用
safeStorage.isEncryptionAvailable()。 - 加密存储:在主进程使用
safeStorage.encryptString()加密,将结果Buffer转为 Base64 字符串后,用electron-store等工具持久化。 - 解密读取:读取 Base64 字符串并转为
Buffer,再用safeStorage.decryptString()解密。 - 隔离进程:通过预加载脚本暴露安全 API,确保明文 Key 不进入渲染进程。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)