외부 계약 방지

견고성 스마트 계약에서 볼 수 있는 거의 모든 취약성은 일부 공격자 계약을 개발한 해커와 이 공격자 계약이 취약한 계약에 해를 끼치는 데 의해 발생합니다.
그건 그렇고, 흥미를 느끼신다면 스마트 컨트랙트 취약점에 대한 시리즈를 만들었습니다( )

하지만 함수 호출자가 컨트랙트인지 일반 지갑 주소인지 알 수 있는 방법이 있다면 어떨까요?
그런 다음 외부 계약이 계약과 상호 작용하는 것을 중지하여 계약이 해킹되는 것을 방지할 수 있습니다.

이것이 어떻게 달성될 수 있는지 봅시다:
  • 재진입에 취약한 계약 고려(내 블로그 확인)
  • 이 경우 해커는 상태 매핑에서 늦은 잔액 업데이트를 이용하고 모든 자금이 고갈될 때까지 공격자의 계약을 사용하여 계약을 계속 다시 입력합니다.
  • 하지만 MyContract 함수를 호출하기 위해 외부 계약을 중지하는 경우에는 그렇지 않습니다. 😎

  • // SPDX-License-Identifier: GPL-3.0
    pragma solidity 0.8.1;
    
    contract MyContract { // this contract is vulnerable to re-entracy attack
    
        mapping (address => uint) balances;
    
        modifier noContract { // this won't allow external contracts to interact with this contract
            require(tx.origin == msg.sender, "No contracts allowed");
            _;
        }
    
        function deposit() external payable noContract { // using noContract 
            balances[msg.sender] += msg.value;
        }
    
        function withdraw() external payable noContract { // using noContract 
            uint amount = balances[msg.sender];
            require(amount > 0, "Nothing to withdraw");
    
            (bool sent, ) = msg.sender.call{value: amount}("");
            require(sent, "Send operation failed");
    
            balances[msg.sender] = 0;
        }
    
        function getBalance() external view returns(uint balance) {
            balance = address(this).balance;
        }
    }
    
    noContract 수정자를 사용하여 외부 스마트 계약을 중지하고 있습니다. 함수 호출자( msg.sender )가 트랜잭션 개시자( tx.origin )와 동일한지 확인합니다.tx.origin에 대해 더 알고 싶습니까? 방문

    이제 일부 공격자 계약이 MyContract에서 자금을 훔치려고 시도하면 거래가 실패합니다.
    공격자 계약:

    // SPDX-License-Identifier: GPL-3.0
    pragma solidity 0.8.1;
    
    interface IMyContract{
        function deposit() external payable;
        function withdraw() external payable;
    }
    
    contract Attacker {
        IMyContract myContract;
    
        constructor(address _myContract) payable {
            myContract = IMyContract(_myContract);
        }
    
        fallback() external payable {
            if (address(myContract).balance > 0) {
                myContract.withdraw();
            }
        }
    
        function attack() external payable {
            myContract.deposit{value: 1 ether}();
            myContract.withdraw();
        }
    
        function getBalance() external view returns(uint balance) {
            balance = address(this).balance;
        }
    }
    

    좋은 웹페이지 즐겨찾기