Back to Blog

Solana 생태계 보안 강화 (4) — 계정 유효성 검사

2022년 4월 1일
5 min read

0. 복습

1. 개요

이전 블로그에서는 프로그램을 업그레이드하는 방법에 대해 논의했습니다. 이번 포스트에서는 DeFi 분야에서 가장 일반적이고 기본적인 보안 주제 중 하나인 접근 제어 관련 문제를 소개합니다.

2. 명령어(Instructions)

Solana에서 각 프로그램은 entrypoint!로 정의된 단일 entrypoint를 내보냅니다. Ethereum과 달리, 클라이언트는 일반적으로 process_instruction이라고 불리는 entrypoint로 정의된 단일 함수만 호출할 수 있습니다. entrypoint 함수는 세 가지 매개변수를 받습니다. 스마트 컨트랙트의 프로그램 ID, 프로그램이 작동할 계정, 그리고 명령어 데이터입니다. 명령어 데이터는 어떤 명령어가 호출될지를 지정합니다. 아래 그림은 예시를 보여줍니다. 명령어 데이터를 언패킹하여 다양한 명령어(예: Lock, Unlock)가 선택됩니다. 따라서 entrypoint에서 도달할 수 있는 명령어는 모든 사람에게 공개되어 있으며 지정된 명령어 데이터로 실행될 수 있습니다.

3. 계정 유효성 검사

앞서 언급했듯이, 프로그램은 읽거나 쓸 계정을 수신합니다. 이 설계에는 두 가지 문제가 발생합니다. 읽을 계정의 경우, 계정에 저장된 데이터가 신뢰할 수 있는지 어떻게 보장할 것인가. 쓸 계정의 경우, 권한 있는 사용자만 계정에 쓰는 명령어를 호출할 수 있는지 어떻게 보장할 것인가. 이하에서는 접근 제어 문제를 설명합니다. 모든 테스트 코드는 여기에서 찾을 수 있습니다.

3.1 코드 리뷰 (PrivilegeOwner)

먼저 두 가지 구조체인 Door와 Config를 정의합니다. 구조체 door에 지정된 key 계정(17번 줄)만 생성된 door를 열 수 있습니다. 그러나 구조체 Config(81번 줄)에 지정된 시스템 상태가 잠겨 있을 때는 문을 열 수 없습니다.

앞서 언급했듯이, Config 계정은 문을 열 수 있는지 여부를 지정합니다. 이 경우 프로그램에는 Config 계정이 하나만 있어야 합니다. 이를 달성하기 위해 PDA를 사용하여 Config의 데이터를 저장합니다. Config 계정을 초기화한 후, 공격자에 의해 다시 초기화될 수 없도록 is_initialized 속성을 true로 설정합니다(108번 줄 - 110번 줄).

명령어 Open()은 문을 여는 데 사용됩니다. 이 명령어는 열릴 door 계정, config 계정, 그리고 door를 열려는 owner 계정을 포함한 여러 계정을 수신합니다. 문이 프로그램에 속하고 구성이 유효한지 보장하기 위해, door 계정과 config 계정의 소유자를 확인합니다(204번 줄 - 205번 줄). 이는 악의적인 사용자가 가짜 계정을 제공하는 것을 방지합니다. 이것이 첫 번째 질문에 대한 답입니다. 읽을 계정이 신뢰할 수 있는지 보장하려면 계정의 소유자를 확인해야 합니다! door 계정의 소유자만 문을 열 수 있다는 점에 유의하세요. 이 경우, owner 계정이 door의 실제 owner인지, 그리고 더 중요하게는 명령어가 소유자에 의해 승인되었는지 확인합니다(217번 줄 - 219번 줄).

validate_owner() 함수에서, 먼저 두 계정의 공개 키가 동일한지 확인하고, 그 다음 소유자의 서명을 확인합니다. 이것이 두 번째 질문에 대한 답입니다. 권한 있는 사용자만 open 명령어를 호출할 수 있도록 보장하려면 계정의 소유자와 서명자를 확인해야 합니다. close 명령어는 open과 유사하며 세부 사항은 코드에서 확인할 수 있습니다.

프로그램을 테스트넷에 배포했으며 다음 링크에서 찾을 수 있습니다.

https://explorer.solana.com/address/2Q7FFMWCthBvc6ubLQRx9TRswvaimmd66VaCAfHwsYuC?cluster=testnet

모든 테스트 트랜잭션은 아래에 나열되어 있습니다. 이 트랜잭션의 전체 과정은 AllocatePDA()-> InitializeDoor()-> InitializeConfig()-> Unlock() -> Open() -> Close()입니다.

https://explorer.solana.com/tx/2X9CyMrHTNEvbzXTE95gem2j8spnvsQsabFeSpV8hiNpYjiQPPzLRqt5KN86ZYRjnQvydvs7y5eUjJK7no8knDhk?cluster=testnet
https://explorer.solana.com/tx/2XfVWiXeQeHbpqAEYm3AH2RU6hunnqtr155EC4EAM5Bq9VVZNP6QocAav9cPjEQdJFcQrbsSSxiKadr4HPMov8pz?cluster=testnet
https://explorer.solana.com/tx/5Em41sg7yFXeNpnEJnhUQJanfLWKwjMqiBeNAqEEzFrSN9P8zKKafcv5F7RKT2pseB171qeoa8Uz4fKgazzayCnW?cluster=testnet
https://explorer.solana.com/tx/2PMtzpSgjnKDLGmRWBdUSFBPimWnudCPekUYbWzPzokENFYa4N4ab4HCtynfGrzswFPTgGYKHU8PccUMHv3mXHkR?cluster=testnet
https://explorer.solana.com/tx/3kviP9MqkWGMV4yA7k7yPQ5BGfXmcYLcctmY1u2D7n56eT1nx8jMtDumkUNJy8yA3KkmzrmfQLjqpigc8ehGZzBN?cluster=testnet
https://explorer.solana.com/tx/38iEaJBzuGMLbfcszdVB8pkniezH8JrA3XGq7JdADZTQ4hNQC82GSTUA2bmcypdVy3t7htWnUzkZ4F8EakmNvqz8?cluster=testnet

3.2 공격 트랜잭션

소유자 확인과 서명자 확인의 중요성을 보여주기 위해, 두 가지 공격 시나리오를 예시로 사용합니다.

첫 번째 시나리오

첫 번째는 config가 잠겨 있을 때 'door' 소유자가 문을 열려는 시도입니다. 이를 위해 다른 프로그램에서 가짜 config 계정을 생성하고, is_lock 속성에 false 값을 할당합니다. 커스텀 프로그램의 코드는 아래와 같습니다.

가짜 config 계정을 생성하기 위해 트랜잭션을 전송하며, 가짜 config 계정의 공개 키는 2MtSrbWp24VjPZQcSUkiWrvNro7qqKemVCsh3Yxc8LTy입니다.

https://explorer.solana.com/tx/2qSyrL5gdQXmgGCFzmzMm1StFQRkDgWpss9A9jV11q2fgDGM5C1XRuXvbX1N5Dt3q2pRqnmyXHVtXGF5dqadAzpJ?cluster=testnet

가짜 config 계정이 생성되면, 이를 프로그램에 입력합니다(423번 줄).

결과는 아래와 같으며, 로그에 incorrect program id for instruction이 출력되어 config 계정의 소유자가 반드시 프로그램이어야 함을 의미합니다. 따라서 공격자는 이 검사를 우회할 수 없습니다.

두 번째 시나리오

두 번째 시나리오는 악의적인 사용자가 문이 잠금 해제된 상태에서 문을 열려는 시도입니다.

이 경우, 실제 owner 계정을 프로그램에 입력하고(419번 줄) 트랜잭션을 전송합니다. 결과는 아래와 같습니다.

Signature verification failed가 출력되어, 실제 소유자가 문을 열기 위해 트랜잭션에 서명해야 함을 의미하므로 두 번째 공격도 실패합니다.

4. 요약

Solana에서 명령어는 클라이언트 또는 다른 프로그램이 제공하는 다양한 계정을 기반으로 지정된 로직을 구현합니다. 따라서 계정에 대한 적절한 확인이 매우 중요합니다.

이 글에서는 계정을 올바르게 확인하는 방법을 소개하고, 두 가지 공격 시나리오를 사용하여 이러한 확인의 중요성을 설명합니다. 계속 팔로우하시면 더 많은 글이 공유될 예정입니다.

이 시리즈의 다른 글 읽기:


BlockSec 소개

BlockSec은 2021년 세계적으로 저명한 보안 전문가 그룹에 의해 설립된 선구적인 블록체인 보안 회사입니다. 이 회사는 대중적 채택을 촉진하기 위해 신흥 Web3 세계의 보안성과 사용성을 향상시키는 데 전념하고 있습니다. 이를 위해 BlockSec은 스마트 컨트랙트 및 EVM 체인 보안 감사 서비스, 보안 개발 및 위협을 선제적으로 차단하기 위한 Phalcon 플랫폼, 자금 추적 및 조사를 위한 MetaSleuth 플랫폼, 그리고 Web3 빌더들이 암호화폐 세계에서 효율적으로 탐색할 수 있는 MetaSuites 확장 프로그램을 제공합니다.

현재까지 이 회사는 MetaMask, Uniswap Foundation, Compound, Forta, PancakeSwap 등 300개 이상의 저명한 고객사에 서비스를 제공했으며, Matrix Partners, Vitalbridge Capital, Fenbushi Capital을 포함한 저명한 투자자들로부터 두 차례의 자금 조달 라운드에서 수천만 달러를 유치했습니다.

공식 웹사이트: https://blocksec.com/

공식 트위터 계정: https://twitter.com/BlockSecTeam

Sign up for the latest updates
약 557만 USD 손실: X100 Freezer·NEM 공격 | BlockSec 주간 보고서
Security Insights

약 557만 USD 손실: X100 Freezer·NEM 공격 | BlockSec 주간 보고서

이 주간 보고서는 2026년 10월 19일–2026년 10월 25일에 Ethereum과 BNB Chain에서 발생한 보안 사고 두 건을 다룹니다. 플래시론으로 자금을 조달해 X100 Freezer의 거버넌스를 장악한 사건과 BNB Chain의 NEM 토큰 유동성 풀에 영향을 미친 세금 정산 결함을 살펴봅니다. 보고서 범위에 포함된 추정 손실액은 X100의 대표 거래에서 발생한 약 475만 USD와 NEM 풀 사고에서 발생한 약 82.0만 USD를 합쳐 총 약 557만 USD입니다. 이 총액에는 별도로 보고된 후속 X100 자금 유출액은 포함되지 않습니다.

Autheo Network·UNCX 해킹으로 약 387만 USD 손실 | BlockSec 주간 소식
Security Insights

Autheo Network·UNCX 해킹으로 약 387만 USD 손실 | BlockSec 주간 소식

이 주간 보고서는 2026년 10월 12일–2026년 10월 18일 기간에 발생한 보안 사고 3건을 다루며, 총 추정 손실액은 약 387만 USD입니다. Autheo Network에서는 개인 키 침해로 약 176만 USD의 손실이 발생했고, Qubic Wallet에서는 취약한 시드 생성으로 약 130만 USD의 손실이 발생했습니다. UNCX Network의 Smart Token Vesting V2 계약에서는 Ethereum, BNB Chain, Base, Robinhood Chain에 걸쳐 약 80.7만 USD의 손실을 초래한 회계 오류가 발생했습니다. 중점적으로 다룬 UNCX 분석에서는 잘못된 지분 합산 계산이 서로 다른 토큰 대 지분 비율로 생성된 베스팅 트랜치를 혼합해 공유 풀에서 초과 인출을 가능하게 한 과정을 설명합니다.

SEAL 인증이란? 암호화폐를 위한 운영 보안 보증
Security Insights

SEAL 인증이란? 암호화폐를 위한 운영 보안 보증

SEAL 인증은 합의된 범위 내에서 암호화폐 운영 보안에 대한 독립적인 보증을 제공합니다. 인증의 6개 모듈, 증빙 자료 요건, 인증의 한계와 BlockSec의 평가 절차를 살펴보세요.