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)
- 외부 호출 사용에 있어서는, 외부 호출이 실패할 것을 대비하고, 시간이 지나면 자동적으로 다음 상태로 진행되도록 하라.
@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.