EIP-712 타입 데이터 서명: 지갑이 무엇을 승인하라고 묻는 걸까?
EIP-712 타입 데이터 서명의 구조와 도메인 분리, 해시 과정, 재생 공격 위험, 서명 전 확인 항목을 쉽게 설명합니다.

지갑을 디앱에 연결했더니 트랜잭션 대신 낯선 양식이 나타납니다. 앱 이름, 체인, 컨트랙트, 기한과 여러 필드가 보이는데 가스비는 0원일 수도 있어요. 하지만 그 서명이 중요한 권한을 넘길 수 있습니다. **EIP-712 타입 데이터 서명(Typed Data Signing)**을 이해하는 일은 개발자만의 문제가 아니라 크립토 지갑 보안의 실전 기본기예요.
이 글에서는 EIP-712가 무엇을 구조화하는지, 지갑이 서명할 해시를 어떻게 만드는지, 이 표준이 무엇을 보장하지 않는지 살펴봅니다. 투자 조언이 아닙니다(NFA). 올바른 서명도 자산 손실로 이어지는 권한을 줄 수 있으니 독립적으로 확인하고, 권한을 제한하며, 스스로 조사하세요(DYOR).
EIP-712 타입 데이터 서명이란?
EIP-712는 타입이 있는 구조화 데이터(Typed Structured Data)를 해시하고 서명하는 표준 절차를 정의해요. 의미를 알 수 없는 바이트 묶음 대신 앱이 타입 이름, 서명 도메인(Domain), 해당 타입에 맞는 메시지 필드를 지갑에 전달합니다.
빈 영수증과 작성이 끝난 구매 주문서를 비교해 보세요. 둘 다 서명할 수 있지만 구매 주문서에는 공급자, 품목, 수량, 가격, 만료일이 나뉘어 적혀 있습니다. EIP-712는 이런 구조화된 주문서의 암호학적 형태를 일관되게 만들도록 해 줘요.
오프체인 주문, 투표, 로그인 문구, 토큰 퍼밋(Permit), 나중에 컨트랙트가 검증할 인가에 활용됩니다. 서명을 만드는 순간에는 보통 트랜잭션을 전송하지 않고 가스비도 들지 않아요. 그렇다고 안전한 것은 아닙니다. 누군가 나중에 그 서명을 온체인에 제출할 수 있어요.
타입 데이터 요청의 네 가지 구성요소
| 구성요소 | 역할 | 확인할 내용 |
|---|---|---|
types | 구조체와 필드 타입 정의 | 예상 밖의 필드, 오해를 부르는 이름 |
primaryType | 대표 구조체 이름 | 약속한 행동과 맞는지 |
domain | 앱·버전·체인·컨트랙트 맥락 분리 | 이름, 체인 ID, 검증 컨트랙트 |
message | 실제 값 | 수신자, 수량, 논스, 기한, 권한 범위 |
도메인에는 사람이 읽는 이름, 버전, 체인 ID, 검증 컨트랙트 주소, 솔트(Salt)가 들어갈 수 있어요. 앱은 필요한 필드만 선택합니다. 표준은 전달된 체인 ID가 현재 활성 체인과 다르면 사용자 에이전트가 서명을 거부해야 한다고 설명해요.
서로 다른 앱이 똑같이 생긴 Order나 Permit 구조를 정의할 수 있습니다. 도메인 분리(Domain Separation)는 해시를 특정 맥락에 묶어 한 앱의 서명이 다른 앱에서 같은 메시지로 취급될 위험을 줄여요. 다만 완전한 재생 공격 방어는 아닙니다.
EIP-712 서명 해시는 어떻게 만들어질까?
과정을 여러 겹의 봉투라고 생각하면 쉬워요.
- 앱이
Order(address maker,address asset,uint256 amount,uint256 nonce)같은 구조체를 설명합니다. - 구조체 정의를 정해진 방식으로 인코딩하고 해시해
typeHash를 만들어요. - 메시지 값을 타입에 따라 인코딩하고 결합해
hashStruct(message)를 만듭니다. - 도메인을 인코딩하고 해시해
domainSeparator를 만들어요. - EIP-191 접두사
0x1901, 도메인 구분자, 메시지 구조체 해시를 결합해 Keccak-256으로 최종 다이제스트를 만듭니다. - 지갑이 선택한 계정으로 그 32바이트 다이제스트에 서명해요.
중첩 구조체는 재귀적으로 처리합니다. 문자열이나 동적 바이트 배열은 내용의 해시로 표현해요. 프런트엔드, 지갑, 검증 컨트랙트가 각자 계산해도 같은 결과에 도달하도록 표준이 순서를 정합니다.
OpenZeppelin의 현재 EIP712 구현 문서는 도메인 구분자 처리와 최종 _hashTypedDataV4 단계를 제공합니다. 프로토콜별 구조체 인코딩은 각 프로토콜이 구현해야 해요. 검증된 라이브러리를 썼더라도 메시지 구조를 잘못 설계했다면 안전해지지 않습니다.
eth_signTypedData_v4와 지갑 화면
지갑은 흔히 eth_signTypedData_v4 RPC로 EIP-712 요청을 받습니다. MetaMask의 현재 서명 데이터 문서는 배열과 중첩 데이터를 지원하는 버전 4를 권장해요.
RPC 메서드는 앱과 지갑 사이에서 요청을 전달할 뿐, 요청이 정직한지는 판단하지 않습니다. 지갑이 이름과 값을 읽기 좋게 보여줘도 악성 앱이 혼동을 주는 필드 이름을 고르거나 과도한 권한을 요청할 수 있어요.
그래서 EIP-712는 클리어 사이닝과 블라인드 사이닝에 연결되지만 같은 개념은 아닙니다. 타입 필드는 더 나은 표시를 가능하게 해요. 실제 명확성에는 정확한 라벨과 포맷, 신뢰할 수 있는 맥락, 빠짐없는 해석도 필요합니다.
EIP-712 자체는 재생 공격을 막지 않아요
표준은 재생 공격 방지(Replay Protection)를 포함하지 않는다고 명시합니다. 도메인 분리는 일부 충돌을 줄이지만, 서명을 한 번만 쓰게 하거나 일정 시간 뒤 무효로 만드는 규칙은 앱이 설계해야 해요.
- 사용 시 소진되는 논스(Nonce)
- 마감 시각이나 만료 시간
- 도메인에 포함된 검증 컨트랙트와 체인 ID
- 메시지에 적힌 정확한 자산, 수량, 수신자, 행동, 계정
- 필요한 경우 취소나 철회 규칙
논스는 은행 수표의 고유 일련번호와 비슷해요. 검증자가 그 번호를 사용 완료로 기록하면 복사한 수표는 다시 처리되지 않아야 합니다. 앱이 논스를 추적하지 않거나 메시지에 맥락이 부족하면 같은 유효한 서명이 재사용될 수 있어요.
지갑에 “EIP-712”가 표시됐다는 이유만으로 안전하다고 생각하면 안 됩니다. 논스와 기한이 보이는지 확인하고, 실제 강제 방식은 프로토콜 공식 문서나 감사된 코드로 살펴보세요.
보안 위험과 실패 사례
읽기 쉬운 악성 요청
타입 데이터는 해로운 권한도 정확히 설명할 수 있어요. 토큰 퍼밋, 주문, 위임 요청이 형식상 완벽해도 의도보다 넓은 권한을 줄 수 있습니다. 제목이 아니라 실제 값을 읽으세요.
오해를 부르는 이름과 빠진 맥락
필드 이름은 앱이 정합니다. beneficiary라는 이름이 그 주소의 안전을 증명하지 않아요. 지갑이 중첩 필드를 생략하거나 주소를 지나치게 줄이거나 검증 컨트랙트를 식별하지 못한다면 거절하세요.
피싱과 침해된 프런트엔드
복제 사이트도 공격자 컨트랙트를 위한 진짜 서명을 요청할 수 있습니다. 브라우저 주소와 EIP-712 서명 도메인은 별도로 확인하고, 컨트랙트 주소는 공식 문서와 대조하세요.
서명 재사용과 넓은 권한
긴 기한, 무제한 수량, 재사용 가능한 논스, 모호한 행동 필드는 피해 범위를 키웁니다. 가스비가 0원인 요청도 릴레이어가 나중에 실행할 수 있어요. 토큰 권한은 ERC-2612 퍼밋과 Permit2와 비교해 보세요.
스마트 계정의 차이
외부 소유 계정(EOA)은 ECDSA 서명을 만들어요. 스마트 컨트랙트 계정은 같은 다이제스트를 ERC-1271과 프로그래밍 가능한 규칙으로 검증할 수 있습니다. 컨트랙트 지갑 정책은 바뀔 수도 있어요.
서명 전 일곱 가지 체크리스트
- 접속 경로: 검증한 URL이나 북마크로 들어왔나요?
- 대표 타입:
Permit,Order,Vote가 약속한 행동과 맞나요? - 도메인: 앱 이름, 체인 ID, 버전, 검증 컨트랙트가 자연스러운가요?
- 권한: 수신자, 지출 권한자, 운영자, 위임 대상이 무엇을 할 수 있나요?
- 가치: 토큰, 수량, 가격, 한도가 예상과 정확히 같나요?
- 수명: 논스와 기한이 있고 유효 기간이 합리적인가요?
- 명확성: 결과를 한 문장으로 설명할 수 있나요? 아니라면 거절하세요.
Caution
가스비가 없거나 EIP 번호가 보인다는 이유만으로 서명하지 마세요. 표준은 형식과 인터페이스를 정의할 뿐, 앱·컨트랙트·경제적 결과를 인증하지 않습니다.
자주 묻는 질문
EIP-712가 personal_sign보다 안전한가요?
구조화된 맥락과 도메인 분리를 제공하는 장점이 있어요. 하지만 안전성은 메시지 설계, 지갑 화면, 검증 로직, 사용자의 검토에 달려 있습니다. 악성 타입 요청은 여전히 악성이에요.
서명하면 트랜잭션이 전송되나요?
보통 서명 시점에는 전송되지 않아요. 다른 주체가 나중에 제출할 행동을 인가할 수 있으므로 중요한 자격 증명처럼 다뤄야 합니다.
EIP-712 서명을 철회할 수 있나요?
공통 철회 방법은 없습니다. 개별 프로토콜이 논스 무효화, 주문 취소, 승인 변경, 만료를 지원할 수 있어요. 공식 방식을 확인하세요.
같은 요청인데 지갑마다 표시가 다른 이유는 무엇인가요?
지갑마다 화면과 해석 방식이 다릅니다. 펌웨어, 확장 프로그램 버전, 하드웨어 화면 크기, 중첩 구조 지원도 영향을 줘요. 핵심 정보가 빠졌다면 추측하지 말고 멈추세요.
서명 도메인 이름은 웹사이트 주소와 같은가요?
반드시 같지는 않아요. EIP-712의 name은 앱이 제공하는 필드입니다. 브라우저 출처와 온체인 검증 컨트랙트는 각각 확인하세요.
핵심 정리
EIP-712는 구조화된 의도를 결정론적인 다이제스트로 바꿔 지갑이 표시하고 앱이 검증하게 합니다. 핵심은 타입 필드와 도메인 분리예요. 하지만 요청을 신뢰할 만하게 만들거나 재생 공격을 자동으로 막지는 않습니다.
서명 전 행동, 도메인, 권한, 가치, 논스, 기한을 확인하세요. 빠지거나 맞지 않는 정보가 있다면 거절하고, 권한은 좁게 유지하며, 공식 1차 자료와 대조하세요. 이 글은 투자 조언이 아닙니다. 크립토 서명은 전액 손실로 이어질 수 있으니 DYOR하고 잃어도 되는 금액만 사용하세요.
함께 읽으면 좋은 글

클리어 사이닝 vs 블라인드 사이닝: 지갑 서명창 읽는 법
클리어 사이닝은 지갑 요청을 읽을 수 있게 보여줘요. 블라인드 사이닝과의 차이, EIP-712·ERC-7730, 서명 전 점검법을 정리합니다.

Sign-In with Ethereum(SIWE): 지갑 로그인 원리와 확인법
Sign-In with Ethereum은 비밀번호 대신 ERC-4361 메시지로 로그인해요. 작동 원리, 필수 필드, 개인정보 한계와 안전 점검법을 알아봅니다.

ERC-1271 스마트 컨트랙트 서명: 지갑은 권한을 어떻게 검증할까?
ERC-1271은 스마트 컨트랙트 지갑이 프로그래밍된 규칙으로 서명을 검증하게 해요. isValidSignature의 작동 원리와 호환성·보안 위험을 정리합니다.
관련 주제 살펴보기

이더리움 트랜잭션 대기 중: 원인 진단·속도 높이기·취소 방법
이더리움 트랜잭션이 대기 중인 이유와 논스·가스비의 관계를 알아보고, 기다리기·속도 높이기·취소 중 안전한 대응을 선택해 보세요.

이더리움 글램스테르담 업그레이드: ePBS·BAL과 확정된 사실
글램스테르담은 2026년 4분기 예정이에요. 확정된 범위, 세폴리아 일정, ePBS, 블록 레벨 접근 리스트와 남은 변수를 설명합니다.