使用 crypto-pouch 插件时,密码轮换策略如何同步到 CouchDB 端?

解读

面试官真正想考察的是:

  1. 你是否理解 crypto-pouch 只在浏览器/客户端侧做加密,而 CouchDB 本身只存密文;
  2. 当业务要求 定期轮换密钥 时,如何 在不破坏离线优先、多主复制的前提下,让旧密文平滑过渡到新密钥,并保证 所有节点(含离线后回来的移动端)都能解密历史数据
  3. 你是否能给出 可落地、可回滚、符合国内等保/密评要求 的工程方案,而不是简单一句“重新加密”。

知识点

  • crypto-pouch 加密层级:在 PouchDB 落盘前对 JSON 文档做 AES-GCM 全字段加密,CouchDB 看到的已是密文,密钥只存在于客户端
  • CouchDB 复制协议:基于 _rev 向量时钟,不会自动触发客户端重新加密,也不会感知加密层变化。
  • 密钥轮换三大痛点
    1. 旧数据仍用旧密钥加密,不能强制全量重写(移动设备可能离线);
    2. 新数据必须用新密钥,且要向后兼容
    3. 国内合规要求 密钥分级、密钥托管、审计日志,不能硬编码在代码仓库。
  • 常见错误
    • 把新密钥直接写死在新版本 App 里,导致老版本离线用户回来后无法解密;
    • 在 CouchDB 侧建“密钥表”,破坏零信任原则;
    • 用 _changes 监听后全量重写,造成 雪崩式冲突

答案

给出一套在国内金融、政务场景已落地的 “双密钥信封 + 分阶段标记” 方案,分五步:

  1. 密钥分级与托管
    主密钥(KEK)放在 国密合规的 HSM 或阿里云 KMS,工作密钥(DEK)由 KEK 加密后随文档携带,CouchDB 只存密文 DEK,不存明文。

  2. 文档内增加加密元数据
    在每条 doc 里新增 _crypto 字段:

    {
      "_id": "order/123",
      "cipher": "...",
      "_crypto": {
        "ver": 2,               // 密钥版本
        "dek_id": "dek_2025Q2", // DEK 标识
        "wrapped_dek": "..."    // 被 KEK 加密的 DEK
      }
    }
    

    该字段 被 crypto-pouch 排除在加密之外,方便客户端快速识别版本。

  3. 轮换触发流程
    密钥管理系统(KMS)定时推送 MQTT/HTTP 通知 到移动端;App 收到后:
    a. 生成新 DEK,用 KEK 加密后写入新 dek_id
    b. 本地新建一个 “只写新密钥” 的 crypto-pouch 实例;
    c. 老数据 按需解密时再读旧 DEK,不写回;新数据一律用新 DEK。

  4. ** CouchDB 复制冲突处理**
    由于 _crypto.ver 不同,同一 doc 不会出现两份不同密文冲突;若用户在不同设备分别更新,CouchDB 会生成冲突节点,客户端在 post-replication 钩子里用本地最新 DEK 重新加密后手动解决冲突,并打上 merged: true 标记,避免无限循环

  5. 旧密钥退役与审计
    当所有活跃设备都上报 last_crypto_ver >= 290 天无 ver=1 写操作 后,KMS 将旧 KEK 标记为 “禁用”(非删除),并生成 密钥轮换审计报告,供等保测评使用。
    若需紧急回滚,只需把旧 KEK 重新启用,客户端在解密失败时自动回退到旧 DEK,业务零中断

一句话总结:密码轮换完全在客户端完成,CouchDB 仅作为密文与加密元数据的存储载体,通过“密钥版本 + 信封加密”实现平滑过渡,既满足离线优先,又符合国内合规审计。

拓展思考

  1. 如果业务要求 “字段级加密”(如只加密手机号),而 crypto-pouch 默认全文档加密,你会如何改造?
    提示:可引入 sub-cipher 插件,把敏感字段抽成子 doc,用相同信封策略,但需额外处理 子 doc 的 _rev 与父 doc 的一致性

  2. 当政府客户要求 “国密 SM4/SM9” 替代 AES-GCM 时,crypto-pouch 的 WebAssembly 性能是否会成为瓶颈?
    提示:在 React Native 端可 预置 SM4 硬件加速模块,并通过 JSCore 与原生层零拷贝 解决 200 MB 大附件的流式加密。

  3. 若未来引入 “量子计算威胁”,需要 后量子算法(如 Kyber) 保护 KEK,如何在不换 CouchDB 的前提下完成 双层密钥升级
    提示:把 Kyber 公钥直接放进 _crypto.pq_kem 字段,客户端在轮询时做 混合密钥交换,老设备不解读该字段即可向前兼容。