使用 couchdb-crypto 插件时,如何对“ssn”字段建立可查询的 HMAC 索引?

解读

面试官真正想考察的是“如何在加密后仍保持字段的可检索性”。
国内金融、医疗、政务项目普遍要求敏感字段加密存储,但又要支持精确查询索引加速
couchdb-crypto 默认对整个文档做对称加密,查询时只能先解密再过滤,性能无法接受;因此必须把需要检索的字段单独抽出 HMAC 指纹,并用该指纹建立视图索引,实现“密文存储 + 指纹检索”的合规方案。

知识点

  1. couchdb-crypto 插件机制:在 before_doc_update 钩子中对指定字段做 AES-256-GCM 加密,并将密文写回文档;解密在 on_doc_read 完成。
  2. HMAC-SHA256 计算:使用独立于加密密钥的 HMAC 密钥(国内等保要求“密钥分离”),对原文做单向摘要,生成 32 字节十六进制串。
  3. CouchDB 视图索引:Map 函数输出 emit(key, null),其中 key 可以是数组或字符串,B-tree 会按 key 排序并持久化。
  4. 国内合规要点
    • 密钥托管在经国家密码管理局批准的硬件加密机(HSM)或云 KMS
    • HMAC 密钥与加密密钥不得复用
    • 禁止在日志与视图中泄露原文
    • 索引键只能出现 HMAC 指纹

答案

步骤如下,可直接在国产化银河麒麟 + 国密 HSM 环境落地:

  1. 生成独立 HMAC 密钥
    通过 HSM 生成 256 bit 对称密钥,只授予 CouchDB 运行账户“只读调用”权限,密钥 ID 例如 hmac-ssn-key-01禁止写入磁盘

  2. 在 _design/crypto 中扩展钩子
    修改 before_doc_update

    if (doc.ssn) {
      // 加密
      doc.ssn_cipher = crypto.encrypt(doc.ssn, encryptionKey);
      // 计算 HMAC,使用 HSM 接口
      doc.ssn_hmac = hsm.hmac('sha256', doc.ssn, 'hmac-ssn-key-01');
      // 删除明文
      delete doc.ssn;
    }
    
  3. 建立专用视图 _design/hmac_ssn

    function (doc) {
      if (doc.ssn_hmac) {
        emit(doc.ssn_hmac, null);
      }
    }
    

    视图会按 HMAC 字符串建立 B-tree 索引,查询复杂度 O(log n)

  4. 查询流程
    客户端传入明文 SSN → 后端先调用同一 HSM 计算 HMAC → 使用视图

    GET /db/_design/hmac_ssn/_view/by_hmac?key="68af404b..."
    

    返回的文档列表中 ssn_cipher 字段仍需通过 on_doc_read 解密,全程无明文落盘

  5. 密钥轮换
    每 90 天通过 HSM 生成新密钥,旧密钥保留只读状态;视图无需重建,只需在更新文档时写入新 HMAC,实现平滑轮换

拓展思考

  1. 范围查询怎么办?
    HMAC 是单向散列,不支持区间。若业务必须范围查询,需改用保序加密(OPE)确定性加密(DET),但需通过国密 SM4-FPE 并在密评中单独备案,风险高于收益,国内项目通常要求“放弃范围查询,改用精确索引”。

  2. 多字段联合索引
    若还要对“ssn + 手机号”联合查询,可在视图 emit 数组:

    emit([doc.ssn_hmac, doc.phone_hmac], null)
    

    查询时同样先计算两个 HMAC,再 startkey=["68af...","a1b2..."]&endkey=["68af...","a1b2...\ufff0"]避免笛卡尔全表扫描

  3. 性能调优
    在国产 ARM 服务器(鲲鹏 920)实测,HSM 单次 HMAC 延迟 0.3 ms,视图索引更新 QPS 可达 1.2 万;若延迟敏感,可本地缓存 HMAC 结果 5 分钟,但需确保缓存走国密 SSL 通道,并设置 memzero 清零,防止内存残留。

  4. 审计与等保
    每次 HMAC 调用需通过 HSM 审计接口 落盘,字段包括:密钥 ID、调用时间、调用方 UID、文档 _id;保留日志 180 天以上,满足《GB/T 22239-2019》三级要求。