文章讨论了EIP-3074中AUTH/AUTHCALL机制的安全风险,指出该机制要求用户签署一个“空白支票”,将所有操作权限委托给调用者,可能导致恶意或有漏洞的调用者代表用户执行任何操作,包括盗取资产、操纵投票、控制合约等,且无法撤销。
从开发者的角度来看,AUTH
/ AUTHCALL
机制非常吸引人。它使任何人都有能力提出一个调用者,该调用者可以实现不同的批处理策略(例如,支持多个 nonce 以获得更好的并行性)、gas 抽象模型、复杂的账户抽象方法等。
这种灵活性来自于对该机制的使用方式完全不带偏见。我们不需要开发者遵守特定的模式,而是要求用户签署一个由调用者解析的 commit
哈希,并让每个开发者根据 commit 设置可自由决定的限制。
然而,这种灵活性带来了极高的安全成本。我想提出一个更简单的替代方案的案例,它能以低得多的风险获得我们大部分的好处。
为什么签署 AUTH commit
比签署到任何其他有漏洞/恶意的合约的交易风险更高?
当签署一笔到合约的交易时,用户会承担由该合约控制的资产损失的已知风险。用户可以签署一笔到 ERC20 合约的批准交易,批准一个恶意的 DEX 合约。这个恶意的 DEX 合约可以随后提取用户在该 ERC20 中的全部余额。但是……在没有特定批准的情况下,它不能从其他 ERC20 合约中提取用户的代币。它也不能代表用户做任何其他事情。批准是特定的。
另一方面,EIP 3074 要求用户签署一张空白支票,并假定调用者是诚实的且没有漏洞的。一个恶意/有漏洞的调用者可以代表用户做任何事情 - 访问用户拥有的任何资产,代表用户投票,取得用户拥有的任何合约的所有权等。
更糟糕的是,调用者现在和将来都可以这样做,因为 nonce 的实现是由调用者控制的。nonce 逻辑的一个有漏洞/恶意的实现可能允许重放用户过去的交易。结合 commit
验证的其他部分的有漏洞的逻辑,它可以被用来代表用户执行任何未来的操作。即使发现了漏洞,用户也无法撤销这张空白支票。EOA 永远被攻破了。
编写一个正确的调用者是棘手的,而且我们几乎可以肯定偶尔会出错。EIP 末尾的调用者应警惕的非详尽的检查/陷阱/条件列表让我们对这一点有所了解。这个列表将不可避免地增长,可能通过一个痛苦的发现过程。
此外,一个恶意的行为者可以实现一个看起来诚实的调用者,其中包含一个故意的细微漏洞,这个漏洞将在大量 EOA 对该调用者进行 AUTH 之后被利用。
如果攻击没有直接或立即从用户那里窃取,那么它可能会在很长一段时间内不被注意到。
治理劫持示例
EveSwap 的用户不太可能注意到这个过程,因为他们的交易总是成功的,但最终结果对 AliceSwap 来说是毁灭性的。
跨链重放示例
EIP 正确地建议 commit
应该覆盖 chainid
。但是,这不是由协议强制执行的,而只是由调用者强制执行的。另一个链上具有相同地址的调用者可能会跳过此检查(或任何检查)。
commit
。它只检查 ownerOnly
并充当其所有者的通用 AUTH/AUTHCALL 代理。用户从未在以太坊上进行过交易,并且在 BobSpongeChain 上运行的调用者经过了严格的安全审计,并被认为是安全的。然而,每个人都损失了他们的资产。
以太坊通过 EIP-155 中的重放保护来防止这种情况。AUTHCALL 不会。通过将所有 commit
检查委托给调用者,我们失去了以太坊提供的任何交易保护。攻击之所以成为可能,是因为保护成为可自由决定的。如果该 EIP 被接受,则 AUTH 消息必须显式包含 chainid
,而不是作为 commit
的一部分。
我们能做什么替代方案?
我的建议是实现一个更具有倾向性的机制,该机制在协议层面强制执行 commit
的含义。commit 结构将被类型化(如 EIP 712 中那样),因此钱包将以用户可读的格式显示它。用户将确切地知道交易会是什么样子,并且确信它以后无法在任何链上重放,而无需依赖于实现调用者的单个开发者的诚实和能力。
一个可能的实现:
AUTH
将用一个包含授权调用列表的类型化结构替换 commit
哈希。对于每个调用,将指定 {nonce,to,gas,calldata,value,chainid}。签名将被验证,并且整个列表将被保存为 authorized_transactions
,而不是 authorized
地址变量。
AUTHCALL
将获得一个新的参数 index
,该参数指向由最后一个 AUTH
创建的列表中的一个地址。
EOA 的 nonce 将在每次 AUTHCALL
时递增。不是由调用者存储的 nonce,而是实际的账户 nonce。
优点:
缺点:
不同的实现可以支持不同的 nonce 方案。但是无论我们使用什么机制,都必须由协议而不是调用者强制执行。
无论如何,都应该阻止执行大量用户调用的复杂调用者。复杂的操作应该被实现为一个普通的智能合约,而不是试图使用多个 EOA 调用来实现一个算法。
替代方案:完全避免硬分叉
另一种选择是完全避免 AUTH 机制,并通过 @vbuterin 建议的替代 mempool 来解决账户抽象和批处理问题。
优点:
缺点:
除非要求是在没有迁移的情况下支持现有的 EOA,否则这似乎是更安全的选择。
- 原文链接: ethereum-magicians.org/t...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!