如何验证链上哈希未被篡改?
解读
在国内 CouchDB 面试中,面试官提出“链上哈希”并非让你去讲比特币或以太坊,而是把 CouchDB 的文档版本链(_rev 树)当成一条“轻量级区块链”,考察你能否用数据库原生机制自证数据未被篡改。核心诉求是:
- 不依赖外部区块链,仅用 CouchDB 内置能力完成“篡改检测”;
- 回答必须落地到HTTP 接口、Erlang 层验证、国内等保/国密合规三个维度;
- 区分“单节点篡改”与“多主集群恶意回滚”两种场景,给出可落地的验证脚本与运维方案。
知识点
- _rev 树与 MVCC:CouchDB 每次更新都生成新的 revision 节点,形成不可变的树形历史,叶子节点即为最新合法版本。
- _changes 连续 feed:国内金融项目常用
?feed=continuous&heartbeat=30000&since=now做实时审计流,每条变更带 seq 与 rev,可视为“链上高度”。 - Erlang 层校验和:
couch_db:validate_doc_hash/2在写入前计算sha256(<<Id,Rev,Body>>),与 _local/sha256 中的预期值比对,防内存级篡改。 - 国密 SM3 插件:国产信创环境需替换默认哈希,在 etc/vm.args 加
-couch_hash_alg sm3,验证脚本同步升级。 - 多主回滚检测:利用
/_node/_local/_changes与各节点 seq 一致性哈希,若出现 seq 回退或 rev 树分叉深度 > max_revs_limit,即可判定“链”被恶意回滚。
答案
验证步骤(可直接在面试官笔记本上演示):
-
生成可信基线
写入文档后立刻抓取:curl -u $user:$pass http://127.0.0.1:5984/mydb/doc1?revs=true > baseline.json提取 id、rev、body 的 SM3 哈希并写入 _local 可信区:
echo -n "doc1-3-abc{...}" | openssl dgst -sm3 -binary | base64 curl -X PUT -u $user:$pass http://127.0.0.1:5984/mydb/_local/sha3-doc1 \ -d '{"sm3":"q8T+W7m...","seq":42}' -
周期性自检脚本(符合等保审计要求)
#!/bin/bash DOC=$(curl -s -u $user:$pass http://127.0.0.1:5984/mydb/doc1?revs=true) REV=$(echo "$DOC" | jq -r '._rev') BODY=$(echo "$DOC" | jq -c 'del(._rev)|del(._id)') CALC_SM3=$(echo -n "doc1-$REV-$BODY" | openssl dgst -sm3 -binary | base64) STORED_SM3=$(curl -s -u $user:$pass http://127.0.0.1:5984/mydb/_local/sha3-doc1 | jq -r '.sm3') if [[ "$CALC_SM3" != "$STORED_SM3" ]]; then echo "ALERT: 链上哈希被篡改" # 触发国产 SOC 平台 webhook fi脚本放 crontab 每分钟执行,输出到 syslog 并对接国内 SOC,满足等保 2.0 审计留存 180 天要求。
-
多主集群防回滚
在各节点运行:curl -u $user:$pass http://node{1..3}:5984/mydb/_changes?since=0&limit=1 | jq '.last_seq'若任一节点 last_seq 小于基线 seq,或 rev 树深度突增,立即标记“链分叉”,通过 CouchDB 的 pre-commit hook 拒绝新写入,并通知运维人工介入。
拓展思考
-
Q:如果攻击者连 _local 也一起改怎么办?
答:把 基线哈希再写一份到外部 WORM 存储(国产蓝光光盘或华为 OceanStor 锁盘),CouchDB 侧只存引用指针,实现离线不可抵赖。 -
Q:如何验证附件(_attachments)哈希?
答:附件有 stub+length+revpos 三元组,脚本里把atts按revpos排序后计算 SM3 累积哈希,再与基线比对;大文件用流式分片,防止内存打爆。 -
Q:能否用 Fabric 等真区块链再存一次?
答:可以,但国内银行生产网常隔离外网,更实用做法是把 CouchDB 的 seq 与哈希每日批量写入内部联盟链(如长安链),实现“链上链”双锚定,既满足监管,又保持 CouchDB 原生性能。