Ir para o conteúdo

Assinaturas tipadas EIP-712: domínios, digests e verificação segura

A EIP-712 torna mensagens estruturadas do Ethereum determinísticas e legíveis, mas assinar com segurança ainda exige verificar domínio, tipo, valor, nonce, prazo, execução e política do signatário.

Atualizado

Somente para fins educacionais; não constitui recomendação nem aconselhamento de investimento. Investir pode causar perdas.

Resposta direta

A EIP-712 padroniza como aplicativos Ethereum descrevem, calculam o hash e solicitam assinaturas de dados estruturados tipados. Uma solicitação contém types, primaryType, domain e message; seu digest é keccak256("\x19\x01" || domainSeparator || hashStruct(message)). Isso torna a codificação determinística e permite que uma carteira compatível exiba os campos com mais clareza que um hash opaco.

Ela não torna a mensagem verdadeira, inofensiva, revogável ou protegida contra replay. O aplicativo precisa vincular a autoridade à rede e ao verificador corretos, definir cada campo sem ambiguidade, impor nonces e limites de tempo, validar o signatário certo e restringir a execução. Uma assinatura válida comprova a aprovação de um digest exato segundo uma regra de verificação; não comprova identidade, intenção informada nem a segurança do site ou contrato.

Assinaturas tipadas EIP-712
0 / 5
0 itens revisados; 5 itens ainda não resolvidos

A conclusão desta revisão não prova que um ativo, transação ou sistema seja seguro.

Como funciona

1. Identifique a ação e o caminho de verificação

Determine se a solicitação autoriza login, ordem, voto, allowance de token, transferência, chamada retransmitida ou outra ação. Localize o código que reconstrói o digest e consome a assinatura. Para uma conta externamente controlada, a verificação costuma recuperar um endereço de uma assinatura ECDSA; para uma conta de contrato, pode ser necessário chamar ERC-1271 isValidSignature(hash, signature) e conferir o valor de sucesso 0x1626ba7e.

2. Fixe o domínio

Examine o tipo EIP712Domain exato e seus valores. Os campos padrão são name, version, chainId, verifyingContract e salt, mas apenas os presentes entram no hash. Confirme de forma independente a rede ativa, o código implantado e o verificador pretendido; nome, símbolo, rótulo de proxy ou endereço com checksum familiar não bastam. ERC-5267 eip712Domain() pode expor o domínio, mas o suporte é opcional e proxies ou upgrades ainda exigem análise.

3. Reconstrua o grafo de tipos

Comece em primaryType, preserve a ordem dos membros e reúna recursivamente as structs referenciadas. encodeType acrescenta suas definições ordenadas pelo nome do tipo. A EIP-712 admite inteiros de largura fixa, address, bool, de bytes1 a bytes32, bytes e string dinâmicos, arrays e structs; o padrão não define os aliases uint e int, tipos de ponto fixo nem valores cíclicos.

4. Decodifique cada valor e unidade

Relacione cada valor ao tipo declarado e ao significado no aplicativo. Confira endereços completos, unidades inteiras brutas, sinais, ordem de arrays, destinatários, spenders, ativos, quantias, taxas, limites, destinos, hashes de calldata e strings legíveis. bytes e string dinâmicos aparecem em encodeData como o hash Keccak-256 do conteúdo; arrays usam o hash das codificações concatenadas e structs aninhadas usam o próprio hashStruct.

5. Recalcule o digest de forma independente

Calcule typeHash = keccak256(encodeType(primaryType)) e depois hashStruct(message) = keccak256(typeHash || encodeData(message)). Calcule o separador de domínio da mesma forma e combine-o com os bytes de versão ERC-191 0x19 0x01. Compare frontend, biblioteca de assinatura, contrato verificador e implementação independente; JSONs visualmente iguais não comprovam codificação tipada idêntica.

6. Audite replay, tempo e controles de execução

A EIP-712 não inclui proteção contra replay. Confirme que o verificador confere o signatário pretendido, consome ou invalida o nonce correto, impõe deadline ou janelas de validade, vincula todos os parâmetros críticos e mantém o resultado pretendido se um relayer ou frontrunner enviar primeiro. A separação de domínio só impede colisões entre domínios realmente codificados; campos ausentes ou errados podem deixar caminhos de reutilização entre contratos ou redes.

7. Assine com escopo mínimo e reconcilie o resultado

Rejeite campos ocultos, tipos inexplicados, valores ilimitados, prazos distantes, contratos desconhecidos, IDs de rede divergentes, telas de blind signing ou contexto de execução incompleto. Preserve o JSON tipado exato e o digest, use uma conta de finalidade limitada quando possível e confira transação, recibo, eventos, saldos, allowances, nonces, estado da ordem e finalidade. Desconectar o site não revoga uma assinatura utilizável nem uma autoridade já criada.

Exemplos calculados

Exemplo 1: Construção do tipo e do digest

Para Order(address maker,address token,uint256 amount,uint256 nonce,uint256 deadline), typeHash é o hash Keccak-256 dessa string exata, inclusive a ordem dos campos. O hash da mensagem é keccak256(typeHash || maker || token || amount || nonce || deadline) e cada membro ocupa 32 bytes. O digest final acrescenta 0x1901, o separador de domínio e o hash da mensagem; alterar amount de 250000000 para 250000001 muda o digest e invalida a assinatura anterior.

Exemplo 2: Unidades e prazo

Uma quantia de 250 USDC com seis casas decimais é codificada como 250000000, não 250. Se o timestamp atual for 1727000000 e o prazo 1727000900, a janela será 900 seconds = 15 minutes. A exibição decimal da carteira e o relógio local servem apenas de apoio; o verificador usa o inteiro bruto e a regra de tempo on-chain escolhida.

Exemplo 3: Controle de replay

Uma ordem leva nonce 41 e preenchimento máximo de 5 ETH. Depois que o verificador marca o nonce 41 como consumido, uma segunda apresentação deve falhar mesmo que a assinatura continue criptograficamente válida. Se o contrato não consumir o nonce nem tornar a execução idempotente, a mesma assinatura pode autorizar mais 5 ETH; o separador de domínio sozinho não impede esse replay.

Exemplo 4: Validade da carteira de contrato

Uma carteira de contrato 2-de-3 aprova um digest com os signatários A, B e C configurados. As assinaturas de A e B podem fazer o ERC-1271 retornar 0x1626ba7e hoje. Se um upgrade substituir B por D, os mesmos bytes podem se tornar inválidos: a validade ERC-1271 pode depender do estado, política, tempo e chamadas externas atuais, e recuperar um endereço não decide a validade de uma conta de contrato.

Riscos

  • chainId errado ou ausente
  • verifyingContract falsificado ou inesperado
  • name ou version de domínio enganoso
  • Implementação proxy ou domínio alterado após upgrade
  • primaryType errado ou tipo sombra com rótulo semelhante
  • Ordem de membros, dependências ou codificador incompatível
  • Endereço truncado, substituído ou rotulado de modo enganoso
  • Erro de casas decimais ou de inteiro com sinal versus sem sinal
  • Item de array, struct aninhada ou payload bytes oculto
  • Valor ilimitado, escopo amplo ou destinatário controlado pelo atacante
  • Nonce ausente, antigo, compartilhado ou consumido incorretamente
  • Prazo ausente, distante, com overflow ou interpretação ambígua
  • Replay entre redes, contratos, contas ou ações
  • Retenção, censura, front-running ou redirecionamento pelo relayer
  • Maleabilidade da assinatura ou recuperação ECDSA permissiva
  • Mudança de signatário, módulo, limite, estado ou código ERC-1271
  • Falha de renderização, blind signing ou tipo não suportado na carteira
  • JSON do frontend diferente do digest do verificador
  • Revogação ou cancelamento que perde uma disputa de ordenação
  • Confundir o resultado do prompt com recibo, mudança de estado ou finalidade

Equívocos comuns

Mito 1: Assinaturas EIP-712 são transações

São mensagens assinadas off-chain. Um relayer ou outro participante pode enviá-las depois a um contrato, e a transação resultante pode gastar Gas e mudar estado sem ser enviada pelo signatário.

Mito 2: Uma exibição estruturada torna a solicitação segura

Campos tipados melhoram a inspeção, mas esquemas, valores, contratos, rótulos, aninhamentos ocultos ou renderização incompleta ainda podem enganar.

Mito 3: O separador de domínio impede todo replay

Ele separa somente o domínio codificado. Replay no mesmo domínio ainda exige nonce, prazo, cancelamento, contabilidade de preenchimento ou idempotência; campos omitidos não criam limites.

Mito 4: Recuperar o endereço esperado comprova autorização

A recuperação comprova uma assinatura EOA sobre o digest, não a semântica do aplicativo. Contas de contrato exigem sua política ERC-1271, não recuperação comum.

Mito 5: Fechar a página ou desconectar a carteira cancela a assinatura

Uma assinatura copiada pode ser usada até que nonce, prazo, cancelamento, estado ou política do verificador a invalide. Confira o estado on-chain relevante, não a sessão.

Tópicos relacionados

Fontes

Navegação

Pesquisar na wiki...