상세 컨텐츠

본문 제목

솔리디티 깨부수기 - Security 1-3강 재진입 공격(re-entrancy attack) 해결법 1

솔리디티 깨부수기 - Security

by D_One 2022. 8. 5. 23:01

본문

안녕하세요. 

지난시간에 재진입 공격(re-entrancy attack) 을 구현 해보았으니, 

오늘은 재진입 공격(re-entrancy attack) 을 어떻게 방지하는 지 알아보도록 하겠습니다. 

 

TLDR ; 글 보다는 유튜브에서 편하게 확인하세요 :))

https://youtu.be/AIoCWtjjvCI

간단하게 Bank 스마트 컨트랙트의 witdhraw 함수를 변경해주면 됩니다. 

 

기존의 witdhraw 함수는 아래와 같습니다. 

 

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

contract Bank {
    
	...

    function withdraw() external {
        uint currentBalance = balances[msg.sender];
        (bool result,) = msg.sender.call{value:currentBalance}("");
        require(result, "ERROR");
         balances[msg.sender] = 0;
    }
    
	...
}

 

재진입 공격이 시작되는 코드는   "(bool result,) = msg.sender.call{value:currentBalance}("");" bank가 attacker에게 예치된금액을 주는 순간이라 생각할 수 있습니다. 

 

그렇다면, attacker에게 예치된 금액을 보내기전에, 보낼 금액을 차감하고 나서 보낸다면 재진입 공격에서 벗어 날 수 있을 것입니다.

 

다음과 같은 코드가 될 수 있겠네요. 

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

contract Bank {
    
	...

    function withdraw() external {
        uint currentBalance = balances[msg.sender];
        balances[msg.sender] = 0;
        (bool result,) = msg.sender.call{value:currentBalance}("");
        require(result, "ERROR");
         
    }
    
	...
}

 

위와 같이 balances[msg.sender] = 0; 을 먼저 만들어주고나서, 예치된 금액을 보냈으므로, 다시 attacker가 재진입 한다해도, attacker의 예치된 금액은 0이기에 줄수가 없겠죠.

 

 

추가적으로 transfer,send를 쓰면 재진입공격을 막을 수 있으나, 이스탄불 하드포크이후 call을 쓰는것을 권장하고 있습니다. 그러므로 재진입공격을 잘 막아주는게 좋겠죠.

더 자세한 내용 유튜브를 통해서 확인 부탁드립니다. 

 

관련글 더보기