我以为不花 gas 就没事
下面这则按真实手法合成,Henry 是化名。他在加拿大玩 DeFi 三年,自认见过场面。2025 年 3 月 15 日他在 Google 搜「Curve」,第一条是 Google Ads:「Curve Finance · 8.7% APY on USDC」,链接 curve-finance[.]live。他没看域名直接点进去 —— 页面 1:1 复刻 Curve 主站。
点 Deposit USDC,钱包弹窗。窗口标题是「Signature request」而不是「Transaction」—— 这一点让他放松了警惕。他下意识里有一条规则:「不要乱签 transaction」,但 signature 在他脑子里是「无 gas、无风险」的同义词。他按了 Sign。
12 秒后我的 23 万 USDC 没了
12 秒后,他持有的 23 万 USDC 通过一笔 permit + transferFrom 组合调用从他地址转到攻击者地址。整个过程他的钱包没有发起任何 transaction,是攻击者用他的签名调用的。区块浏览器上他的钱包看起来「什么都没做」,只是 USDC 余额变成零。
我现在才搞懂 Permit 的本质
EIP-2612 Permit 是 ERC-20 的离链授权扩展。设计目的是替代昂贵的 approve 交易、节省 gas。结构上你签的是一段 owner / spender / value / deadline 数据,等同于「允许某地址在某时间前转走我的某 token,最多 value 这么多」——钓鱼页通常把 value 填成最大值。攻击者拿到签名后调用 permit + transferFrom 一气呵成,交易由攻击者发起,受害者自己的钱包里从头到尾没有发出过任何一笔授权交易。
致命点:Permit 不出现在 revoke.cash 里 —— 那只显示链上 approval。也不出现在区块浏览器的 Token Approval Checker。它是离链的,唯一痕迹是攻击者最终调用 transferFrom 那一刻。这意味着你签完一周、一个月后才被扫都有可能,那时你早忘了自己签过什么。
我应该在哪一步看出来
第一处:Google Ads 搜 DEX 名字。搜索广告位经常被钓鱼站买下。直接在书签栏存 app.uniswap.org 这类官方域名(Curve 就从 Curve 官方公布的域名进入)比搜索引擎稳得多。
第二处:弹窗显示「Signature request」结构化数据,里头有 owner / spender / value / deadline 字段。这就是 Permit 数据格式。看到这种结构 + spender 是不认识的合约 + value 是 unlimited,直接 reject。
第三处:deadline 字段。正常 dApp 的签名截止时间多在分钟到小时级,攻击者用的 Permit deadline 一般设几个月甚至几年。看到几个月、几年后的 deadline 要高度警惕。
5 个 Permit 钓鱼硬信号
- Google Ads / X 广告里的 DEX 链接 —— 真官方常买不过钓鱼站
- Connect wallet 后弹的是 Signature 而非 Transaction —— Permit 钓鱼第一特征
- 签名里有 owner / spender / value / deadline 字段 —— 这就是 Permit 数据
- value 是超大数字(unlimited / 2^256-1)—— 攻击者要的就是无限授权
- deadline 远到几个月以上 —— 高度警惕
我已经签了之后做的事
签出的 Permit 很难作废(要抢先用掉同一个 nonce),最快是把这种 token 全转到一个新地址。按《私钥泄露应急 · 五步抢救流程》第三步执行 —— Henry 自己花了 11 分钟把剩余 USDC 转走,但 23 万那笔已经被攻击者抢先扫走。
之后这个旧地址做「冷冻处理」:永远不再接收同种 token、不在任何 dApp 中使用、最好直接弃用。攻击者拿到的 Permit deadline 可能是几个月甚至几年,长期看任何到账都会被 sweep。
「不签 transaction」是 2020 年的规则。2025 年大量钓鱼改走签名通道。下一条规则应该是:「看不懂的签名一律拒绝」。宁可错过一次空投也不要瞎签 —— 装个 Pocket Universe / Rabby 把结构化数据翻译成中文是低成本高回报的护栏。