密码学 39:结课二——经 HTTPS 提交交易,分别验证通信与账本
钱包用 HTTPS RPC 提交了一笔“支付测试订单”的 Ethereum 交易,RPC 返回哈希,收据显示 status=1。这意味着什么?它不意味着现实商家已经履约;更不意味着仅凭一个 HTTPS 连接,就能信任 RPC 提供的区块头在预期链的共同历史中。本结课真正需要的,是在同一条实际传输路径上把通道身份、签名授权、规则/状态、交易包含、最终性与现实结果逐个分开,并对错身份、重放和错链给出独立失败证据。
一张贯通图:五问各向谁要答案
1 | |
浏览器订单与交易是两条不同授权关系。浏览器发合成订单通过 TLS 保护通信;钱包对有类型交易签名授权账本变化。钱包私钥不该交给 RPC。RPC 证书由谁认证?客户端只信这次在临时目录生成并显式加载的测试 CA,校验 orders.test 的 SAN;把 hostname 改成 attacker.test,握手就失败。这个名字在本地 /rpc 是合成端点标识,不声称公网 DNS 真的有相应服务。
节点怎样看懂交易?钱包离线构造 EIP-1559 type-2 的 chainId=131277322940537、账户 nonce、接收地址、100 wei、gas 与费用上限,然后真实签名。以太坊 type-2 签名不是签 HTTP POST 的文本,也不是签 TLS 记录;它签该交易类型定义的字段编码。服务实际收到经 TLS 传输的带签名 raw transaction,开发链解码执行,返回的是该笔签名字节的交易哈希。签名可以由第三方核对,但交易能否执行还取决于账户余额、nonce、费用、链规则等,跟 HTTPS 是否绿灯是两回事。
实际跨层可失败实验
examples/cryptography/39_https_rpc.py 用独立无价值 Prague 开发链、真实 Python TLS 1.3 回环服务器及只接受少量 JSON-RPC 方法的网关。钱包先获测试资产,再从内存生成临时私钥并在客户端签署 type-2 交易;客户端依次经 HTTPS 查链 ID、发 eth_sendRawTransaction、查 eth_getTransactionReceipt,并另外做以下检查:
- 错 TLS 主机名阻止发起 RPC;这拒绝的是服务端身份,不需要也不能靠钱包签名弥补。
- 同一原始交易再次提交,由开发链的账户 nonce 状态拒绝;此前签名仍针对同样字节验真,变的是可执行性。
- 另签一笔错误链 ID 的 type-2 交易,被网关自己的预检查拒绝;这项仅证明本网关有额外检查,不证明后端链规则正确。
- 本地 receipt
status=1、受款测试账户余额增加 100 wei,是执行观察;区块头的transaction_root另与从所含真实交易重建的 trie 根相同,proof 只对这个本地区块头验真。把预期根改成零值,证明路径无法成立。
先按仓库内 examples/cryptography/README.md 完成环境准备;以下命令从仓库根目录执行。
1 | |
本地 1 项集成测试通过,输出只有布尔结果,私钥不进仓库或日志。不可掩盖的失败边界来自 28:这个冻结版 py-evm==0.12.1b1 Prague 后端曾实测接纳并执行错误 chain ID 的 type-2 交易;39 网关拒错链 ID 不能擦掉这个后端偏差。因此脚本明确 wrong_chain_id_rejected_by_backend_verified=false;独立客户端交叉核查仍 NOT_RUN,不应宣称节点的跨链重放边界通过。代码只运行单进程自创世开发链,不代表公网安全状态。
“看见结果”仍不等于“确认结果”
测试收据来自同一进程,测试 trie 的期望区块头根也来自它本身。攻击者如果控制 RPC 并给你伪造的整套头、交易和 proof,即使你重新计算路径,也没有从外部独立证明该头属于你信任的共同历史。HTTPS 可以帮助确认你连接的是配置的 RPC 服务,而不能证明它说的账本历史没错;外部轻客户端/可信共识来源以及确认策略仍需独立实现。Bitcoin regtest 的 UTXO sighash 与确认链路更不能用 Ethereum type-2 结果冒充。
当应用说“交易对应现实订单”,还要能回答哪个订单号和金额被签进了哪份应用授权、谁关联交易与订单、退款和交付按什么状态机完成。普通 Ethereum 转账成功只说明本地链中状态有过指定变化;签名验真、receipt 成功、包含证明、可信最终性、现实交付是五个不同断言。看清每个断言,才能在失败时找对修复位置。
两道可检查练习
画图题: 在图上写出每处秘密的持有人与验证者:TLS 服务证书私钥、钱包交易私钥、Prague 测试链中的账户状态、可信区块头根。若只拿到 RPC 返回 status=1 和根证明,还缺少哪种输入才能宣称“这笔交易已在我认可的共同历史里达到要求的确认”?
答案: TLS 服务持证书私钥,钱包独有交易私钥;客户端按临时 CA/服务名校验前者,链组件按账户及交易字节检查后者。状态不是私钥,头根不是可独自相信的秘密;第三方应按自己认可的链规则/共识状态获得并核查预期头与确认或最终性,再对照 proof。一个同进程生成的收据不提供独立历史来源,更没有现实履约输入。
实验变更题: 在网关的 TypedTransaction.from_bytes(raw)...chainId 预检查处暂时去掉“必须等于 CHAIN_ID”判断,再送正确 nonce、错误 chain ID 的新签交易。怎样记录观察才不掩盖缺陷?另把发送客户端 hostname 改成 attacker.test,要在哪一步失败?
答案: 对当前冻结 py-evm 后端,28 已实测错链签名可能被执行;此实验若重现,应明确写“后端错误链接受/执行=true,节点级验收失败”,即使 EIP-712 应用模型或网关预检在别处能拒也不能改写。错 TLS 主机名应在建立 HTTPS 连接/验证证书时失败,绝不能因钱包交易签名有效而放过服务器身份校验。
资料与衔接
- EIP-1559 · EIP-155 · Ethereum Yellow Paper · RFC 9846。本篇实际运行的是受限本地 RPC,并非完整公开 Ethereum 节点。
- 28:Ethereum 签名字节与 EIP-712 · 29:Merkle 根与可信头 · 38:HTTPS 订单。






