블로그 1뉴스 개발자 엔터프라이즈 블록 체인 설명 이벤트 및 컨퍼런스 보도 자료뉴스 레터

뉴스 레터 구독.

이메일 주소

우리는 귀하의 개인 정보를 존중합니다

홈 블로그 블록 체인 개발

이더 리움 스마트 계약 보안 권장 사항

약정 계획에 대한 외부 호출을 처리하는 방법부터 Ethereum을 구축 할 때 따라야 할 10 개 이상의 스마트 계약 보안 패턴이 있습니다 .by ConsenSys 2020 년 7 월 10 일 Posted on July 10, 2020

이더 리움 스마트 계약 보안 권장 사항

스마트 계약 보안 사고 방식에서 다루었 듯이 경계하는 이더 리움 개발자는 항상 다음 5 가지 원칙을 최우선으로 생각합니다.

  • 실패에 대비
  • 신중하게 출시
  • 계약을 단순하게 유지
  • 최신 상태 유지
  • EVM의 특이성에주의

이 게시물에서는 EVM의 특이성에 대해 자세히 알아보고 Ethereum에서 스마트 계약 시스템을 개발할 때 따라야하는 패턴 목록을 살펴 보겠습니다. 이 부분은 주로 중급 이더 리움 개발자를위한 것입니다. 아직 탐색 초기 단계에 있다면 ConsenSys Academy의 주문형 블록 체인 개발자 프로그램을 확인하세요.. 

좋아요, 뛰어 들자.

외부 전화

외부 전화를 걸 때주의하세요.

신뢰할 수없는 스마트 계약에 대한 호출은 몇 가지 예기치 않은 위험 또는 오류를 유발할 수 있습니다. 외부 호출은 해당 계약 또는 종속 된 다른 계약에서 악성 코드를 실행할 수 있습니다. 따라서 모든 외부 호출을 잠재적 인 보안 위험으로 취급하십시오. 외부 전화를 제거 할 수 없거나 바람직하지 않은 경우이 섹션의 나머지 부분에있는 권장 사항을 사용하여 위험을 최소화하십시오..

신뢰할 수없는 계약 표시

외부 계약과 상호 작용할 때 변수, 메서드 및 계약 인터페이스의 이름을 지정하여 상호 작용이 잠재적으로 안전하지 않다는 것을 명확히합니다. 이것은 외부 계약을 호출하는 자체 함수에 적용됩니다..

// 불량 Bank.withdraw (100); // 신뢰할 수있는 것인지 신뢰할 수없는 것인지 불분명 함 function makeWithdrawal (uint amount) {//이 함수가 잠재적으로 안전하지 않은지 명확하지 않음 Bank.withdraw (amount); } // 좋은 UntrustedBank.withdraw (100); // 신뢰할 수없는 외부 호출 TrustedBank.withdraw (100); // XYZ Corp에서 유지하는 신뢰할 수있는 외부 은행 계약 function makeUntrustedWithdrawal (uint amount) {UntrustedBank.withdraw (amount); } 코드 언어 : PHP (php)

외부 호출 후 상태 변경 방지

원시 호출 (someAddress.call () 형식)을 사용하든 계약 호출 (ExternalContract.someMethod () 형식)을 사용하든 악성 코드가 실행될 수 있다고 가정합니다. ExternalContract가 악성이 아니더라도 호출하는 모든 계약에 의해 악성 코드가 실행될 수 있습니다..

한 가지 특별한 위험은 악성 코드가 제어 흐름을 가로 채 재진입으로 인한 취약성을 유발할 수 있다는 것입니다. (보다 재진입 이 문제에 대한 자세한 논의를 위해).

신뢰할 수없는 외부 계약을 호출하는 경우 호출 후 상태 변경을 피하십시오. 이 패턴은 때때로 검사 효과 상호 작용 패턴.

보다 SWC-107

transfer () 또는 send ()를 사용하지 마십시오..

.transfer () and.send () 정확히 2,300 가스를 수신자에게 전달합니다. 이 하드 코딩 된 가스 봉급의 목표는 재진입 취약성, 그러나 이것은 가스 비용이 일정하다는 가정 하에서 만 의미가 있습니다.. EIP 1884, 이스탄불 하드 포크의 일부인 SLOAD 작업의 가스 비용이 증가했습니다. 이로 인해 계약의 폴백 기능에 2300 개 이상의 가스 비용이 들었습니다. .transfer () 및 .send () 사용을 중지하고 대신 use.call ()을 사용하는 것이 좋습니다..

// 잘못된 계약 Vulnerable {function withdraw (uint256 amount) external {// 이것은 2300 가스를 전달합니다. // 수신자가 계약이고 가스 비용이 변경되면 충분하지 않을 수 있습니다. msg.sender.transfer (amount); }} // 좋은 계약 Fixed {function withdraw (uint256 amount) external {// 사용 가능한 모든 가스를 전달합니다. 반환 값을 확인하십시오! (bool 성공,) = msg.sender.call.value (amount) (""); 필요 (성공, "전송 실패."); }} 코드 언어 : JavaScript (자바 스크립트)

.call ()은 재진입 공격을 완화하기 위해 아무것도하지 않으므로 다른 예방 조치를 취해야합니다. 재진입 공격을 방지하려면 검사 효과 상호 작용 패턴.

외부 호출의 오류 처리

Solidity는 원시 주소에서 작동하는 저수준 호출 메서드를 제공합니다 : address.call (), address.callcode (), address.delegatecall () 및 address.send (). 이러한 저수준 메서드는 예외를 throw하지 않지만 호출에서 예외가 발생하면 false를 반환합니다. 반면에 계약 호출 (예 : ExternalContract.doSomething ())은 자동으로 throw를 전파합니다 (예를 들어, ExternalContract.doSomething ()도 doSomething ()이 throw되면 throw됩니다)..

하위 수준 호출 방법을 사용하기로 선택한 경우 반환 값을 확인하여 호출이 실패 할 가능성을 처리해야합니다..

// 잘못된 someAddress.send (55); someAddress.call.value (55) (""); // 남아있는 모든 가스를 전달하고 결과를 확인하지 않으므로 두 배로 위험합니다. someAddress.call.value (100) (bytes4 (sha3 ("예금()"))); // deposit에서 예외가 발생하면 raw call ()은 false 만 반환하고 트랜잭션은 되 돌리지 않습니다. // good (bool success,) = someAddress.call.value (55) (""); if (! success) {// 실패 코드 처리} ExternalContract (someAddress) .deposit.value (100) (); 코드 언어 : JavaScript (javascript)

보다 SWC-104

외부 통화에 대한 풀오버 푸시 선호

외부 호출은 실수로 또는 고의로 실패 할 수 있습니다. 이러한 실패로 인한 손상을 최소화하려면 각 외부 호출을 호출 수신자가 시작할 수있는 자체 트랜잭션으로 분리하는 것이 좋습니다. 이는 특히 사용자가 자금을 자동으로 자금을 인출하는 것보다 인출 할 수있는 지불과 관련이 있습니다. (이것은 또한 가스 한도 문제.) 단일 트랜잭션에서 여러 이더 전송을 결합하지 마십시오..

// 잘못된 계약 경매 {address higherBidder; uint highBid; function bid () payable {require (msg.value >= 최고 입찰가); if (highestBidder! = address (0)) {(bool success,) = higherBidder.call.value (highestBid) (""); 필요 (성공); //이 호출이 계속 실패하면 다른 누구도 입찰 할 수 없습니다.} higherBidder = msg.sender; 최고 입찰 = msg.value; }} // 좋은 계약 경매 {address higherBidder; uint highBid; 매핑 (주소 => uint) 환불; function bid () payable external {require (msg.value >= 최고 입찰가); if (highestBidder! = 주소 (0)) {환불 [highestBidder] + = 최고 입찰가; //이 사용자가 청구 할 수있는 환불을 기록합니다.} higherBidder = msg.sender; 최고 입찰 = msg.value; } function withdrawRefund () 외부 {단위 환불 = 환불 [msg.sender]; 환불 [msg.sender] = 0; (bool success,) = msg.sender.call.value (refund) (""); 필요 (성공); }} 코드 언어 : JavaScript (자바 스크립트)

보다 SWC-128

신뢰할 수없는 코드에 호출을 위임하지 마십시오.

delegatecall 함수는 호출자 계약에 속하는 것처럼 다른 계약의 함수를 호출합니다. 따라서 수신자는 발신 주소의 상태를 변경할 수 있습니다. 이것은 안전하지 않을 수 있습니다. 아래 예는 delegatecall을 사용하여 계약이 파괴되고 잔액이 손실되는 방식을 보여줍니다..

계약 소멸자 {function doWork () external {selfdestruct (0); }} 계약 작업자 {function doWork (address _internalWorker) public {// 안전하지 않은 _internalWorker.delegatecall (bytes4 (keccak256 ("일해()"))); }} 코드 언어 : JavaScript (자바 스크립트)

배포 된 Destructor 계약의 주소를 인수로 사용하여 Worker.doWork ()를 호출하면 Worker 계약이 자체 소멸됩니다. 신뢰할 수있는 계약에만 실행 위임 사용자가 제공 한 주소가 아닙니다..

경고

균형이없는 계약이 만들어 졌다고 가정하지 마십시오. 공격자는 계약이 생성되기 전에 이더를 계약 주소로 보낼 수 있습니다. 계약은 초기 상태에 잔액이 0이라고 가정해서는 안됩니다. 보다 61 호 상세 사항은.

보다 SWC-112

이더는 계정에 강제로 전송 될 수 있습니다.

계약의 균형을 엄격하게 확인하는 불변의 코딩에주의하십시오..

공격자는 강제로 모든 계정에 이더를 보낼 수 있습니다. 이것은 막을 수 없습니다 (revert ()를 수행하는 폴백 함수로도).

공격자는 계약을 만들고 1wei로 자금을 조달하고 selfdestruct (victimAddress)를 호출하여이를 수행 할 수 있습니다. 희생자 주소에는 코드가 호출되지 않으므로 방지 할 수 없습니다. 이는 임의의 주소가 될 수있는 채굴 자의 주소로 전송되는 블록 보상에도 해당됩니다..

또한 계약 주소를 미리 계산할 수 있으므로 계약이 배포되기 전에 이더를 주소로 보낼 수 있습니다..

보다 SWC-132

온 체인 데이터는 공개된다는 것을 기억하십시오.

많은 응용 프로그램이 작동하려면 제출 된 데이터가 특정 시점까지 비공개로 유지되어야합니다. 게임 (예 : 온 체인 가위 바위 보) 및 경매 메커니즘 (예 : 봉인 된 입찰 비 크리 경매)는 두 가지 주요 범주의 예입니다. 개인 정보 보호가 문제가되는 애플리케이션을 구축하는 경우 사용자가 정보를 너무 일찍 게시하도록 요구하지 않도록하십시오. 가장 좋은 전략은 약속 계획 별도의 단계 : 먼저 값의 해시를 사용하여 커밋하고 이후 단계에서 값을 표시합니다..

예 :

  • 가위 바위 보에서는 두 플레이어 모두 의도 한 동작의 해시를 먼저 제출 한 다음 두 플레이어 모두 자신의 동작을 제출하도록 요구합니다. 제출 된 이동이 해시와 일치하지 않으면 버리십시오..
  • 경매에서 플레이어는 초기 단계에서 입찰 값의 해시를 제출하고 (입찰 값보다 큰 입금과 함께) 두 번째 단계에서 경매 입찰 값을 제출해야합니다..
  • 난수 생성기에 의존하는 응용 프로그램을 개발할 때 순서는 항상 (1) 플레이어가 동작을 제출하고, (2) 난수를 생성하고, (3) 플레이어가 지불해야합니다. 많은 사람들이 난수 생성기를 적극적으로 연구하고 있습니다. 현재 동급 최고의 솔루션에는 비트 코인 블록 헤더 ( http://btcrelay.org), hash-commit-reveal 체계 (즉, 한 당사자가 숫자를 생성하고 값에 “커밋”하기 위해 해시를 게시 한 다음 나중에 값을 표시 함) 및 RANDAO. Ethereum은 결정 론적 프로토콜이므로 프로토콜 내에서 예측할 수없는 난수로 변수를 사용할 수 없습니다. 또한 채굴자가 어느 정도 block.blockhash () 값을 제어하고 있음을 유의하십시오.*.

일부 참가자가 “오프라인으로 전환”되어 돌아 오지 않을 가능성에주의하십시오.

자금을 인출하는 다른 방법없이 특정 작업을 수행하는 특정 당사자에 따라 환불 또는 청구 프로세스를 수행하지 마십시오. 예를 들어 가위 바위 보 게임에서 한 가지 일반적인 실수는 두 플레이어가 동작을 제출할 때까지 지불금을 내지 않는 것입니다. 그러나 악의적 인 플레이어는 단순히 자신의 동작을 제출하지 않음으로써 상대방을 “슬픔”할 수 있습니다. 실제로 플레이어가 다른 플레이어의 공개 된 동작을보고 패배했다고 판단하면 자신의 동작을 제출할 이유가 전혀 없습니다. 이 문제는 주 채널 정산의 맥락에서도 발생할 수 있습니다. 이러한 상황이 문제가되는 경우 (1) 시간 제한을 통해 비 참여 참가자를 피할 수있는 방법을 제공하고 (2) 참가자가 모든 상황에서 정보를 제출하도록 경제적 인센티브를 추가하는 것을 고려하십시오. 그렇게해야한다.

가장 음의 부호가있는 정수의 부정에주의

Solidity는 부호있는 정수로 작업 할 수있는 여러 유형을 제공합니다. 대부분의 프로그래밍 언어에서와 같이 Solidity에서 N 비트의 부호있는 정수는 -2 ^ (N-1)에서 2 ^ (N-1) -1까지의 값을 나타낼 수 있습니다. 이것은 MIN_INT에 대해 동등한 양의 값이 없음을 의미합니다. 부정은 숫자의 2의 보수를 찾는 것으로 구현되므로 가장 많은 음수의 부정은 같은 숫자가됩니다.. Solidity의 모든 부호있는 정수 유형 (int8, int16,…, int256)에 해당됩니다..

계약 부정 {function negate8 (int8 _i) public pure returns (int8) {return -_i; } function negate16 (int16 _i) public pure returns (int16) {return -_i; } int8 public a = negate8 (-128); // -128 int16 public b = negate16 (-128); // 128 int16 public c = negate16 (-32768); // -32768} 코드 언어 : PHP (php)

이를 처리하는 한 가지 방법은 부정하기 전에 변수 값을 확인하고 MIN_INT와 같으면 던지는 것입니다. 또 다른 옵션은 용량이 더 큰 유형 (예 : int16 대신 int32)을 사용하여 가장 많은 음수를 얻지 못하도록하는 것입니다..

MIN_INT를 -1로 곱하거나 나눌 때 int 유형과 유사한 문제가 발생합니다..

블록 체인 코드가 안전합니까?? 

이러한 권장 사항이 도움이 되었기를 바랍니다. 귀하와 귀하의 팀이 출시를 준비 중이거나 개발 라이프 사이클의 시작 단계에 있고 스마트 계약의 온 전성 검사가 필요한 경우 ConsenSys Diligence의 보안 엔지니어 팀에 언제든지 문의하십시오. 100 % 확신을 가지고 이더 리움 애플리케이션을 시작하고 유지하도록 도와 드리겠습니다.. 

보안 지점 수표 예약

블록 체인 보안 전문가 팀과 함께 1 일 리뷰를 예약하세요. 지금 예약하세요 보안 스마트 계약 뉴스 레터 최신 이더 리움 뉴스, 엔터프라이즈 솔루션, 개발자 리소스 등에 대한 뉴스 레터를 구독하십시오.성공적인 블록 체인 제품을 구축하는 방법웨비나

성공적인 블록 체인 제품을 구축하는 방법

이더 리움 노드를 설정하고 실행하는 방법웨비나

이더 리움 노드를 설정하고 실행하는 방법

나만의 Ethereum API를 구축하는 방법웨비나

나만의 Ethereum API를 구축하는 방법

소셜 토큰을 만드는 방법웨비나

소셜 토큰을 만드는 방법

스마트 계약 개발에서 보안 도구 사용웨비나

스마트 계약 개발에서 보안 도구 사용

금융 디지털 자산 및 DeFi의 미래웨비나

금융의 미래 : 디지털 자산 및 DeFi

Mike Owergreen Administrator
Sorry! The Author has not filled his profile.
follow me