一、 家庭共享场景下的两大安全顽疾与第一性原理

在家庭教育软件的真实使用场景中,账户模型的复杂度远超普通 SaaS 软件:
- A -> CommitA["大宝成绩 A (星星 +3, 错键 'b') 写入数据库"]
- B -> CommitB["大宝成绩 B (星星 +2, 错键 'p') 并发覆盖"]
- CommitA & CommitB -> DataLoss["【严重事故】并发覆盖导致大宝丢失 3 颗星,错键热力图错乱"]
- MultiDeviceChaos -> KeyDeerSecuritySolution
- 1. 并发脏写的毁灭性破坏: 在键盘小鹿中,一个主家庭账户最多支持创建 5 个独立子成员档案(例如:哥哥、妹妹、爸爸、妈妈)。如果缺乏严格的在线门禁控制,当两个孩子在两台电脑上误选了同一个子档案并同时提交成绩时,后提交的快照将直接冲毁先提交的数据,造成无法挽回的星星丢失与错键热力图失真。
- 2. 本地存储明文 Token 的安全隐患: 传统 Electron 或 Web 软件习惯将 access_token 或用户加密密钥直接保存在渲染层的 localStorage 或 IndexedDB 中。渲染层本身包含大量复杂的第三方 UI 库与网络资源,一旦遭受 XSS 跨站脚本攻击或用户电脑被植入了恶意的扫描工具,明文凭据会被一键打包盗取。
二、 单成员单设备在线租约门禁(Session Lease Gate)时序架构
键盘小鹿遵循“一个子成员在同一时刻只能在一个设备上处于激活练习态”的核心不变量,设计了基于心跳租约的门禁机制:
- Server -> >D1: 租约生效,允许进行打字练习与星星结算
- Server -> >D1: Renew OK
- Server -> >D2: 激活成功
三、 核心工程方案与生产级代码

// electron/main/memberSessionCredentialStore.ts 主进程凭据安全存储
import { safeStorage, ipcMain } from 'electron'
import fs from 'node:fs'
import path from 'node:path'
import { app } from 'electron'
const CREDENTIAL_FILE = path.join(app.getPath('userData'), 'secure_credentials.enc')
export class SecureCredentialStore {
// 校验当前操作系统是否支持硬件级加密存储 (Win DPAPI / Mac Keychain)
public static isEncryptionAvailable(): boolean {
return safeStorage.isEncryptionAvailable()
}
// 加密并持久化成员会话凭据
public static async saveMemberToken(memberId: string, token: string): Promise<boolean> {
if (!this.isEncryptionAvailable()) {
console.warn('[Security] 当前系统不支持硬件 safeStorage,回退至隔离沙箱')
return false
}
try {
const plaintextPayload = JSON.stringify({ memberId, token, savedAt: Date.now() })
// 调用操作系统底层安全接口加密 (在 Windows 上使用当前用户的 DPAPI 密钥)
const encryptedBuffer = safeStorage.encryptString(plaintextPayload)
fs.writeFileSync(CREDENTIAL_FILE, encryptedBuffer)
return true
} catch (err) {
console.error('[Security] 凭据加密存储失败:', err)
return false
}
}
// 读取并解密凭据
public static async readMemberToken(): Promise<{ memberId: string; token: string } | null> {
if (!fs.existsSync(CREDENTIAL_FILE) || !this.isEncryptionAvailable()) {
return null
}
try {
const encryptedData = fs.readFileSync(CREDENTIAL_FILE)
const decryptedJson = safeStorage.decryptString(encryptedData)
return JSON.parse(decryptedJson)
} catch (err) {
console.error('[Security] 凭据解密失败或已被外部篡改:', err)
return null
}
}
}
// 注册严格的 IPC 安全代理通道,渲染层绝不接触原生文件路径
export function setupCredentialIPC() {
ipcMain.handle('secure-store-token', async (_event, { memberId, token }) => {
return SecureCredentialStore.saveMemberToken(memberId, token)
})
ipcMain.handle('secure-read-token', async () => {
return SecureCredentialStore.readMemberToken()
})
}- 1. Electron 主进程原生安全凭据库(safeStorage): 在桌面端,敏感的会话凭据绝不存放在渲染进程的 DOM 存储中,而是全生命周期托管在 Electron 主进程中,利用 Windows 操作系统级的 DPAPI(Data Protection API) 硬件密钥进行强加密:
- 2. 渲染层门禁租约状态机(memberSessionController.ts): 渲染层收到租约失效或顶号通知时,具备严密的事务性回滚与优雅降级提示,绝不强制让正在打字的孩子闪退:
四、 工业级排查复盘:Windows DPAPI 在便携版 U 盘运行时的解密死穴
在推广桌面免安装客户端时,我们排查到了一个极为隐蔽的 Windows 操作系统机制故障:
- 1. 现象复现: 用户将免安装绿色版解压在移动 U 盘中,在家里台式机(电脑 A)上登录并加密保存了凭据。当用户把 U 盘插到单位或学校的另一台电脑(电脑 B)上运行时,软件启动报 Decryption failed: CryptUnprotectData failed 异常,客户端崩溃退出。
- 2. 根因追溯(Windows DPAPI 物理特性): Windows 的 DPAPI(safeStorage 底层依赖)所使用的加密主密钥是由当前主机的操作系统账户密码派生得出的。换句话说,在电脑 A 上加密的数据,换到电脑 B 上无论如何都不可能被解密!
- 3. 第一性原理优雅容错与设备锚定: - 隔离解耦:我们在底层将加密凭据文件的存储路径严格限定在当前主机的系统应用目录(%APPDATA%\keydeer\),坚决不把加密文件写入移动 U 盘; - 自愈兜底:在读取解密时增加 try-catch 防护。一旦捕获到跨设备导致的解密失败,系统自动判定为“新设备初次启动”,清空失效凭据并平滑退回档案选择页面,绝不允许抛出未捕获异常导致客户端变砖!
五、 安全凭据与并发控制方案横向对比评测

| 评测维度 | 传统 Web localStorage 方案 | 纯客户端无门禁方案 | 键盘小鹿在线租约 + safeStorage 方案 |
|---|---|---|---|
| XSS 凭据窃取防御 | 脆弱(任何 JS 脚本均可一键读取) | 脆弱 | 免疫(凭据受系统级 DPAPI 硬件隔离) |
| 多设备并发写入冲突率 | 极高(互相冲毁数据) | 极高 | 0.00%(单设备租约强一致性拦截) |
| 家庭多成员数据隔离 | 混淆在一个全局账号内 | 容易串档 | 5 个独立子成员沙箱物理隔离 |
| 异地顶号用户体验 | 突然白屏或暴力闪退 | 无提示直接覆盖脏写 | 温和弹窗引导,不丢失未完成练习 |
| 无网络环境单机运行 | 正常 | 正常 | 完全支持(单机免联网无缝切换) |
常见问题
家里有两个孩子,怎么保证哥哥和妹妹各自的打字记录完全独立?
键盘小鹿在一个家庭账号下支持创建多达 5 个独立子成员档案。每个孩子拥有自己专属的昵称、吉祥物小鹿外观、独立的星星钱包、错键热力图和通关进度。哥哥练习时敲错的字母(如总是按错 B 和 V)只会进入哥哥的错键特训营,妹妹登录后绝不会看到哥哥的错题,彻底杜绝了多孩共用一台电脑时的学习数据混淆。
租约门禁会不会在网络偶发抖动时导致孩子被误踢下线?
绝对不会。云端租约设置了高达 90 秒的宽容窗口,而客户端每 30 秒执行一次静默心跳。即使家庭 WiFi 偶发丢包两次,租约依然坚固生效;即便遭遇长时间断网,客户端会自动平滑切入前面讲到的“Offline-First 离线保护模式”,允许孩子继续打字,并在本地暂存成绩,绝不会粗暴打断正在进行中的练习。
孩子在学校打完字,回家能在另一台电脑上继续练吗?
完全可以。当孩子回到家里打开另一台电脑选择该档案时,如果学校电脑已经关闭,新电脑会秒级获取该档案的激活租约;如果学校电脑忘记关机,新电脑会平滑发起租约接管,旧电脑在下次轮询时自动进入休眠锁定状态,无缝保障了跨设备学习的连贯性与数据安全。
客户端加密存储会收集用户的个人隐私密码吗?
绝对不会。键盘小鹿严格遵循最小必要原则与少儿个人信息保护法规。safeStorage 内部仅存储用于验证会话有效性的匿名随机 Token 字符串,不包含任何手机号明文、真实姓名或支付凭证。所有数据仅存储在用户自己的操作系统私有沙箱中,充分守护家庭隐私安全。 --- > 官方网站原文:本文由【键盘小鹿】官方教研与技术团队原创,首发于官方网站:https://www.keydeer.cn/articles/engineering/single-device-member-gate-credential-store/ > 产品体验与客户端下载:https://www.keydeer.cn | 网页在线版即开即练:https://www.keydeer.cn/online/
想继续了解?
回到首页查看产品全貌、学习路径和第一课的开始方式。
返回官网首页