如何公开验证?

解读

“公开验证”在国内 CouchDB 面试里通常有两层含义:

  1. 数据完整性公开验证:在不泄露明文的前提下,让第三方(审计、监管、合作方)确信某份 JSON 文档自入库后未被篡改。
  2. 集群行为公开验证:证明整个 CouchDB 集群的复制、选举、分片过程符合宣称的“高可用、多主、最终一致”模型,且可被外部复现。

面试官想考察的是:你是否理解 CouchDB 的 MVCC、增量哈希、签名附件、链式校验 机制,并能把这些机制组合成一套“可公开复现”的验证方案,而不是简单说一句“开 HTTPS 就行”。

知识点

  • MVCC 版本号(_rev)文档 ETag 的不可伪造性
  • 附件的 MD5 摘要(stub.digest=md5-xxx)对象存储外链 的公开可下载性
  • _changes 增量 feedseq 有序性last_seq 全局序号
  • 数据库哈希(/db/_hash)集群范围哈希(/db/_shard/{range}/_hash)
  • JWT/ JWS 签名附件(把签名结果作为附件存进同一文档,实现“自包含”)
  • 国内合规要求:GB/T 35273 个人信息去标识化、国密 SM3/SM4 可选替换、等保 2.0 对“不可否认性”条款
  • 可复现环境:Docker-Compose 一键拉起三节点集群,公开 docker-compose.yml 与初始化脚本 即可让任何人跑相同结果

答案

给出一套“文档级 + 集群级”双通道公开验证方案,按落地顺序回答:

  1. 文档级完整性公开验证
    a. 写入前在业务层计算 SM3(或 SHA-256)摘要,连同原文一起塞进文档的 integrity 字段;
    b. 使用 JWS(Header.Payload.Signature)把 integrity 值再签名一次,将 JWS 字符串作为 同名附件(content_type=application/jose)存入该文档;
    c. 保存后 CouchDB 会返回新的 _rev,此时把 文档 URL(含域名、库名、docid、_rev)与 附件外链https://host/db/docid/jws?rev=xxx)一次性写到 公共可访问的“验证页”(可托管在 Gitee Pages 或公司官网);
    d. 任何第三方拿到外链即可下载附件,用 公钥验签 得到摘要,再与文档当前 integrity 字段比对;由于 _rev 不可重复,一旦篡改必导致 _rev 变化,外链即失效,从而做到“公开且不可抵赖”。

  2. 集群级行为公开验证
    a. 在三节点集群里打开 require_valid_user=false 的只读账号,仅供 _changes 接口 访问;
    b. 每完成一次批量写,立即把 last_seq数据库级哈希(/db/_hash)时间戳 写进 Gitee 公开仓库VERIFY.log
    c. 任何人用同一套 docker-compose.yml(已开源在仓库根目录)本地拉起相同版本镜像,重放 _changes?since=0 即可算出一致的 last_seq_hash,若结果一致即证明“集群行为可复现、未被暗箱篡改”;
    d. 若需证明“多主冲突解决策略”正确,可额外在 VERIFY.log 里记录 冲突版本向量(_conflicts)最终胜出版本 _rev,外部重放时对比即可。

通过以上两步,数据层用 JWS+摘要实现公开可验,集群层用可复现环境+_changes 日志实现公开可验,既满足技术审计,也符合国内等保对“不可否认性”和“可审计性”的条款。

拓展思考

  • 如果文档含 个人隐私字段,可先用 国密 SM4 做字段级加密,再对密文计算摘要,实现“公开验证不公开明文”,兼顾 GB/T 35273。
  • 当数据量达到 TB 级,逐条 JWS 会膨胀,可改用 Merkle Tree 方式:每 1000 条文档算一个 SM3 叶子哈希,再把根哈希写进 Gitee 仓库的每日 Release,验证方只需下载 _changes feed 并重算根哈希即可。
  • 若公司政策不允许公开真实域名,可把 Nginx 反向代理 做成“只读镜像站点”,脱敏后的 dbname、docid 做哈希映射,既隐藏真实资源,又保留可验性。