tx.origin 사용 시 주의

견고하게 우리는 호출자 또는 트랜잭션 제작자의 주소에 액세스하는 두 가지 방법, tx.originmsg.sender 가 있습니다. 다음은 둘 사이의 차이점입니다.
  • tx.origin - Alice -> 계약_A -> 계약_B; tx.origin = 앨리스
  • msg.sender - Alice -> 계약_A -> 계약_B;msg.sender = 계약_A

  • 피싱 공격의 가능성이 있으므로 tx.origin을 사용하는 동안 주의하는 것이 중요합니다.

    예를 들어 이해해 봅시다.
  • 앨리스는 누구나 ETH를 받고 앨리스만 이체/출금할 수 있는 지갑 계약(피해자)을 생성합니다.
  • transfer() 함수에서
  • tx.origin가 발신자가 Alice인지 확인하는 데 사용되는 것을 볼 수 있습니다.

  • contract Victim {
        address owner;
    
        constructor() {
            owner = msg.sender; // Alice
        }
    
        receive() external payable {
    
        }
    
        function transfer(address _to, uint amount) external payable {
            require(tx.origin == owner, "Only owner can cause this txn");
    
            (bool sent,) = _to.call{value: amount}("");
            require(sent, "Send txn failed");
        }
    
        function getBalance() external view returns(uint) {
            return address(this).balance;
        }
    }
    


    공격자는 Alice를 속여 공격자 계약의 기능attack()을 호출함으로써 이를 이용할 수 있습니다.
  • 이것은 transfer()가 Alice와 같은 Victim 계약의 tx.origin 함수를 호출합니다.

  • interface IVictim{
        function transfer(address _to, uint amount) external payable;
        function getBalance() external view returns(uint);
    }
    
    contract Attacker {
        address attacker;
        IVictim victimContract;
    
        constructor(address _victim) {
            attacker = msg.sender;
            victimContract = IVictim(_victim);
        }
    
        function attack() external payable { // attacker will trick Alice to call this function
            victimContract.transfer(attacker, address(victimContract).balance);
        }
    }
    


    이러한 피싱 공격은 msg.sender 대신 tx.origin를 사용하여 방지할 수 있습니다.
    Alice가 Attacker 계약의 attack() 함수를 호출하도록 사기를 당하더라도 이것이 transfer() 함수를 호출할 때 msg.sender는 Attacker 계약의 주소와 같기 때문입니다. 따라서 트랜잭션이 실패합니다.

    contract VictimSafe {
        address owner;
    
        constructor() {
            owner = msg.sender;
        }
    
        receive() external payable {
    
        }
    
        function transfer(address _to, uint amount) external payable {
            require(msg.sender == owner, "Only owner can cause this txn");
            // changing tx.origin to msg.sender, to avoid phishing attack
    
            (bool sent,) = _to.call{value: amount}("");
            require(sent, "Send txn failed");
        }
    
        function getBalance() external view returns(uint) {
            return address(this).balance;
        }
    }
    

    좋은 웹페이지 즐겨찾기