궁금한 주제를 찾아보세요

비트코인, 스테이블코인, 온체인 데이터처럼 주제로 검색하세요.

다시 읽을 이야기

저장한 글은 이 브라우저에만 보관됩니다.

해설기술·생태계

EIP-712 타입 데이터 서명은 무엇을 사람이 읽게 만드는가

타입·필드·domain separator를 구조화해 지갑 표시를 개선하는 EIP-712와 여전히 남는 phishing·nonce·UI 생략 위험을 설명합니다.

난이도 중급주제 카테고리와 개념 밀도 기준검토 정보AI 보조 초안 · 출처 목록 제공 · 주장별 대조 진행 중
사람이 읽는 구조화된 정보 항목을 서명 문서에 묶고 계약별 사용 경로를 나누는 EIP-712 그림
주제의 이해를 돕기 위해 imagegen으로 제작한 AI 생성 개념 일러스트
먼저 읽는 핵심

Typed data는 이름 붙은 구조와 domain을 digest에 묶습니다.
배열·중첩 struct는 canonical type ordering과 hash 규칙을 따라야 합니다.
읽기 좋은 UI는 악성 권한과 replay를 자동 차단하지 않습니다.

EIP-712는 사람이 의미를 구분할 수 있는 struct type과 fields를 정규 encoding하고, name·version·chainId·verifyingContract 등을 담는 domain separator와 결합해 0x1901 || domainSeparator || hashStruct(message)를 서명 digest로 만듭니다. 이는 opaque hex보다 지갑이 spender·amount·deadline 같은 값을 구조적으로 표시할 기반을 주지만 UI가 모든 field를 정확히 보여 준다는 보장은 아닙니다. Contract는 type hash와 domain, nonce·deadline을 정확히 검증하고 사용자는 chain·contract·행위·무제한 금액을 확인해야 합니다.

두 개의 hash를 최종 digest에 결합합니다

EIP-712 message hash는 hashStruct(s)=keccak256(typeHash || encodeData(s))입니다. typeHash는 canonical encodeType 문자열의 hash이고 custom struct가 다른 struct를 참조하면 dependencies를 이름순으로 이어 붙입니다. 구현마다 type 문자열 순서가 다르면 같은 화면 데이터도 다른 digest가 됩니다.

Domain도 EIP712Domain struct의 hashStruct이며 일반 fields에는 name, version, chainId, verifyingContract와 salt가 있습니다. 최종 prefix 0x19 0x01은 EIP-191 version 0x01 영역을 사용합니다. 모든 domain field가 필수는 아니지만 생략한 경계의 replay 가능성을 application이 책임져야 합니다.

Typed data는 사용자가 읽을 재료와 계약이 검증할 구조를 맞춰 주지만, 그 내용이 사용자에게 유리한 승인인지 판단해 주지는 않습니다.

JOBCOIN 해설

VISUAL GUIDE키 보관과 거래 서명
보호된 개인키로 거래에 서명하고 노드가 서명을 검증하는 개념도
그림과 함께 짚어볼 본문 내용

그림은 이 주제의 공통 개념을 단순화한 설명입니다. 아래 항목에서 이 글의 구체적인 조건과 예외를 함께 읽어보세요.

  1. 두 개의 hash를 최종 digest에 결합합니다

    EIP-712 message hash는 hashStruct(s)=keccak256(typeHash || encodeData(s))입니다.

  2. 정적 값과 동적 값을 다르게 encoding합니다

    uint·address·bytes32 같은 atomic 값은 32바이트 ABI 형태로 encodeData에 놓입니다.

  3. Permit 화면을 계약 digest와 맞춥니다

    Token permit에서 지갑은 owner, spender, value, nonce, deadline을 보여 줄 수 있습니다.

AI로 제작한 개념도 · 실제 가격·거래 내역·통계가 아닙니다.

정적 값과 동적 값을 다르게 encoding합니다

uint·address·bytes32 같은 atomic 값은 32바이트 ABI 형태로 encodeData에 놓입니다. string과 bytes는 내용의 keccak256 hash를 사용하고 struct field는 그 struct의 hashStruct를 넣습니다. Array도 각 원소 encoding을 이어 hash하므로 일반 abi.encodePacked를 임의로 대체하면 안 됩니다.

JSON-RPC 요청 객체의 field 순서가 digest 순서를 정하는 것이 아닙니다. types에 선언된 member order와 canonical dependency ordering이 기준입니다. 숫자를 JavaScript 부동소수점으로 다뤄 큰 uint를 바꾸거나 address checksum 표시와 실제 20바이트를 다르게 처리하지 않게 test vector를 사용합니다.

EIP-712 구성 요소와 검증 질문
요소 역할 확인할 위험
types 필드 이름·형식 선언 숨은 권한 필드
primaryType 서명할 root struct 다른 type 선택
domain name/version 앱·버전 구분 동일 이름 사칭
chainId/contract 배포 경계 cross-chain replay
message nonce/deadline 1회·시간 제한 재사용·장기 승인

Permit 화면을 계약 digest와 맞춥니다

Token permit에서 지갑은 owner, spender, value, nonce, deadline을 보여 줄 수 있습니다. Value가 uint 최대값이면 사실상 무제한 승인이고 spender가 router처럼 보이더라도 verifyingContract는 token 계약입니다. 사용자는 token·spender 두 주소와 chain을 함께 확인해야 합니다.

Contract는 현재 nonces[owner]를 message와 대조하고 성공 시 증가시킵니다. Domain separator를 deployment chainId에 고정 캐시하면 chain split 뒤 replay 조건이 생길 수 있어 구현이 chainId 변경을 어떻게 처리하는지 확인합니다. Proxy에서는 verifyingContract가 implementation이 아니라 호출·상태 주소인 proxy인지 검증합니다.

  • Primary type과 모든 dependency type 문자열을 출력합니다.
  • Domain name·version·chainId·contract를 표시합니다.
  • 주소·uint·dynamic fields의 encoding을 test vector로 비교합니다.
  • Nonce·deadline·권한 금액을 사용자 화면에 생략하지 않습니다.
  • Contract와 wallet이 만든 digest를 byte 단위로 대조합니다.

구조화됐다는 사실이 안전한 승인을 뜻하지 않습니다

악성 dApp도 EIP-712로 무제한 token allowance, NFT 전체 운영자 권한이나 marketplace order를 명확한 형식으로 요청할 수 있습니다. Wallet이 primary type 제목만 크게 보여 주고 중요한 nested field를 접으면 사용자는 위험을 놓칩니다. Human-readable은 정보 표현 가능성이지 정책 보증이 아닙니다.

Sign-in 메시지와 자산 이전 권한을 같은 시각적 등급으로 보여 주면 phishing이 쉬워집니다. Wallet은 알려진 schema 의미, spender·operator 권한, 만료와 simulation을 추가로 설명할 수 있지만 contract upgrade와 이후 호출까지 완전히 예측할 수는 없습니다.

버전·재생 방지와 실패 증거를 함께 남깁니다

Backend가 typed data를 만들고 frontend가 서명할 때 JSON 원본만 보관하면 serializer 차이로 재현이 어려울 수 있습니다. Canonical type strings, domainSeparator, structHash, final digest와 recovered signer를 함께 기록하되 raw private data는 최소화합니다.

검증 test에는 field 순서 변경, type 이름 대소문자, chainId·contract 변경, 만료, 이미 사용한 nonce, high-s signature를 포함합니다. Wallet preview screenshot만으로 계약이 같은 digest를 검증했다고 주장하지 않고 on-chain call result와 nonce 변화를 확인합니다.

자주 묻는 질문

EIP-712 서명이면 피싱이 불가능한가요?

아닙니다. 내용을 구조적으로 표시할 수 있을 뿐 악성 권한이나 UI의 필드 생략, 사칭을 자동 차단하지 않습니다.

JSON field 순서를 바꾸면 서명이 달라지나요?

Digest는 선언된 struct member order와 canonical type 규칙을 따릅니다. 임의 JSON property order에 의존하면 안 됩니다.

Domain에 chainId와 contract를 넣으면 nonce는 불필요한가요?

아닙니다. Domain은 배포 경계를, nonce는 같은 경계 안에서 반복 실행을 제한하는 별도 장치입니다.

더 깊이 읽기

본문에서 다룬 개념과 확인 절차를 다음 글에서 이어서 살펴보세요.

참고한 원문 자료

자료 확인 기준일 2026.09.27
  1. EIP-712: Typed structured data hashing and signingeips.ethereum.org
  2. ERC-191: Signed Data Standardeips.ethereum.org
자료 대조 기록과 확인 범위
출처 수집
원문 링크 2개 제공
핵심 주장 대조
완료 근거가 아직 기록되지 않았습니다.
분야 전문가 검수
별도 완료 기록이 없습니다.

원문 링크와 자료 확인일은 글 전체의 주장 대조나 전문가 검수 완료를 뜻하지 않습니다. 별도 확인이 필요한 절차는 원문의 적용 대상과 최신 안내를 함께 확인해 주세요.

AI 활용 안내

이 글은 초안 구성과 자료 정리에 AI를 활용했습니다. 글에 표시된 출처와 기준일을 함께 확인해 주세요. 별도 검토 정보가 없다면 전문가 검수를 뜻하지 않습니다.

이해를 위한 정보 콘텐츠

이 글은 특정 자산의 매수·매도 또는 수익을 권유하지 않습니다. 자료의 발표 시점과 이후 변경 사항을 함께 확인해 주세요.

편집 원칙 보기 →이 기사 정정 제보 →