[WEB3] Accessing Private Data


1. Concept

솔리디티에서는 변수나 함수를 다음과 같이 네가지로 정의할 수 있다.

privatecontract 내부에서만 접근 가능. 또한 이름을 명명할때 _를 많이 붙인다.
public모든 방법으로 접근 가능. 외부 contract에서도 접근 가능.
internalcontract 내부와 상속된 contract에서 접근이 가능. 외부에서는 접근할 수 없기 때문에 this 로 접근도 불가능. 이름은 private와 동일한 느낌으로 _를 붙인다.
external다른 contract와 transaction으로만 호출 가능. 내부호출은 불가능.

이 중에서 이번에 알아볼 것은 private이다. private은 내부 컨트랙트에서만 접근이 가능하고, 외부 컨트랙트에서는 접근이 불가능하다. 그렇다면 private으로 password 같은 것을 저장해도 괜찮을까?

그건 아니다. 왜냐하면 ‘접근’이 불가능 한 것이지 ‘읽기’가 불가능 한 것은 아니기 때문이다. 기본적인 블록체인의 속성이 모든 정보를 투명하게 공개하는 것이므로 private이라고 해도 내용을 숨길 수는 없다.

 

본격적으로 코드를 알아보기 전에 한 가지 알아둘 것이 있다.

다음 그림은 EVM에서 데이터를 저장하는 형식이다.

EVM은 총 2^256개의 slot을 가지고 있으며, slot 하나의 크기는 32byte이다. 위처럼 선언된 순서대로 저장되는 것은 이해하기 쉬운데, 마지막에 boo를 보면 address가 20byte이기에 자리가 남아서 addr의 오른쪽에 저장된 것이 보인다.

그런데 mapping과 구조체는 위 그림처럼 순서대로 저장되지 않는다. 자세한 건 Code를 보면서 설명하겠다.


2. Code

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.18;

contract Vault {
    //slot 0
    uint public count = 123;

    //slot 1
    address public owner = msg.sender; // 20 bytes
    bool public isTrue = true; // 1 byte
    uint16 public u16 = 31; // 2 bytes

    //slot 2
    bytes32 private password;

    //constants do not use storage
    uint public constant someConst = 123;

    //slot 3, 4, 5 (ont for each array element)
    bytes32[3] public data;

    struct User {
        uint id;
        bytes32 password;
    }

    //slot 6 - length of array
    //starting from slot keccak256(6) - array elements
    //slot where array element is stored = keccak256(slot) + (index * elementSize)
    //where slot = 6 and elementSize = 2 
    User[] private users;

    //slot 7 - empty
    //entries are stored at keccak256(key, slot)
    //where slot = 7, key = map key
    mapping (uint => User)  private idToUser;
}

 

변수만 선언한 간단한 컨트랙트이다. slot 1을 보면 address가 20byte만 차지하여 bool type(1 byte)인 isTrue와 uint16 type(2 byte)인 u16이 추가로 slot 1에 저장되는 것을 확인할 수 있다.

 

상수(constant)는 EVM의 slot에 저장되지 않고 컨트랙트 자체에 hard-coding된다.

 

data의 경우 순서대로 배열을 저장하고 있다. 그런데 users는 모습이 조금 다르다. users는 User 구조체 배열이므로 slot 6에는 배열의 길이만 저장하고, 실제 구조체 배열은 keccak256(6)번째 slot에 저장한다.

 

mapping의 경우도 위와 비슷하게 keccak(key, slot)번째 slot에 저장한다.

 

위 그림은 truffle을 이용해서 ropsten 네트워크에 배포된 컨트랙트의 2번째 slot을 확인하는 것이다. slot 2에는 password가 저장되는데, private 변수임에도 쉽게 읽을 수 있음을 알 수 있다.

 

위 그림은 User 구조체 배열의 값을 확인하는 과정이다. 먼저 keccak(6) 값을 구해주고, 해당 부분을 확인하면 users의 첫번째 user의 id가 나온다. 그 다음 슬롯(hash 값 + 1)에서는 user의 password를 확인할 수 있었다. 이처럼 구조체 역시 private으로 선언되더라도 쉽게 읽을 수 있다.

 


3. Prevention

해결방법은 별 다른 게 없다. 그냥 민감한 정보는 위 코드처럼 블록체인 상에 저장하지 않는 것이 바람직하다!

 


4. Reference

 

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤