几乎所有的 Solidity 合约都有这个安全问题
几乎所有的Solidity合约都有这个安全问题,有些合约比其他的更严重。这个问题是Solidity编译器固有的。考虑在Solidity中实现映射:
mapping(uint256 => bytes32) mapping1;
生成的存储地址总是在0` – 2**256-1范围内。没有数学上的保证可以确定其没有冲突。事实上,在这个范围内证明冲突的存在是很容易的。
Pseudo-Demonstration
考虑定义在N1范围内的keccak256函数k:从0到2**256-1的自然数。它在EVM中的输出也是N1。此外,N1中任何元素的输出都是有保证的,输出也不是微不足道的(否则就不能满足加密要求);因此k不是恒等函数。另外:输出尽可能接近于单射。因此,它尽可能的会接近于双射(在不破坏密码属性的情况下证明双射应该是不可能的)。(我称之为伪双射。)
这种伪双射函数几乎在所有时间都不同于恒等函数,保证每个参数值至少有一次冲突(除了是当函数给出与恒等函数相同的输出时)。对于任何其他没有冲突的情况,它们必须有相同数量的有多于一次冲突的情况)。换句话说:伪双射函数不是排列,平均每个输入值有 1 次冲突,并且很有可能超过1次。k函数有可能与另一个输入发生1/(2**256-1)冲突。
重力
有些合约的风险比其他合约小。
例如,与映射相比,数组发生冲突的几率要小得多。在映射中,输入值有更广泛的可能值范围,通常由用户给出或确定。而在keccak256函数中使用的数组的索引通常范围较小,且不受用户的控制——它们更具有确定性。
那些使用映射,keccak256的合约是有非零风险。这些是目前为止最常见的。
mapping(uint256 => bytes32) mapping1; mapping(address => bytes32) mapping2; mapping(uint128 => bytes32) mapping3;
发生冲突的机会增加:
- 用户对输入值的控制
- 定义变量的数量
- 映射的输入范围
- 在这种映射中拥有的数据量(合约使用)
缓解
大多数人会认为发生冲突的几率很低。确实是这样,但既然我们有办法使它变为0,我们就应该付出努力(如果不需要额外的gas)。如果不是我们的资产被盗或我们的合约受到损害,那么所有的漏洞利用都是不重要的,也不太可能发生。所以,与其祈祷不好的事情不要发生在你的合约上,我们可以制定一些解决这个问题的方案:
- 使用salt作为存储Key的一部分来偏移输入范围NI以获得输出范围NO
- 使资产管理独立于受冲突影响的变量
- 使用组装而不是标准的Solidity解决方案
安全解决方案
使用恒等函数i而不是kecak256函数k。因为恒等函数保证在任何范围内都不会发生冲突。这是平凡排列:恒等排列。
Source:https://medium.com/@provable.laurel/almost-all-solidity-contracts-have-this-security-issue-e694cfdc5a0d
关于
ChinaDeFi - ChinaDeFi.com 是一个研究驱动的DeFi创新组织,同时我们也是区块链开发团队。每天从全球超过500个优质信息源的近900篇内容中,寻找思考更具深度、梳理更为系统的内容,以最快的速度同步到中国市场提供决策辅助材料。
Layer 2道友 - 欢迎对Layer 2感兴趣的区块链技术爱好者、研究分析人与Gavin(微信: chinadefi)联系,共同探讨Layer 2带来的落地机遇。敬请关注我们的微信公众号 “去中心化金融社区”。
|