如何公开验证?
解读
“公开验证”在国内 CouchDB 面试里通常有两层含义:
- 数据完整性公开验证:在不泄露明文的前提下,让第三方(审计、监管、合作方)确信某份 JSON 文档自入库后未被篡改。
- 集群行为公开验证:证明整个 CouchDB 集群的复制、选举、分片过程符合宣称的“高可用、多主、最终一致”模型,且可被外部复现。
面试官想考察的是:你是否理解 CouchDB 的 MVCC、增量哈希、签名附件、链式校验 机制,并能把这些机制组合成一套“可公开复现”的验证方案,而不是简单说一句“开 HTTPS 就行”。
知识点
- MVCC 版本号(_rev) 与 文档 ETag 的不可伪造性
- 附件的 MD5 摘要(stub.digest=md5-xxx) 与 对象存储外链 的公开可下载性
- _changes 增量 feed 的 seq 有序性 与 last_seq 全局序号
- 数据库哈希(/db/_hash) 与 集群范围哈希(/db/_shard/{range}/_hash)
- JWT/ JWS 签名附件(把签名结果作为附件存进同一文档,实现“自包含”)
- 国内合规要求:GB/T 35273 个人信息去标识化、国密 SM3/SM4 可选替换、等保 2.0 对“不可否认性”条款
- 可复现环境:Docker-Compose 一键拉起三节点集群,公开 docker-compose.yml 与初始化脚本 即可让任何人跑相同结果
答案
给出一套“文档级 + 集群级”双通道公开验证方案,按落地顺序回答:
-
文档级完整性公开验证
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 变化,外链即失效,从而做到“公开且不可抵赖”。 -
集群级行为公开验证
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 做哈希映射,既隐藏真实资源,又保留可验性。