这段代码此刻要求每一个乐成的解锁挪用都包括一个序列号。因为动静中得包括一个唯一无二的数字,所以每次乐成挪用所要求的签名都是唯一无二的。这暗示之前视察到的动静对进攻者来说没用了,因为重放会失败。
暗码学签名大大都的暗码学签名体系都基于公私钥对。私钥可以或许对数据举办签名,并且此签名可以或许被对应的公钥所验证。就像它的名字所体现的一样,一个用户的公钥是果真的,而私钥则必然要保密。
address signer = ecrecover(msgHash, v, r, s);
数据完整的可验证性,意思是签名可以用于证明自签名以来数据未被修改。
function unlock( address_to, uint256_amount, uint8[]_v, bytes32[]_r, bytes32[]_s) external{ require(_v.length >= 5); bytes32 hashData = keccak256(_to,_amount); for (uint i = 0; i <_v.length; i++) { address recAddr = ecrecover(hashData,_v[i],_r[i],_s[i]); require(_isValidator(recAddr)); } to.transfer(_amount);}
Bob 在与以太坊毗连的另一条链上有等价于 10ETH 的资产被他通过桥接器传回了以太坊链上。
Bob 此刻可以复制这个签名值的序列而且本身提交一个一模一样的解锁函数挪用请求。这个解锁的操纵可以或许再一次乐成,导致又一个 10ETH 被发送给 Bob。
改造手段以上景象被称为签名重放进攻。这种进攻能乐成是由于我们无法验证所签名动静的独一性,也不知道它之前是否被用过。
与签名验证相关的裂痕凡是是由于误解了底层的暗码学道理和签名的目标而引起的。因此,在具体相识此特定裂痕之前,我们先快速相识一下暗码学签名的事情道理。
任何特另外查抄,岂论是查抄签名地点是否为正确地点,照旧查抄被签名的动静是否独一,都必需被手动添加进智能public uint256 nonce;function unlock( address_to, uint256_amount, uint256_nonce, uint8[]_v, bytes32[]_r, bytes32[]_s) external{ require(_v.length >= 5); require(_nonce == nonce++); bytes32 hashData = keccak256(_to,_amount,_nonce); for (uint i = 0; i <_v.length; i++) { address recAddr = ecrecover(hashData,_v[i],_r[i],_s[i]); require(_isValidator(recAddr)); } to.transfer(_amount);}
作者:Stefan BeyerAlice 是一个处理惩罚跨链生意业务的中继者。她收集了必须的验证者签名,在所毗连的链上锁定了相对应的资产数量,而且挪用 unlock 函数将 10ETH 从合约中释放给 Bob。
对数据举办加密签名可实现两个重要属性:
这个要领的输入参数是签名值 v,r 和 s,以及签名数据的 keccak256 哈希值。它可以校验数据的完整性,即确认数字签名与数据的哈希值相对应,而且可以从签名中规复签名者的以太坊地点(以太坊地点乃是从公钥中推导出来的)。
可是,这段代码并不完美。它并没有遵循签名验证的最佳实践。原因是它没有查抄可塑性签名,我们应查抄作为已接管签名一部门的 s 值是否在较低范畴内。利用 ecrecover 函数的推荐流程可以在 Open Zeppelin 的 excellent ECDSA 库中找到。事实上,在社区审计过的代码,好比 Open Zeppelin 长举办开拓,老是一个好主意。
Bob 可以或许反复这个进程直到智能合约中的以太坊被耗尽。
进攻情景郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。