solidity智慧合約中tx.origin的正確使用場景
阿新 • • 發佈:2019-07-18
簡介
tx.origin是Solidity的一個全域性變數,它遍歷整個呼叫棧並返回最初發送呼叫(或事務)的帳戶的地址。在智慧合約中使用此變數進行身份驗證會使合約容易受到類似網路釣魚的攻擊。
但針對tx.origin的使用並不用談虎色變,正確的使用還是有它的應用場景的。
漏洞詳解
漏洞合約
在如下合約中使用到了tx.origin的判斷。
pragma solidity ^0.4.11; // 不要使用這個合約,其中包含一個 bug。 contract TxUserWallet { address owner; function TxUserWallet() public { owner = msg.sender; } function transferTo(address dest, uint amount) public { require(tx.origin == owner); dest.transfer(amount); } }
上面的合約提供了建構函式(新版本中使用constructor)和轉賬方法。其中在轉賬方法transferTo中進行了owner的判斷,這裡用到了tx.origin。
攻擊者合約
下面看一下攻擊者的合約:
pragma solidity ^0.4.11; interface TxUserWallet { function transferTo(address dest, uint amount) public; } contract TxAttackWallet { address owner; function TxAttackWallet() public { owner = msg.sender; } function () public { TxUserWallet(msg.sender).transferTo(owner, msg.sender.balance); } }
攻擊者建立一個上面的合約,然後通過各種騙術來欺騙你用正常合約(TxUserWallet)的擁有者的地址向該攻擊合約(TxAttackWallet)轉賬。然後區塊鏈會預設呼叫攻擊合約的fallback方法,也就是最後沒有方法名的方法,並執行轉賬操作。
而此時TxUserWallet合約裡面的校驗是可以正常通過的。因為tx.origin是最初發起交易的地址,也就是合約擁有者的地址。然後,地址裡面的ether便被轉到攻擊者地址中。
使用提醒
tx.origin不應該用於智慧合約的授權。更多的時候採用msg.sender == owner來進行判斷。
但它也有自己使用的場景,比如想要拒絕外部合約呼叫當前合約則可使用require(tx.origin ==msg.sender)來進行實現。