[마스터링 이더리움] 스마트 컨트랙트 보안 - 패턴11 DoS

in #busy5 years ago

DoS 서비스 거부 (Denial of Service)

  • Dos는 주로 사용자가 일정 시간 동안 서비스를 이용할 수 없는 것을 말한다.
  • 이것은 이더를 영원히 묶어 둘 수 있다.

취약점

  • 여러 가지 DoS 공격이 있지만 일부만 소개
  • 외부에서 조작된 mappings이나 arrays를 통한 루핑
  • DistributeTokens 컨트랙트
1 contract DistributeTokens {
2   address public owner; // gets set somewhere
3   address[] investors; // array of investors
4   uint[] investorTokens; // the amount of tokens each investor gets
5
6   // ... extra functionality, including transfertoken()
7
8   function invest() public payable {
9     investors.push(msg.sender);
10    investorTokens.push(msg.value * 5); // 5 times the wei sent
11  }
12
13  function distribute() public {
14    require(msg.sender == owner); // only owner
15    for(uint i = 0; i < investors.length; i++) {
16      // here transferToken(to,amount) transfers "amount" of
17      // tokens to the address "to"
18      transferToken(investors[i],investorTokens[i]);
19    }
20  }
21 }
  • 위 코드는 단순히 해커가 투자자(계정)를 많이 만들어서 15행의 for문을 무수히 많이 돌게 할 수 있다.
  • 그 결과 컨트랙트 코드를 실행하기 위한 gas량을 증가시켜 block gas limit을 넘기게 할 수 있다.
  • 따라서 distribute함수는 실행되지 못한다.

권한 관리

  • 많은 컨트랙트에서 소유자가 특정 권한을 가지고 있고, 소유자가 액션을 취해야만 진행되는 경우가 많다.
1 bool public isFinalized = false;
2 address public owner; // gets set somewhere
3
4 function finalize() public {
5   require(msg.sender == owner);
6   isFinalized == true;
7 }
8
9 // ... extra ICO functionality
10
11 // overloaded transfer function
12 function transfer(address _to, uint _value) returns (bool) {
13  require(isFinalized);
14  super.transfer(_to,_value)
15 }
16
17 ...
  • 위 코드에서 owner가 finalize 함수를 실행하여, 코인이 투자자에게 분배된다.
  • 그런데 권한을 가지고 있는 owner가 개인키를 잃어버리거나 사용할 수 없게 되면, 전체 컨트랙트는 동작하지 않게 된다.
  • 토큰은 영원히 이동할 수 없게 된다.
  • 전체 컨트랙트 기능들이 하나의 주소에 의해서 좌우되는 것은 좋지 않다.

외부 호출을 기반으로 한 진행 상태

  • 새로운 상태로 진행되기 위해서 어떤 주소로 이더를 보내거나 외부 소스의 입력을 기다려야 하도록 컨트랙트가 코딩 될 때가 있다.
  • 이 경우, 외부 호출이 실패하거나 외부적 원인으로 막히면 DoS 공격으로 이어질 수 있다.
  • 예를 들어, 새로운 상태로 진행되기 위해 이더가 인출되어야 하는 경우, 이더를 수신하지 못하는 사용자 계정으로 이더를 보내면 컨트랙트는 다음 상태로 진행될 수 없다.

예방기법

  • 외부 사용자가 조작할 수 있는 데이터 구조에 대해 루프 돌리지 마라!
  • withdrawal 패턴이 추천된다. 각각의 투자자가 withdraw 함수를 호출하도록 한다.
  • multisig 다중서명 컨트랙트로 만들어라.
  • 또는 time-lock을 이용하라. 위 코드 5행에서 owner만 체크하지 말고, or 로 일정 시간이 지나면 다음 상태로 진행하게 하라.그래서 누구든 finalize를 할 수 있게 하라.
    require(msg.sender == owner || now > unlockTime)
  • 외부 호출 사용에 있어서는, 외부 호출이 실패할 것을 대비하고, 시간이 지나면 자동적으로 다음 상태로 진행되도록 하라.
Sort:  

@etainclub You have received a 100% upvote from @steemguardian because this post did not use any bidbots and you have not used bidbots in the last 30 days!

Upvoting this comment will help keep this service running.

Coin Marketplace

STEEM 0.19
TRX 0.15
JST 0.029
BTC 63237.60
ETH 2647.23
USDT 1.00
SBD 2.81