防止意外的RAM消耗

原文地址:https://medium.com/eosio/preventing-unexpected-ram-consumption-8029a9342659

有些用户和基于EOSIO的智能合约在无意中被创建特殊智能合约的恶意第三方消耗他们的RAM资源。发生这种情况的原因是对通知功能的认识误区,这个功能目的在于使合约能够将事件通知给其他合约,例如资金转入转出事件。恶意合约使用此通知功能可以在未通知其他人且未经其他人同意的情况下使用随机数据消耗他们的RAM,并且他们无法释放此数据。

概述

没有代币被盗

正确实现的合约不容易受到攻击

治理程序可以修复与各方意图相悖的代码行为

4 Block Producer-only mitigation选项可用于保护

持续升级可以使默认行为更安全

没有代币丢失

恶意合约利用了对智能合约开发者和用户对开发智能合约的最佳实践的认识误区。这种攻击类似于故意破坏而非盗窃,一旦EOS治理程序可以审查和纠正这种情况,就不会对相关各方造成长期损害。

防止滥用的最佳实践

我们希望每个用户审查与他们交互的合约,或信任第三方代表他们审查合约。这意味着审查者应该谨慎地与使用通知功能的智能合约进行交互。举个例子,将代币发送给他们不信任的CPU和RAM资源的智能合约。

编程将代币发送到不受信任的第三方指定的帐户的开发人员应通过没有可用RAM资源的帐户中继传输。这既适用于处理用户提款的中心化交易,也适用于通过智能合约执行去中心化交易。这里有几个可信的中继合约可用。

当事务可能消耗RAM时,大多数钱包供应商会采取措施警告用户。

通过治理程序释放消耗的RAM

我认为代码的意图与用户和开发人员所希望的结果的一致的,应该得到执行。如果恶意合约明显地利用了用户的意图与代码的实际效果之间的不匹配,那么恶意合约的始作俑者与与之交互的合约纠纷被仲裁时,块生产者有权将恶意合约列入黑名单。

如果仲裁发现代码的行为违背了与代码交互的各方的意图,那么当选的生产者可以不受约束地更新代码,使得结果与各方的原始意图尽可能匹配。在这种情况下,代码将被更新来释放意外消耗的RAM并且将来不再消耗RAM。

为什么这是EOSIO的一个功能?

有许多真实的使用案例表明该功能被滥用来消耗RAM。最基本的案例是想要接收用户资金存款的游戏合约。交易所将用代码实现处理来自代币合约的转账通知,然后在交易所将余额记入发送者。在这种情况下,交易所和存款用户可以合理地授权交易合约消耗用户的RAM来存储他们的余额。交易不一定要将用户的余额存储在他们自己的RAM中,因为这可能导致不同的攻击,比如说许多帐户同时向交易所发送很小的余额。

EOSIO有一个相关的功能,内联动作,允许合约调用另一个合约的代码作为当前交易的一部分。与操作通知功能不同,内联动作仅限于分配生成内联动作的合约资源。动作通知推进了原始动作的资源分配权限。

防止意外行为的发生

虽然现有的设计很多用在了合理用途,但我们现在发现代码的默认行为与用户和开发人员的直觉相反。为了简化不太常见的用例,必须采取的防止滥用的步骤,但这同时也使正常的用例更加复杂。

在以后,我们建议通知处理器只有权使用接收通知的合约的RAM。这样可以安全地将代币发送到任何合约,而不必担心它以意想不到的方式消耗你的RAM。如此交易所无需在处理提款请求之前审查部署到用户帐户的合约才可安全地处理提款了。

根据此提议的更改,现有合约必须获得直接授权以使用一些用户可用的RAM。在接受用户的存款之前,交换合约将请求用户“开打账户以预留存储其余额的空间”。然后,转入的存款通知将仅增加预先分配的RAM,而不是分配新的RAM。

建议的升级

我们正在准备一个生产者专用的升级版本,它将改变默认行为,以防止动作通知的接收者(例如代币转移通知)意外消耗发送者的RAM。如果所有块生产者都采用此升级,那么滥用缓解策略就不需要了。因为不幸的是,直到它们可以更新为在动作通知处理器不依赖于用户帐户上的RAM分配前,这种缓解策略可能会破坏有效合约。

幸运的是,采用新的最佳实践的合约升级过程应该相对简单。

作为下一次公投的一部分,所有节点都将升级为生产者专用的版本。

结论

EOSIO的设计符合设计要求,并且在正确使用时是安全的。我们相信,我们可以更轻松地使用EOSIO开发大多数的用例,同时我们将与EOS社区合作开发最强大的整体解决方案。​​​​