把一笔订单从浏览器发往网站,再把一笔测试交易从钱包交给节点,这两件事都会出现“哈希、公钥、签名”。如果只记住算法名称,很容易做出一个危险的推论:网站已经有 HTTPS,订单自然是真的;交易验签成功,货物自然已经交付。两个推论都不成立。

本系列不从算法表开始,而从攻击者能做什么开始。本篇先看两条路径的责任边界,再拿固定订单字节做一个可以失败的摘要实验。图中的 TLS 与链节点是后续章节的研究对象:本篇没有运行 TLS 握手,也没有发送真实交易。

第一张图:订单发到 HTTPS 服务

设浏览器准备提交公开的合成订单 order_id=demo-001, sku=book, quantity=1。攻击者可能控制一段网络,能够观察、修改、转发旧数据,也可能提供一个伪装成服务端的地址。目标不是让订单“看起来复杂”,而是让客户端与服务端各自知道自己正在依赖什么。

1
2
3
4
5
6
7
8
浏览器(预期服务名、可信 CA 配置)                 HTTPS 端点
| 连接 + 验证身份 / 协商临时密钥 |
|<===== 双向 TLS 受保护通道 =======================>|
| POST /orders 合成订单 | -> 业务服务
| <--------- 应用确认 / 订单状态 ------------------|
↑ 网络攻击者可观察或注入流量

若 TLS 终止于代理:代理 -> 后端是另一段连接,须单独判断。

谁有秘密?在典型证书认证握手中,服务器持有与证书公钥相配的私钥,客户端与服务器用临时交换建立只供当前连接使用的秘密;CA 的签发私钥不应在服务器上。浏览器从预期服务名和自身配置的可信根出发,验证“通信端点的密钥与预期名称是否按规则绑定”。这不是用证书公钥直接加密每一笔订单;详细的握手消息、派生和记录加密留到 14–16。

TLS 防网络上的第三方轻易读到或悄悄改掉受保护记录,并帮助浏览器认证连接到的端点。但如果攻击者控制的是正确站点的业务账户,或者拿到了一个有效的应用登录会话,TLS 并不能辨认订单应不应该被处理。若代理解开 TLS 后把明文交给后端,这段后续连接也不能因为浏览器一侧出现了挂锁图标就自动算作受保护。安全性属于明确的端点和连接段,不属于一整个业务故事。

删掉身份核对会怎样?只加密却不检查服务名与可信公钥绑定,冒充站点的对手可以分别和浏览器、真正服务端建立加密连接,在中间读取和改写订单。删掉记录保护,能改包的对手便可能把 quantity=1 换成别的值。即使两步都保留,重放一个之前合法的业务请求是否会重复下单,仍取决于应用层是否设置唯一请求标识、有效期和消费状态;TLS 不能自动保证业务幂等。

第二张图:钱包发出测试交易

现在合成订单的某个标识与测试资产相关,钱包向无价值的开发网络发出一笔交易,RPC 接口走 HTTPS。这里容易把两层都叫“安全连接”,进而混淆它们验证的东西。

1
2
3
4
5
6
7
8
9
10
钱包(本地持有私钥)
| 交易字段 -> 确定的签名字节 -> 生成签名
| 原始交易 --[HTTPS:认证 RPC 端点、保护传输]--> RPC 节点
| |
| 验签 + 交易规则 + 状态检查
| |
| 广播 / 执行 / 纳入共同历史
| |
| RPC 回执 <--[HTTPS]------------------------|
| 再查询交易、区块与结果:分别核对,不凭回执猜测

钱包私钥留在钱包控制范围内;节点持有可公开验证的规则、交易及相关公钥或可验证的支出条件,不需要知道钱包私钥。真正被签名的是该链按具体交易类型规定的字节,而不是网页上的“订单描述”;Bitcoin 和 Ethereum 的规则不相同,27、28 再逐项核对。交易字段往往是公开的,交易签名也不是加密交易内容。节点即使通过签名检查,还须检查余额或未花费输出、业务规则、链和状态等条件。请求已提交 RPC 不表示交易执行成功;进入某个区块不自动意味着按所需确认策略不可逆;链上状态不证明现实货物已经交付。

删掉交易签名,任何看到交易字段的人就可以伪造一笔“来自你”的支出;只保留交易签名却不核对所签的交易字节或正确授权条件,也会让授权落在错误对象上。删掉 HTTPS,RPC 路上的第三方可能窥视请求、替换节点回复或阻断发送;但能否替换为一笔以钱包私钥有效授权的新支出,仍由链上签名与交易规则决定。反过来,有 HTTPS 也不能替钱包生成有权支出的签名。

两张图里出现的“可信公钥”不是同一种起点。浏览器要通过服务名与受信 CA 路径寻找可信的服务密钥;节点要根据其账本规则和交易字段确定哪个公钥或条件可以授权这笔交易;未来讲 Merkle 包含证明,还要先知道所拿的区块头或根为何可信。随手从收到的消息里拿一个公钥或根来验,计算结果可以为真,身份结论却可能是假。

摘要实验:相等能否代表可信

先从只有公开字节的步骤开始。examples/cryptography/00_bytes.py 固定使用 Python 3 标准库;它把订单按当前实验规定的 JSON 键序与分隔符编码成 UTF-8,再计算 SHA-256。这个编码规则只是本实验双方约定的消息格式,不能拿来宣称所有 JSON 文本天然规范化。

1
2
3
4
输入  {"order_id":"demo-001","quantity":1,"sku":"book"}
UTF-8 -> 原单字节 -> SHA-256 -> 原单摘要
│
改单 quantity=9 -> 新字节 -> 新摘要

在仓库根目录运行:

1
2
python3 examples/cryptography/00_bytes.py
python3 -m unittest discover -s examples/cryptography -p 'test_00*.py' -v

2026-10-06 UTC,在 Python 3.12.3 上执行了两条命令,退出码均为 0,四个单元测试通过。原单摘要是 a9e337c6b3839760edbb1be0431f51e0153cfec257ca8a7f12e91e649f04a320;将数量改为 9 后,摘要变成 e3da07c91627e10ebf33e5c5b83ee65a0a9917f7ba148ef24f39a14fad314af8。用原单的可信预期摘要校验改单,断言失败;如果允许攻击者把消息和“预期摘要”一起换掉,相等检查又成功。这不是发现 SHA-256 碰撞,而是预期摘要没有可信来源。

这一步只有输入字节与摘要,没有私钥、CA 或链;它不证明通信身份、加密能力或交易授权。接下来的章节分别给出“如何确定哪些字节”“谁能生成认证值”“谁能公开验证”以及“验证对象怎么绑定身份与用途”。

两道带答案的练习

画图题。 在第二张图上标出哪条边依赖 TLS,哪一步依赖钱包私钥。如果 RPC 端点收到一笔验签成功却余额不足的交易,是否应在订单系统里标记“已经交付”?

可核对答案: 钱包到 RPC 的通信段依赖 TLS;钱包生成链上授权依赖钱包私钥,节点按链上条件验签。余额不足还会触发交易规则失败,验签不能推出可执行、已确认,更无法证明现实交付。即使 RPC 返回哈希,也必须分别查交易状态、区块与业务订单。

变更题。 修改 examples/cryptography/00_bytes.py 中的 ORDER,把 quantity 从 1 改为 9,但让对照用的 altered 改为 1;重新运行测试和脚本,哪些断言会先失败?若攻击者能同时替换消息与预期摘要,哪一个布尔值仍为真?

可核对答案: 未同步修改测试时,test_order_encoding_is_explicit_and_reproducible 中固定的字节断言会失败;test_reusing_original_digest_rejects_altered_order 原本写死“改单为 9”,此时与原单同为 9,其拒绝断言也会失败。运行脚本时,新原单与数量为 1 的改单摘要不同,固定预期摘要下改单不匹配,而“改单 + 攻击者自行算出的改单摘要”仍为真。若意外都通过,应先检查是否真的修改了源码、是否运行了同一目录下的文件,不能只看到退出码就认定反例成立。

这里四个新词可先带走:消息字节是进入算法的确切输入;摘要是公开哈希的输出;可信起点决定拿哪个摘要、公钥或根来校验;交易授权是对规定的交易字节执行有权签名的判定。别的术语可随 01–13 的攻击和操作逐步补齐。

资料与继续阅读