
이 문서는 Consensys Diligence와 MSQ 프로젝트가 DFinity Foundation 및 MetaMask Snaps DAO의 지원을 받아 협력하여 작성되었습니다.

Consensys Diligence는 Consensys Software Inc. 산하의 감사 전문 부서로, Solidity, Cairo 및 다양한 ZK 라이브러리에 걸친 정밀 감사 분야에서 탁월한 전문성을 보유한 것으로 널리 알려져 있습니다. Diligence 팀은 MetaMask Snaps의 감사 및 보안 표준을 선도하며, MetaMask 팀과 긴밀히 협력하여 지갑 기능의 보안을 보장합니다. 또한 Diligence 팀은 보안 툴링 개발과 가장 까다로운 프로덕션 환경에서 검증된 최첨단 지속적 퍼징(fuzzing) 솔루션 개발을 선도하고 있습니다.
MSQ 프로젝트는 최근 MetaMask Snaps 스토어에 출시되었습니다. MSQ는 사용자가 Internet Computer 네트워크와 상호작용하고, IC 기반 토큰을 관리하며, IC 기반 dapp에서 안전하게 인증하고, 디지털 상품 및 서비스 결제를 가능하게 하는 Snap입니다. 본질적으로 MetaMask와 통합된 크립토 지갑으로, 인증 및 결제를 위한 고유 기능을 갖추고 Internet Computer에 특화되어 설계되었습니다.
Diligence 팀과 MSQ 팀은 공동으로 이 글에서 다룰 다섯 가지 핵심 영역—문서화, 소프트웨어 설계, 코드, 공급망, 수정—을 선정하였습니다. MSQ 팀이 개발 과정에서 활용한 실천 방법 목록과 함께, Diligence 팀이 해당 방법들의 보안적 이점을 설명하는 해설을 제공합니다. 이는 MetaMask Wallet 또는 보안 감사 대상이 될 수 있는 보안 중요 시스템을 위한 Snap을 개발하는 모든 분들에게 유용한 자료가 될 것입니다. 시작해 보겠습니다!
문서화는 머릿속의 개념을 다른 사람들이 볼 수 있는 형태로 변환합니다. 계층적 문서화는 독자를 점진적으로 맥락에 몰입시켜 의도한 방식으로 개념을 이해할 수 있도록 돕습니다. 문서가 명확할수록 프로젝트에 대한 더 넓은 시각을 제공하고, 다른 사람들이 더 잘 이해할 수 있습니다.
문서화 계층은 독자가 일반적으로 접근하는 순서의 역순으로 정의하며, 각 계층은 더 높은 수준의 추상화를 제공합니다. 이를 통해 큰 그림부터 시작하는 독자가 점진적으로 세부 사항으로 깊이 들어갈 수 있습니다.
소프트웨어에 관한 궁극적인 정보 출처는 코드 자체이며, 이는 문서화의 기초 계층 역할을 합니다. 코드에는 필요한 모든 정보가 담겨 있지만, 이 정보를 처리하기가 어렵습니다. 코드가 깔끔할수록 상위 수준의 추상화를 파악하기 쉬워집니다. 그러나 실제 시스템에서는 이러한 추상화가 시스템 구성 요소들의 복잡한 상호작용, 수 주간 쌓인 기술 부채, 그리고 빠르고 임시방편적인 해결책 뒤에 숨겨져 있습니다.
따라서 무엇보다 먼저, 코드를 읽는 사람들이 시스템의 복잡한 부분에 의해 오해를 받지 않도록 보호해야 합니다. 가장 좋은 방법은 코드를 읽는 데 필요한 인지 부하를 줄이는 것입니다. 몇 가지 전략은 다음과 같습니다:
IDE에서 쉽게 탐색할 수 있도록 코드를 탐색 가능하게 만들기
코드 요소의 목적과 기능을 명확히 하는 상세한 명명 사용
명확한 데이터 형식을 정의하기 위해 강타입 언어 활용
MSQ Snap과 dapp 프론트엔드는 TypeScript로 개발되었으며, 이는 일반 JavaScript의 함정과 대조적으로 수많은 잠재적 오류를 방지했습니다. 마찬가지로, 백엔드는 강력한 타입 시스템으로 알려진 Rust를 활용합니다. 또한 MSQ Snap은 서드파티 앱이 실행할 수 있는 다양한 메서드를 내보냅니다. 그러나 이러한 메서드를 식별하는 데 문자열을 사용하지 않고 상수를 사용합니다. 다음과 같은 상수 객체를 사용합니다:
코드에서 이 상수 객체는 올바른 메서드에 접근하기 위한 가이드로 사용될 수 있으며, 독자는 객체 내 식별자를 통해 해당 메서드에 대해 많은 것을 이해할 수 있습니다. 예를 들어, SNAP_METHODS.protected.identity.login 메서드는 MSQ의 companion dapp에서만 실행할 수 있으며 사용자가 로그인할 수 있도록 합니다. 이 접근 방식은 코드 명확성을 높이고 리팩토링을 단순화합니다. 메서드 이름 변경이 여러 곳에서 개별적으로 업데이트되는 대신 중앙에서 관리되기 때문입니다.
메서드 이름을 매칭하기 위해 다음과 같은 분기를 가진 큰 switch 표현식을 사용합니다:
보시다시피, 여기서 무언가를 잘못 해석하기가 매우 어렵습니다—모든 것이 정확하게 명명되어 있어 상상의 여지가 없습니다.
Diligence 코멘트 시간은 중요한 요소입니다. 개발자들은 코드베이스를 이해하는 데 몇 주가 있지만, 보안 엔지니어들은 종종 위험을 식별하는 데 며칠밖에 없습니다. 이러한 제약은 코드의 인지 부하를 줄이는 것의 중요성을 강조하며, 이는 개발자 효율성과 보안 모두에 이점을 줍니다.
MSQ의 코드베이스에서 배울 수 있는 것은, 설명적인 명명과 강타입(TypeScript 등)을 갖춘 명확하고 탐색 가능한 코드가 오해를 줄인다는 것입니다. 오해는 취약점의 일반적인 원인입니다.
단, TypeScript 타입 어노테이션은 컴파일 타임에만 검사된다는 점을 기억하세요! 런타임에 처리되거나 파싱되는 모든 데이터(RPC, JSON 등)에는 추가적인 타입 강제, 데이터 형식 및 범위 검사가 필요합니다! 이를 위해 MSQ는 정적 타입 추론을 갖춘 TypeScript 우선 스키마 유효성 검사 라이브러리인 zod를 우아하게 활용하며, 팀들이 이 접근 방식을 따르도록 권장합니다.
MSQ는 적절한 양의 주석을 통해 코드 의도를 명확하게 만드는 최적의 균형점을 찾았습니다. 이러한 명확성은 보안 연구자들이 코드베이스의 "핵심 흐름"과 주요 개념을 빠르게 파악하는 데 도움이 됩니다. 이해하기 쉬운 코드를 작성함으로써 개발자들은 신속한 보안 검토의 효과를 크게 높입니다.
주석 작성은 코드의 100%를 커버하는 것이 아니라고 생각합니다. 복잡하거나 잘못 작성된 부분에 주석을 다는 것이 중요합니다. 정규 표현식, 암호화, 문자열 조작과 같은 영역은 명확한 주석으로 특히 도움을 받습니다.
예를 들어, MSQ에는 문자열에서 가능한 Markdown 제어 문자를 이스케이프하는 함수가 있습니다. 본문은 한 줄의 코드이지만 정규 표현식 매칭이 포함되어 있어 주석으로 기능을 설명합니다:
워크플로우에 AI를 활용하는 것에 거부감이 없다면, ChatGPT는 이러한 유틸리티 함수에 대한 좋은 주석을 빠르게 생성하는 데 탁월합니다(단, 출력 결과를 반드시 검토하세요).
Diligence 코멘트 보안 검토자로서 우리는 함수 주석을 낯선 코드를 탐색하는 로드맵으로 활용합니다. 코드를 검토할 시간이 제한되어 있으며, 주석이 구현과 일치하지 않을 때는 단순히 혼란스러운 것이 아니라 경고 신호입니다.
이는 종종 함수나 설명이 사양에서 벗어났음을 나타내며, 잠재적 취약점을 시사합니다. 함수가 약속된 검사를 건너뛰거나 데이터를 예상치 못하게 처리할 수 있으며, 이는 심각한 결과로 이어질 수 있습니다.
따라서 MSQ가 코드베이스에서 하는 것처럼 주석을 간결하고 정확하게 유지하세요. 인라인 주석은 단순한 메모가 아니라 코드를 안내하는 등대이며, 불일치는 무언가 잘못되었을 수 있다는 단서입니다.
코드와 그 복잡성이 잘 문서화되었다면, 다음 단계는 시스템의 아키텍처를 개략적으로 설명하는 것입니다. 여기에는 구성 요소 간의 상호작용, 소프트웨어가 사용하는 프로토콜, 알고리즘 및 데이터 구조를 상세히 설명하는 것이 포함됩니다. 이 계층은 주로 코드보다는 텍스트와 다이어그램과 같은 사람이 읽을 수 있는 형식을 사용합니다.
MSQ의 시스템 문서에는 아키텍처 개요와 통합 가이드가 포함되어 있습니다. 텍스트 설명, 예시, 다이어그램이 풍부한 이 문서들은 시스템의 다양한 부분이 어떻게 상호작용하는지 명확히 합니다.
시퀀스 다이어그램은 구성 요소 상호작용을 시각화하는 데 매우 유용합니다. 다양한 프로젝트에서 다목적으로 활용되는 무료 도구인 diagrams.net (draw.io)을 사용하도록 권장합니다.
Diligence 코멘트 함수를 상세히 설명하는 인라인 주석과 달리, 시스템 문서는 애플리케이션의 전체 구조를 조망하는 10,000피트 높이의 시각을 제공합니다. 이 관점은 코드 수준에서는 종종 보이지 않는 구성 요소 간 문제나 사용자 흐름 취약점을 발견하는 데 매우 중요합니다.
보안 검토를 Command & Conquer 게임처럼 생각해 보세요. 대부분 가려진 지도로 시작합니다. 탐색하면서 시스템 문서는 정찰 유닛처럼 작동하여 전체 아키텍처—권한, Snap-dApp 상호작용, 사용자 상호작용—를 드러냅니다. 이 전개되는 개요를 통해 검토자들은 게임 유닛의 움직임을 추적하듯 사용자 여정을 추적하여 보안을 우회할 수 있는 경로를 발견할 수 있습니다.
또한 포괄적인 시스템 문서에는 보안 관련 비고와 이상적으로는 위협 모델링 연습의 결과물이 포함되어야 합니다. 주요 구성 요소, 상호작용, 위험, 행위자 및 일반적인 사용자 흐름에 대한 명확한 개요를 제공하여 검토자들이 우선순위가 높은 영역에 집중하고 사양에서 벗어난 부분을 발견할 수 있도록 합니다.
개발자들에게 좋은 시스템 문서는 단순한 서류 작업이 아닙니다. 공격적 및 방어적 전략을 안내하는 공유 지도로, 보안 검토를 맹목적인 탐색에서 전략적 작업으로 전환시킵니다.
이 계층에는 기사, 랜딩 페이지, 블로그 게시물, 데모 영상 등 다양한 자료가 포함됩니다.
이 정보는 주로 비즈니스 관련 내용이지만, 이전 계층들이 다양한 수준의 세부 사항으로 "어떻게?"라는 질문에 답했다면, 이 계층은 "무엇?"이라는 질문에 크게 답합니다.
신규 방문자는 이러한 자료를 통해 프로젝트를 처음 접할 가능성이 높으므로, 이 계층을 최대한 단순하고 시각적으로 유지하는 것이 좋습니다. 또한 이러한 자료는 일반적으로 소프트웨어가 실제로 작동하는 모습—사용자가 소프트웨어를 사용하여 상태 A에서 상태 B로 어떻게 이동할 수 있는지—을 보여주는 유일한 자료입니다. 실제 작동 모습을 통해 사람들은 소프트웨어의 핵심 아이디어를 파악하고, 내부적으로 어떻게 작동하는지 추측할 수 있습니다.
예를 들어, MSQ의 랜딩 페이지 히어로 화면에는 큰 글씨로 "USE THE INTERNET COMPUTER WITH METAMASK"라고 적혀 있습니다. 이 간단한 문장을 읽은 독자는 아마도 이렇게 추측할 것입니다: "아, 이건 Internet Computer 블록체인의 토큰을 저장할 수 있는 지갑 Snap이구나. 다른 블록체인을 위한 다른 Snap들과 같은 방식으로 작동하되, IC의 개발 생태계 기술을 사용하는 것이겠지"—이는 100% 정확한 추측입니다.
Diligence 코멘트 MSQ 및 수많은 다른 블록체인 프로젝트에 대한 경험을 통해, 명확하고 고수준의 문서화가 단순히 유익한 것이 아니라 사용자 채택과 보안 모두에 있어 매우 중요하다는 것을 일관되게 확인했습니다. MSQ의 Snap 검토 중 다층적 문서화 접근 방식에 긍정적으로 놀랐습니다. 개발자의 영상 안내를 통해 빠르게 파악할 수 있었습니다. 코드를 보기 전에도 Snap의 기능을 빠르게 이해할 수 있었습니다. 이 고수준 개요는 예상 동작과 일반적인 사용자 흐름에 대한 해설과 함께 사용자 인터페이스를 보여주었습니다. 이러한 시각적 자료는 매우 유용하여 보안 전문가들이 애플리케이션에 인코딩된 의도된 "행복한 경로(happy path)"를 훨씬 빠르게 파악하고 이러한 경로에서 벗어난 곳에 숨겨진 취약점을 찾을 수 있게 합니다. 이것과 Snap 및 코드의 라이브 안내를 결합하는 것이 일반적으로 보안 검토의 이상적인 시작점입니다.
이 부분은 아마도 프로젝트 보안에 있어 가장 중요한 부분일 것입니다. 코드가 버그로부터 100% 안전하고 인프라가 수백만 달러 상당의 다양한 조치로 보호될 수 있습니다. 그러나 설계에 악의적인 행위자가 악용할 수 있는 근본적인 결함이 있다면 이러한 모든 노력은 의미가 없습니다.
구체적인 예시는 사용 사례에 따라 다르지만, 몇 가지 보편적인 팁을 제공합니다.
MSQ 시작 시, 우리의 비전과 일치하는 핵심 보안 원칙을 수립했습니다:
MSQ 팀은 아무것도 모른다: 키 자료, 인증 세션 데이터, 계정 세부 정보를 포함한 사용자 민감 정보를 수집하지 않습니다.
암호화 자료는 Snap을 절대 벗어나지 않는다: 보호된 사용자 MetaMask 엔트로피는 Snap 내에서만 처리되고, 필요 시 생성되며, 사용 후 즉시 폐기됩니다.
MSQ는 결정론적이다: 사용자는 추가 지식 없이 루트 시드 구문만으로 모든 자금, 신원 및 키 쌍을 결정론적으로 복구할 수 있습니다.
MSQ는 프라이버시 우선이다: 우리의 노력은 무엇보다 사용자 프라이버시를 최우선으로 합니다.
이러한 원칙은 MSQ의 특정 요구 사항에 맞게 조정되었습니다. 그러나 MetaMask 팀도 MSQ가 준수하는 Snap 개발자를 위한 보안 가이드라인을 제공하며, 여기에서 확인할 수 있습니다.
예를 들어, 최소 권한 원칙이 있는데, 이는 기본적으로 Snap이 사용자에게 요청하는 권한이 적을수록 보안이 더 좋다는 것을 의미합니다. MSQ는 4가지 권한만 요청합니다:
endowment:rpc
snap_dialog
snap_manageState
snap_getEntropy
MSQ는 트랜잭션 서명만 담당하고 IC에 전달하는 것은 담당하지 않기 때문에 endowment: network access가 필요하지 않습니다—후자는 통합 dapp의 책임입니다.
여러분의 Snap에서도 동일하게 해야 합니다—MetaMask의 기본 가이드라인을 가져와 특정 규칙으로 확장하고 따르세요.
Diligence 코멘트 우리는 고객들에게 "보안은 추가하는 기능이 아니라 설계 중심에 두는 원칙입니다"라고 말합니다. MSQ가 프로젝트 시작 시 핵심 보안 원칙을 수립한 것이 바로 우리가 찾는 것입니다. 너무 많은 프로젝트들이 보안을 사후 고려 사항으로 취급하여 핵심 아키텍처가 설정된 후에 조치를 추가합니다. 이러한 사후 접근 방식은 코드 수준의 수정으로는 진정으로 해결할 수 없는 근본적인 결함을 필연적으로 남깁니다.
Consensys Diligence에서 우리는 보안 전문가 서비스, 툴링을 제공하고 최종 사용자의 권리를 옹호합니다. 여기에는 사용자의 키 자료가 지갑 신뢰 경계 내에서 안전하게 유지되고, 이 영역 밖으로 의도치 않게 노출되지 않도록 보장하는 것이 포함됩니다. 또한 사용자 프라이버시를 보존하는 데 집중하며, 이상적으로는 메타데이터나 사이드 채널 정보가 서드파티에 유출되는 것을 방지합니다. 추가적으로, Snap이 기능에 필요한 최소한의 권한만 요청하도록 촉구합니다—최소 권한 원칙.
MSQ의 선제적 입장은 이러한 원칙과 일치합니다. 처음부터 보안을 우선시함으로써 본질적으로 취약점에 더 강한 기반을 구축하고 있습니다.
이것은 메타 가이드라인에 가깝습니다—온라인 게임부터 뱅킹 시스템까지 모든 소프트웨어에 구현되어야 하는 원칙입니다.
MSQ에서 이것의 가장 주목할 만한 예는 신원 관리에 대한 접근 방식입니다. 아시다시피, 대부분의 지갑은 사용자에게 신원(주소, 계정 등) 세트를 제공합니다. 이 세트는 사용자의 동의 하에 모든 dapp이 접근할 수 있습니다. 예를 들어, 일부 트랜잭션에 서명하기 위해서입니다.
이는 dapp 간 통합에 매우 유용합니다. 모든 dapp이 사용자를 대신하여 다른 dapp의 스마트 컨트랙트 메서드를 호출하고 서로의 기능을 확장할 수 있기 때문입니다. 예를 들어, 크립토 결제 플랫폼은 Uniswap의 스마트 컨트랙트를 호출하여 구매자의 토큰을 자동으로 스왑하여 판매자가 특정 상품이나 서비스의 결제로 받기를 기대하는 것과 일치시킬 수 있습니다.
그러나 이는 보안에 해롭습니다. 사기 웹사이트가 사람들을 속여 악의적인 트랜잭션에 서명하게 하고 지갑을 비울 수 있기 때문입니다.
이와 대조적으로, MSQ는 신원 범위 지정 기술(identity scoping technique)을 채택합니다—각 dapp(각 고유 URL 출처)은 상호작용할 수 있는 자체 별도의 사용자 신원 세트를 가지며, 다른 dapp의 사용자 신원과 상호작용할 수 없습니다. 이는 사기 웹사이트 문제를 해결할 뿐만 아니라 프라이버시에도 크게 도움이 됩니다. dapp이 더 이상 사용자를 추적하고 사용자가 어떤 스마트 컨트랙트(IC에서는 캐니스터(canister)라고 함)와 상호작용하는지 볼 수 없기 때문입니다. Internet Identity와 WebAuthn 사양에서 영감을 받은 이 방법은 보안 위험을 크게 완화합니다.
예를 들어, 잘 알려진 dapp이 침해된 경우, 전통적인 지갑은 모든 dapp에 걸쳐 취약할 것입니다. 반면, MSQ의 신원 범위 지정은 위협을 침해된 dapp으로 제한하여 더 광범위한 피해를 방지합니다.
그러나 이 방법은 사용자가 각 dapp에서 고유한 신원을 가지므로 dapp 간 직접 통합을 제한합니다. MSQ는 도메인 이름 변경과 같은 상황에 유용한 이중 동의를 통한 dapp 간 신원 공유 허용과 같은 특정 시나리오에 대한 솔루션을 제공합니다.
또한 MSQ는 dapp이 접근할 수 있는 데이터가 관련 신원에 엄격히 연결되도록 하여 사용자 정보를 더욱 보호하고 다양한 애플리케이션에서 프라이버시를 유지합니다.
Diligence 코멘트 제한된 직접 dApp 통합의 트레이드오프는 사려 깊은 결정입니다. 위험 평가에서 우리는 종종 "보안 예산"에 대해 논의합니다—완벽한 보안이 기능을 방해할 수 있다는 것을 인정하면서. MSQ는 이 예산을 현명하게 사용했습니다. dApp 간 상호작용을 제한함으로써 가장 심각한 위험 중 하나(광범위한 신원 남용)를 크게 줄이면서 핵심 지갑 기능을 보존했습니다.
문서화를 논의할 때 코드에 대해 조금 이야기했습니다. 여기서는 가독성보다 기술과 더 관련된 코드의 몇 가지 다른 측면을 강조하고자 합니다.
여기서 "견고한"이란 코드가 예상되는 모든 입력과 예상치 못한 입력을 포함하여 예측 가능하게 동작한다는 것을 의미합니다. 예를 들어, hex를 기대할 때 base64 문자열이 주어지면 Snap은 어떻게 반응해야 할까요? 또는 메서드가 의도하지 않은 순서로 호출되거나 정의되지 않은 RPC 메서드가 호출되면 어떻게 해야 할까요?
이러한 불확실성을 해결하려면:
명확한 오류 처리: 코드의 모든 분기와 케이스가 적절하게 검사되고 처리되도록 합니다. MSQ의 Snap에서는 TypeScript의 switch-case 문에서 완전한 검사를 사용하여 예상치 못한 메서드 호출을 포착합니다. 아래와 같이:
이 설정은 알 수 없는 RPC 메서드 식별자가 사용되는 경우를 포착합니다.
입력 검증: 입력 데이터를 예상 타입과 형식에 대해 검증하는 것은 복잡할 수 있지만 보안에 필수적입니다. TypeScript에서 zod 라이브러리를 활용하여 TypeScript의 타입 시스템을 런타임 검사로 확장합니다. Zod는 상세한 스키마 정의를 허용하여 유효한 데이터만 처리되도록 합니다.
예를 들어, SNAP_METHODS.protected.identity.login 메서드는 zod 스키마를 사용하여 입력을 엄격하게 검증합니다:
여기서 ZOrigin과 ZIdentityId는 단순한 문자열이나 숫자가 아니라 특별히 검증된 하위 타입으로, 입력이 타입적으로 올바를 뿐만 아니라 문맥적으로도 적절함을 보장합니다.
zod 스키마를 최대한 정밀하게 정의함으로써 많은 잠재적 문제를 선제적으로 해결할 수 있습니다. 감사자들은 MSQ에서 엄격한 검증을 강제하도록 권고했으며, 구현 후 여러 보안 위험이 식별되고 수정되었습니다.
Diligence 코멘트 특정 공격 시나리오에 대한 권고 사항을 기반으로 더 엄격한 검증을 구현한 결과 다른 여러 보안 위험이 드러났다는 이야기를 고객들로부터 처음 듣는 것이 아닙니다. 이는 우리의 경험과 정확히 일치하며, 그래서 우리는 항상 공격 표면을 줄이기 위한 엄격한 입력 검증을 옹호합니다. 많은 보안 검토에서 입력 검증을 면밀히 검토하는 것으로 시작합니다. 이를 강화하면 종종 잠재된 문제들이 드러납니다—하나의 취약점을 수정하면 다른 취약점이 드러나는 도미노 효과. 이는 프로젝트가 피드백을 진지하게 받아들이고 시스템을 반복적으로 강화하고 있다는 명확한 신호입니다. 공격 표면이 줄어들면 공격자가 취약점을 성공적으로 악용하기가 점점 더 어려워집니다.
MSQ에서 우리는 dapp 개발자들에게 Snap과의 올바르고 효율적인 상호작용을 용이하게 하는 직관적인 라이브러리를 제공하는 것이 우리의 의무라고 생각합니다. 이를 통해 MSQ뿐만 아니라 서드파티 개발자들도 깔끔하고 견고한 코드베이스를 유지할 수 있습니다.
이러한 라이브러리는 여러 이유로 유익합니다:
API 복잡성 단순화: Snap의 복잡성을 사용자 친화적인 API로 추상화합니다. 예를 들어, MSQ의 클라이언트 라이브러리는 데이터 인코딩에 CBOR을 사용하여 JSON-RPC의 제약을 우회하고 개발자들이 수동 데이터 인코딩 및 디코딩의 번거로움을 덜어줍니다.
안전하고 직접적인 상호작용 보장: 특정 Snap 기능은 companion dapp에만 독점적입니다. 이를 용이하게 하기 위해 postMessage를 통한 원활한 흐름을 보장하면서 리디렉션 및 데이터 전송 프로세스를 관리합니다. 이 내부 처리는 서드파티 개발자들이 명확하고 간단한 API를 통해 Snap과 상호작용하도록 보장합니다.
의미론적 명확성 향상: 깔끔한 API는 단순한 도구 이상입니다. 복잡한 인코딩/디코딩 프로세스와 추가 운영 계층의 혼란 없이 코드를 더 읽기 쉽고 이해하기 쉽게 만드는 커뮤니케이션 매체입니다.
이러한 측면을 우선시함으로써 MSQ는 Snap과 통합 dapp 모두가 효율적이고 안전하게 운영될 수 있는 생태계를 만들고자 합니다.
Diligence 코멘트 라이브러리를 통한 서드파티 코드 통합에 대한 MSQ의 접근 방식은 보안을 유지하면서 개발을 단순화하려는 의지를 보여줍니다. 핵심적으로 보안은 Snap 컨텍스트에서 엄격하게 강제되어야 하지만, dapp 대면 라이브러리는 Snap과 통신하는 편리한 방법을 제공할 수 있습니다. 그러나 dapp 개발자는 dapp의 컨텍스트 내에서 사용될 때 Snap과의 안전한 상호작용과 데이터의 안전한 인코딩을 보장해야 한다는 점을 항상 유의해야 합니다.
최근 XZ 백도어는 악의적인 코드가 의존성 중 하나에 침투하는 것을 방지하는 것이 얼마나 중요한지를 다시 한번 강조했습니다. MSQ에서는 pnpm을 사용하여 의존성을 관리하지만, 실제로 어떤 패키지 관리자를 선호하는지는 차이가 없습니다. MSQ에서 이러한 공격 벡터로부터 보호하기 위해 두 가지를 수행합니다:
pnpm install --save <package-name>을 사용하면 일반적으로 semver 사양을 준수하는 최신 버전의 패키지가 설치되어 호환성을 깨지 않는 최신 버전으로 자동 업데이트가 허용됩니다. 이는 package.json에서 허용 가능한 버전 범위를 나타내는 캐럿(^) 기호로 표시됩니다:
"zod": "^3.22.4" // Installs version 3.22.4 or newer up to 4.0.0그러나 악의적인 업데이트로 인한 위험을 방지하려면 의존성을 특정 버전으로 고정하는 것이 더 안전합니다:
package.json에서 캐럿(^)을 제거하여 각 의존성 버전을 고정합니다. 기존 잠금 파일과 node_modules를 제거한 다음 pnpm install을 실행하여 정의된 버전에 엄격하게 맞춥니다.
향후 설치 시 --save-exact 플래그를 사용하여(pnpm install --save-exact <package-name>) 자동 업데이트를 방지합니다.
신뢰는 이 결정의 요소입니다. 예를 들어, MSQ에서는 @metamask와 @dfinity 의존성 네임스페이스를 안전하다고 간주하고 semver 범위 내에서 업데이트를 허용합니다. 그러나 그렇게 할 때는 전이적 의존성으로 인한 잠재적 취약점에 주의하세요.
Diligence 코멘트 프로젝트를 정확한 의존성 버전으로 전환하면 수많은 문제를 방지할 수 있습니다:
패치된 취약점이 자동 업데이트로 재도입되는 것을 막았습니다.
다른 모듈이 다른 라이브러리 동작을 보는 "버전 스큐"를 방지했습니다.
정확한 환경을 복제할 수 있어 사후 사고 조사에 매우 중요했습니다. 모든 다음 업데이트는 어떤 네임스페이스, 어떤 패키지에서든 악의적일 수 있습니다. 사용된 패키지를 검토하고 알려진 안전한 버전에만 고정하여 우발적인 업데이트를 방지함으로써 공급망 공격에 대한 공격 표면이 더욱 줄어듭니다. 특정 공급업체를 신뢰하는 것은 괜찮지만, 새 버전이 사용 전에 악의적인 코드를 포함하지 않는지 수동으로 확인해야 합니다. 특히 많은 프로젝트에서 사용되는 잘 알려진 패키지는 악의적인 행위자의 주요 표적이며, 과거가 보여주듯이 이러한 핵심 라이브러리는 정교한 공급망 공격에 취약할 수 있습니다(XZ 백도어 공격 참조).
팀 전체의 일관성을 보장하고 재현 가능한 빌드를 유지하려면 잠금 파일을 버전 관리 시스템에 커밋하세요. MSQ에서는 pnpm workspaces와 turborepo를 활용하여 단일 루트 잠금 파일인 pnpm-lock.yaml이 필요합니다. 그러나 설정에 따라 여러 잠금 파일을 유지해야 할 수 있습니다. 환경 일관성을 보장하기 위해 모두 버전 관리되어야 합니다.
Diligence 코멘트
이 관행은 때때로 단순한 개발 편의성으로 간과되지만, 실제로는 안전하고 안정적인 코드베이스를 유지하는 데 있어 중요한 구성 요소입니다. 스마트 컨트랙트, 블록체인 구성 요소, 그리고 이제 MetaMask Snaps를 감사한 수년간의 경험을 통해 재현 가능한 빌드가 단순히 있으면 좋은 것이 아니라 근본적인 보안 요구 사항임을 반복적으로 확인했습니다. 잠금 파일을 커밋하는 것은 공급망 공격에 대한 공격 표면을 줄이는 퍼즐 조각 중 하나입니다. npm install이 더 이상 복권이 아닐 때, 구체적인 버전과 체크섬이 저장소에 감사 추적을 남기고, 빌드가 더 결정론적이 되며, "내 컴퓨터에서는 작동해요" 논쟁이 사라집니다.
이것은 Snap에 직접적으로 관련된 것은 아니지만, 감사 결과를 효율적으로 처리하는 방법을 이해하는 것이 중요합니다.
감사팀이 발견 사항을 보고하는 즉시 수정 작업을 시작해야 합니다. 수정의 크기와 복잡성은 발견 사항에 따라 명확히 달라지지만, 가능한 경우 증상이 아닌 원인을 수정하여 더 작고 깔끔하게 만들라는 조언이 있습니다.
예를 들어, MSQ에서 감사자들은 MetaMask 동의 메시지에 Markdown 제어 문자를 주입할 수 있다는 것을 발견했습니다. 코드의 다른 부분에서 여러 변경을 하여 각 동의 메시지를 개별적으로 수정하는 대신, text()와 heading() 요소(@metamask/snaps-sdk에서)를 재정의하여 먼저 콘텐츠를 escapeMarkdown() 함수를 통해 전달한 다음 렌더링하도록 했습니다. 이를 통해 각 text()와 heading() 호출을 개별적으로 수정하는 대신, 동의 메시지가 있는 모든 파일의 import 표현식을 사용자 정의 요소로 간단히 교체할 수 있었습니다. 이것이 훨씬 더 깔끔한 수정이었습니다.
효과적인 해결은 특정 문제를 개선할 뿐만 아니라 보이지 않는 취약점에 대해서도 선제적으로 보안을 강화합니다.
Diligence 코멘트 너무 많은 프로젝트들이 근본적인 취약점 클래스를 고려하지 않고 각 개별 문제가 나타날 때마다 패치하는 두더지 잡기 방식으로 보안에 접근하는 것을 봅니다. 문제의 근본 원인을 해결하고 취약점 클래스를 전역적으로 제거하는 것을 주저하지 않음으로써, MSQ는 보안을 일련의 패치가 아닌 전체론적 규율로 이해하고 있음을 보여줍니다. 보안 전문가로서 우리는 고객들에게 수정을 서두르지 말고 보안 발견 사항을 프로젝트의 보안에 긍정적인 영향을 미치는 이벤트로 전환하는 데 충분한 시간을 갖도록 권장할 수 있을 뿐입니다.
이것으로 MetaMask Snaps 보안 감사를 성공적으로 탐색하는 방법에 대한 인사이트를 마칩니다. 이러한 가이드라인을 따름으로써 MSQ 팀은 Diligence 팀으로부터 긍정적인 보고서를 받을 수 있었습니다. MSQ의 경험을 공유함으로써 보안 감사 준비에 도움이 되어 철저하고 효과적인 프로세스를 보장하기를 바랍니다.
Consensys Diligence는 블록체인 생태계 전반에 걸친 다양한 프로젝트들이 프로토콜의 출시 준비를 갖추고 사용자를 보호하도록 구축하는 데 도움을 주었습니다. 맞춤형 감사를 통해 여러분의 Snap에서 이러한 취약점 및 그 이상을 확인해 드릴 수 있습니다. 지금 문의하고 견적을 받아보세요!
AI가 번역했습니다. 오류가 있을 수 있습니다. 항상 정보를 확인하시기 바랍니다.