加固资金通路:KVR 结算中的交易安全
三类真实漏洞——支付签名重放、无鉴权奖励铸造、竞态双花——在网关结算服务中被发现、用测试利用并封堵。
在 DePIN 中,资金通路与算力通路同样充满对抗:每一个记账 KVR 的端点,终将被想不劳而获的人试探。对网关结算服务——验证链上支付并记账质押、节点奖励与推理费用的进程——的一次安全审查发现并封堵了三类真实漏洞。每一类都在修复前用攻击式测试演示,修复后重新验证。
验证链上事实,而非客户端声称
Kvasir 的托管模型把密钥留在用户手里:钱包签署交易,Solana 记录交易,结算服务的职责是在触碰任何余额前验证链上真正发生了什么。支付遵循 *quote → payment → inference*,每个被消费的交易签名都记入一次性 usedSignatures 注册表,永远无法二次出示。这使结算服务成为咽喉要道——它绝不能违背的规则只有一条:只记账链证明的东西,绝不记账客户端声称的东西。不过,该服务在 devnet 上确实持有资金:在链上质押程序上线之前,已质押的 KVR 和预付额度存放在其 treasury 中,并记录在其账本里。

把支付绑定到付款人
Solana 签名是公开的。质押验证路径只检查 vault 是否*收到*了预期的 KVR——从不检查*是谁发的*。攻击者可以在 devnet 上盯着受害者的 KVR→vault 转账,然后提交 {owner: 攻击者, signature: 受害者的}:vault 收款检查通过,本金记到攻击者名下,一次 unstake 后资金就归攻击者了。仅凭一个区块浏览器即可完成的直接盗窃。
修复:KVR 必须是从被记账 owner 拥有的代币账户中扣出的。
verifyStakeTransfer(signature, owner, amount):
delta(vault) >= amount # vault actually received it (old check)
Σ debits from token accounts
whose owner == credited owner # NEW — sender binding
>= amount # summed across that owner's accounts
# inference path (no owner): bound by private requestId
# + one-shot usedSignatures instead奖励只来自经过认证的来源
节点奖励端点曾用自报输入铸造可领取的 KVR:POST /api/node/contribution 照单全收客户端声称的 units——units: 1e9 加一次 claim 就能掏空 vault——register/heartbeat 也照信自称的 hub/网关角色(按小时的基础设施奖励)和性能分(奖励乘数)。修复把每一项影响奖励的断言都关进可信上报者之后:只有 hub 贡献轮询所用的 M2M 服务令牌,或经认证的管理员,才能断言 units、基础设施角色或性能等级——即使在开放 LAN 模式下也强制执行,因为这些会铸造 KVR。令牌比较是常数时间的;钱包↔节点关联仍然自由,只是不能再自报奖励。
每个余额只有一个写入者
结算状态是无锁的读-改-写,而每个资金操作中途都会 *await* 一次链上支付或验证——握着过期余额把事件循环让了出去。两个并发 claim 可以读到同一笔 100 KVR 待领余额并都付出去。这不是理论:攻击测试显示三个并发 claim 对 100 的余额付出了 300。
按键异步串行化:同键资金操作严格先后执行。
withLock(key, fn) # per-key promise chain, self-cleaning map stake / unstake / claim → keyed by owner inference settlement → keyed by requestId inside the lock: usedSignatures check + credit # no same-signature double-credit pay out FIRST, then debit # failed payout leaves balance intact
各层现状
| 层 | 机制 |
|---|---|
| 身份 | 对服务器 nonce 的 SIWS 钱包签名登录 + TOTP 2FA + 一次性备份码 |
| 传输 | 分片下载用钱包派生 node token;中继上的构建指纹一致性 |
| 支付 | 质押转账的发送者绑定;一次性 usedSignatures;推理的私有 requestId |
| 结算 | 每次余额写入都有按键锁;先付后扣;幂等重提交 |
| 上报 | 影响奖励的事实仅限 M2M 服务令牌或管理员,常数时间比较 |
| 托管 | 非托管钱包——服务只能动 vault 里的钱,永远碰不到用户密钥 |
每个修复都自带攻击测试
- 用攻击者钱包重放受害者转账签名现在会被拒绝("not sent by owner");正常质押、超额领取与推理支付行为不变。
- 对同一余额的三个并发 claim 恰好支付一次;对已支付推理的重提交幂等地返回相同结果。
- 无鉴权客户端自报的
units、hub/网关角色和性能等级,再也动不了奖励的一个 lamport。
三个修复的贯穿线是同一条原则的三种应用:链是事实之源,服务是验证者,每个余额恰有一个写入者。结算服务仍运行在 Solana devnet 上——这恰恰是在主网抬高赌注之前发现、利用并修复这些漏洞类别的最佳场所。