题目
用户在钱包里看到一串十六进制数据,DApp 却告诉他“只是登录”;另一个页面使用 EIP-712,钱包能显示字段名,但签名仍可能授权转走资产。什么是盲签?EIP-712 改善了什么,为什么它本身不等于安全?前端应怎样降低误签风险?
考察目标
- 是否理解签名对象是确定字节及其语义,而不是 DApp 按钮上的自然语言。
- 是否能说明 EIP-712 的结构化数据和 domain separation 价值。
- 是否知道钱包缺少协议语义、类型命名误导或用户不核对时,结构化签名仍可能近似盲签。
考察原始签名数据、结构化展示、domain 校验、钱包解析能力以及签名授权的产品防线。
用户在钱包里看到一串十六进制数据,DApp 却告诉他“只是登录”;另一个页面使用 EIP-712,钱包能显示字段名,但签名仍可能授权转走资产。什么是盲签?EIP-712 改善了什么,为什么它本身不等于安全?前端应怎样降低误签风险?
盲签是用户无法从钱包确认界面理解自己实际签署的字节或授权后果,只能相信 DApp 描述。EIP-712 把消息定义成带类型的结构,并用 domain 中的 name、version、chainId、verifyingContract 等信息隔离签名场景,让钱包有机会展示字段并检查上下文;但字段名和类型仍由请求方提供,钱包未必理解 Permit、订单或自定义协议的真实效果,也不能阻止恶意 DApp 构造“看起来正常”的授权。前端要在发起签名前展示用途、目标合约、链、金额、spender、有效期与 nonce,使用最小权限和短有效期,并让这些文案与实际 typed data 一一对应;钱包无法清晰展示时应升级警告或停止高风险操作。
钱包签名不是对按钮文字或网页截图背书,而是对经过编码和哈希的消息产生密码学签名。personal_sign 通常只能展示字符串或原始字节,复杂授权被编码后用户很难理解;如果钱包只显示 hash 或 hex,用户无法独立确认接收方、额度和期限,这就是典型盲签。
EIP-712 定义类型、消息和 domain separator。合理的 domain 可以绑定:
钱包因此能把 spender、value、deadline 等字段结构化展示,也能发现活动链与 domain chainId 不一致。domain separation 还减少相同结构在不同协议、合约或版本间被重放的风险。
EIP-712 只标准化编码,不自动解释业务后果:
value 的单位、token 地址和 spender 可能没有友好解释。清晰签名格式与协议注册表可以帮助钱包展示更接近人类语义的信息,但最终仍需钱包实现、协议描述和用户确认共同配合。
签名前的确认页必须从即将发送的真实 typed data 派生,而不是维护另一套可能漂移的文案。高风险签名至少展示完整目标地址、链、资产、额度、spender、有效期和用途;无限额度、任意 operator、长期订单或未知合约应使用阻断式提示。
签名完成后也不应只显示“成功”,而要记录它授权了什么、何时到期、怎样撤销或使 nonce 失效。前端不得把签名描述为“免费所以安全”。签名不上链、不花用户 Gas,但后续可能被任何持有者提交并产生资产影响。
const typedData = buildPermitTypedData({
chainId,
token,
owner: account,
spender,
value,
nonce,
deadline,
});
renderSigningSummary({
chainId: typedData.domain.chainId,
verifyingContract: typedData.domain.verifyingContract,
spender: typedData.message.spender,
value: typedData.message.value,
deadline: typedData.message.deadline,
});
const signature = await walletClient.signTypedData({
account,
...typedData,
});
关键不是 API 调用,而是确认页和钱包收到的数据来自同一个对象,避免展示内容与真实签名参数不一致。
发现这道题有问题? 反馈此题