마스터링 이더리움(Mastering Ethereum) 9장 - 스마트 컨트랙트 보안(1)

JinJinJJara·2021년 1월 27일
0

Mastering_Ethereum

목록 보기
5/11

스크립토 6기 하진원입니다.
스크립토 방학 스터디로 마스터링 이더리움 공부하고 있습니다.

스마트 컨트랙트 보안

프로그래밍시 준수해야 할 점(방어적 프로그래밍)

단순성

단순성은 버그와 의도치 못한 결과와 반비례한다. 따라서 버그를 줄이기 위해 최대한 코드의 줄 수를 줄이는 노력을 해야 한다.

코드 재사용

만들어져있는 라이브러리와 스마트 컨트랙트를 재사용하는 것이 좋다. 많이 사용되고 검증된 코드는 새로 작성한 코드보다 안전하기 때문에 새로 작성할 필요가 없다.

코드 품질

스마트 컨트랙트에서 버그는 금전적 손실을 발생시키기 때문에 실수에 대한 비용이 크게 발생된다. 따라서 코드가 배포되기 전에 문제가 없다는 것을 확실시 해야 한다.

가독성 / 감사 용이성

코드는 가독성이 뛰어나야 한다. 가독성이 뛰어나다면 다른 사람이 검증해주기도 쉬우며 감사받기도 편하고 협업을 하는데도 좋다.

테스트 범위

할 수 있는 모든 경우를 테스트하여 버그를 방지하는 것이 필요하다.
예를 들면 함수에서 입력 인수에 대한 테스트

보안 위험 패턴 및 해결 방법

재진입성

컨트랙트는 외부 코드를 호출하여 활용하거나 외부 사용자 주소로 이더를 전송하는 경우가 잦다. 이런 작업들을 위해 컨트랙트는 외부 호출을 요청하는데 공격자가 이를 콜백함수를 사용해 악용한 것이 재진입성 공격이다. 재진입이라는 용어는 외부의 해커가 호출하여 해킹이 발생되는 것이 아닌

취약성

컨트랙트가 알 수 없는 주소로 이더를 전송하는 경우 공격자는 폴백함수에 악성코드를 가지고 있는 컨트랙트를 외부 주소에 만들어 해 주소에 이더가 보내지면 악의적인 코드가 호출되게 할 수 있다.

예방기법

  • 이더를 외부의 컨트랙트에 보낼 때 transfer 함수 사용하기.
    transfer 함수는 외부 호출에 가스를 2300으로 제한하여 목적지 주소/컨트랙트가 다른 컨트랙트를 호출하는 것을 막는다.

  • 이더를 전송하기 전에 상태 변수를 변경하는 로직이 발생하게 하는 것. 즉, 외부 호출을 수행하는 코드를 가장 마지막에 두는것

  • 뮤텍스(mutex) 도입하기. 코드 실행 중에 컨트랙트를 잠그는 상태 변수를 추가하여 재진입을 방지하는 것. 뮤텍스 변수가 잠겨있으면 컨트랙트가 실행되지 않게 하는 방법이다.

산술 오버플로/언더플로

데이터 타입을 벗어나는 숫자를 고정 크기 변수에 저장해야 하는 연산이 수행되면 발생한다.

취약점

  • 언더플로 : 정의된 범위 아래의 숫자를 할당한 경우 결과가 순환하는 경우.
  • 오버플로 : 정의된 범위 이상의 숫자를 할당하는 경우 결과가 순환하는 경우.
  • 예시 : uint8에서 0+257을 하면 1(오버플로), 0에서 1을 빼면 255(언더플로)

예방기법

  • 수학 라이브러리 사용하기. 덧셈, 뺄셈과 같은 표준 수학 연산자 대신 수학 라이브러리, 특히 SafeMath 라이브러리는 해당 문제를 방지하는데 도움을 준다.

예기치 않은 이더

이더가 컨트랙트에 전달될 때는 폴백 함수나 컨트랙트에 정의된 함수를 실행해야 한다.
이에 대한 예외는 어떤코드를 샐행하지 않고 컨트랙트 내에 이더가 존재할 수 있는 경우이다.

취약점

일반적으로 payable을 통해서만 이더 교환이 가능하다고 생각을 한다. 하지만 payable 함수와 컨트랙트에서 코드를 실행하지 않고 컨트랙트에 이더를 보내는 방법이 두가지 있고 그것이 자기파괴(selfdestruct)미리 보내진 이더(pre-sent ether)이다.

  • 자기파괴(selfdestruct)
    모든 컨트랙트는 컨트랙트 삭제함수인 self-destruct 함수를 구현할 수 있다.
    자기파괴 함수가 실행될 때 컨트랙트에 저장된 모든 이더를 입력값으로 받아 지정된 주소로 보내는데 지정된 주소가 컨트랙트인 경우 폴백함수를 포함한 어떤 함수도 호출되지 않는다.
    따라서 selfdestruct 함수는 컨트랙트의 코드와 관계없이 이더를 강제로 어떠한 주소에도 보낼 수 있다.
  • 미리 보내진 이더(pre-sent ether)
    컨트랙트 주소는 무작위로 정해지는 것이 아닌 컨트랙트를 생성하는 생성자의 주소와 트랜잭션 논스의 해시값으로 계산한다.
    따라서 컨트랙트 주소를 미리 알 수 있기 때문에 미리 계산된 주소로 이더를 보낼 수 있다.

예방 기법

this.balance에 근거하지 않은, 별도의 상태 변수를 만들어 정확한 입금 이더를 추적해야 한다.

DELEGATECALL

CALL과 DELEGATECALL은 개발자가 코드를 모듈화하는데 유용하다.
컨트랙트에 대한 외부 메시지 호출은 CALL에 의해 처리되고 코드가 외부 컨트랙트/함수의 컨텍스트에서 실행된다.
DELEGATECALL은 CALL과 유사하고 코드가 호출한 컨트랙트에서 실행된다.
또, msg.sender와 msg.value는 변하지 않고 이를 통해 라이브러리를 구현할 수 있다.
다만, DELEGATECALL은 예기치 않은 코드를 실행할 위험이 있다.

취약점

DELEGATECALL는 컨텍스트를 보존하기 때문에 안전한 사용자 지정 라이브러리를 구축하는 것은 쉽지 않다.
라이브러리에 문제가 없더라도 특정한 컨텍스트에서 취약점이 발생할 수 있다.

디폴트 가시성

솔리디티는 가시성 지정자가 있는데 이는 함수의 호출 방법을 지정할 수 있다.
가시성은 사용자가 함수를 외부에서 호출할 수 있는지 여부와 다른 컨트랙트가 함수를 내부에서, 외부에서 호출할 수 있는지 여부를 결정한다.
기본 가시성은 public으로 사용자가 외부에서 호출할 수 잇다.

취약성

기본 가시성이 public인데 개발자가 private으로 함수의 가시성을 지정하지 않아 생기는 문제이다.

예방 기법

가시성을 의도적으로 항상 지정하는 것이 좋다.

엔트로피 환상

이더리움 블록체인의 트랜잭션은 결정론적인 연산이기 때문에 엔트로피, 즉 무작위성이 없다.

취약성

이더리움 블록체인 플랫폼을 기반으로 만든 컨트랙트 중 일부분은 도박을 구현하려 하였다.
여기서 일반적으로 무작위 값을 구현하기 위해 값이 알려지지 않은 트랜잭션에 관련된 변수를 사용하는 방법을 사용하였다. 그렇지만 이는 채굴자가 통제가능하기 때문에 무작위한 방법이 아니다.

예방 기법

엔트로피의 원천은 블록체인 외부에 있어야 한다.

외부 컨트랙트 참고

이더리움은 코드를 재사용하고 네트워크에 배포된 컨트랙트를 참고할 수 있는 장점이 있어 외부 메시지 호출을 통해 참고한다.

취약성

참고(캐스팅) 할 때 주소의 코드의 진위 여부에 상관없이 가져오기 때문에 악의적 공격자가 주소에 악의적인 코드를 삽입한다면 문제가 생긴다.
권한 있는 사용자가 컨트랙트 라이브러리를 변경할 수 있으면 다른 사용자가 모르는 사이 임의의 코드를 실행할 수 있다, 즉 악의적 의도를 가진 코드를 실행할 수 있다.

예방 기법

  • new 키워드를 사용하여 컨트랙트 작성. 이 경우 참고된 컨트랙트의 인스턴스가 배포 시 생성되고 배포자는 컨트랙트의 주소를 바꿀 수 없다.
  • 외부 컨트랙트 주소를 하드코딩하는 방법.
  • 이를 예방하기 위해 컨트랙트 주소가 public이어서 감사가 가능하게 되어있는지 확인하는 것이 중요하다. private로 되어 있는 경우 악의적으로 행동한다고 생각할 수 있다.
profile
갈팡질팡 공부하는 중입니다

0개의 댓글