Solidity有一个全局变量tx.origin,它遍历整个调用堆栈,并返回原先发送调用(或事务)的帐户地址。在智能合约中使用此变量进行身份验证会使合约很容易受到类似网络钓鱼的攻击。
坑点分析
授权用户使用tx.origin变量的合约通常容易受到网络钓鱼攻击,这种攻击可以欺骗用户在漏洞合约上执行授权操作。
例如下面合约: image
这份合约使用tx.origin授权了withdrawAll ()函数,因此,它允许攻击者创建一个攻击合约,如下代码所示: image
为了利用这个合约,攻击者会先对其进行部署,然后说服Phishable合约的所有者向这份合约发送某些数量的以太币。攻击者可以把这个合约伪装成他们自己的私人地址,然后让受害者向地址发送某种形式的交易。
如果不是特别谨慎,几乎不可能注意到代码中有攻击者的地址。而且攻击者也可能会把它当做一个多重签名钱包或者一些高级的存储钱包。
无论什么时候,只要受害者向AttackContract地址发送一个交易(有足够的gas),它都将调用fallback函数,fallback函数又调用Phishable合约的withdrawal()函数,调用参数为attacker。
这样一来就会造成,从Phishable合约中取回所有的资金到了攻击者的地址上。因为这是受害者第一个初始化调用的地址(即Phishable合约的拥有者)。因此,tx.origin会等于owner,这样,在Phishable合约第11行上的require将会顺利执行。
避坑技巧
通过上文可以看出,在智能合约中,不应该使用tx.origin作为授权。这并不是说永远不应该使用tx.origin变量。它在智能合约中确实有一些合法的用例。
例如,如果一个人想要拒绝外部合约调用当前的合约,可以通过require(tx.origin == msg.sender)实现这一要求。这就阻止了中间合约被用来调用当前的合约,从而将合约限制为无码地址。
真实案例:未知