代币授权:你不断在赋予的权限

·阅读 8 分钟·作者:SSP Editorial Team
一叠代币授权权限被作为钥匙交给智能合约的插画

代币授权:你不断在赋予的权限

每当你与 DeFi 应用交互——在 DEX 上换币、把币存入借贷市场、跨链桥接 ERC-20——你几乎肯定都授予了一次代币授权。大多数用户在几秒内就签下这些交易,然后把它们忘得一干二净。然而那一笔 approve 交易,是你在 Ethereum 上做过的最具后果的事情之一:它把一份长期许可交给了一个智能合约,让它可以移动你的代币,往往再也不需要你额外确认。本文讲清楚什么是代币授权、dApp 为什么要它、无限 allowance 模式的风险,以及当你通过 SSP 签名授权时,这一切究竟意味着什么。

授权为什么存在

ERC-20 代币不像 ETH 那样"存"在你的钱包"里面"。一个 ERC-20 代币合约其实是一本账:从地址到余额的映射。当你持有 1,000 USDC,链上真正存在的是 USDC 合约中的一行,写着你的地址拥有 1,000 个单位。

因为余额住在代币合约里面,所以只有这个合约能移动它。当你把 USDC 转给朋友时,你的钱包是直接调用代币的 transfer 函数。

但 DEX 不同:另一个合约(router)必须从你的地址里把 USDC 拿出来去执行 swap。router 无法直接伸进代币合约里抓走你的余额。ERC-20 用一个两步式的委托模式解决这件事:

  1. 在代币合约上调用 approve(spender, amount),这就设置了一个 allowance:一条记录,说明 spender 有权转移你最多 amount 数量的代币。
  2. spender 之后在代币合约上调用 transferFrom(yourAddress, destination, amount)。代币合约检查 allowance、将其减去、然后转移代币。

授权就是那把钥匙。没有它,router 根本无法触及你的 USDC。

你实际上授予了什么

approve(spender, amount) 直白地读一遍。你是在告诉 ERC-20 合约:"这个地址可以提取我最多这么多代币,任何时间、任何次数的交易,直到我自己改变它。"

由此可以得出几点:

  • 这是长期许可,不是一次性动作。 一旦授予,只要 allowance 没花完也没被撤销,spender 无需你再次签名就能拉走代币。
  • 按代币区分。 给 DEX router 授权 USDC,并不允许它动你的 DAI;DAI 需要另一笔授权。
  • 按 spender 区分。 不同的合约——哪怕来自同一个 dApp——也各自拥有自己的 allowance。
  • 没有过期时间。 ERC-20 没有内置截止日期。一个 2023 年设定的 allowance,到了 2026 年只要没花光也没撤销,就仍然有效。

你可以在区块浏览器(例如 etherscan)上调用代币合约的 allowance(owner, spender) 视图函数,来查看任何 allowance。

无限 allowance 模式

如果授权是按金额来的,为什么几乎每个 DEX 都让你授权一个巨大的数字——通常是 2^256 - 1,显示为"无限"或 MaxUint256——而不是你正要交易的那个数额?

答案是 UX 和 gas。如果 DEX 每次 swap 都要求一个等于交易额的全新 allowance,你每次都要付一笔授权交易的 gas,并且为一个看起来像单次的操作确认两次交易。让 dApp 一次性问你要一个无限 allowance,之后你就能用每笔交易一次确认自由 swap。

这真的方便。也真的更冒险。无限 allowance 意味着 spender 合约获准在任何时刻清空你当前的全部该代币余额——以及你将来持有的任何余额——而你无须再签任何东西。

对于一个广为人知、经过审计、不可升级的合约,实际风险通常很低。对于一个刚部署的 dApp、可升级的代理合约或你从未听说过的合约,无限 allowance 就是一个远比你打算做的那笔交易要大得多的攻击面。

真正的风险:通向你代币的一把常驻钥匙

授权的危险不在授权交易本身,而在之后发生的事。考虑几个场景:

  • spender 合约有漏洞。攻击者利用其 transferFrom 逻辑,所有持有非零 allowance 的钱包都被掏空。
  • spender 合约可以升级。掌握升级权限的人推送了一份新逻辑,能把任何有活跃 allowance 的人的代币拉走。
  • 你授权了一个恶意克隆。一个钓鱼站点模仿了真实 dApp 的 URL,你授权的合约从一开始就由攻击者控制。它先等上几天再下手,把所有交互过的人一并掏空。
  • spender 的签名密钥被攻陷。官方合约本身没问题;是运维方的钱包被攻击了,allowance 由入侵者来执行。

每一种情况下,被掏空时你都没签任何东西。攻击者所需的全部授权,就是你几周前甚至几个月前授予的那一份。"只授权你需要的,撤销你不再使用的"不是偏执,而和你不会把家门备用钥匙留给每一个雇过的施工队工人是同一个道理。

授权是怎样悄无声息地堆积起来的

一个在 DeFi 里活跃了一两年的钱包,往往已经累积了几十个授权:每个用过的 DEX、每个曾经路由过的聚合器、每个借贷市场存款、每个 NFT 市场、每个跨链桥。用户几乎从不回去撤销。结果就是一条长长的"常驻许可"的尾巴,其中大部分是无限的,许多还给了用户早已不再使用的合约。

这就是那道沉默的攻击面。它不会在任何一笔单独的交易里显形;它是正常使用所留下的累积残渣。审计并修剪这份清单,是自我托管中最有效的安全习惯之一——本系列的下一篇会逐步介绍方法,参见 从 SSP 撤销代币授权

一种更新的模式:EIP-2612 permit

ERC-20 比绝大多数现代 DeFi 都要古老,approve-然后-swap 这种两笔交易的舞步,长期以来都被认为不够顺滑。EIP-2612 为支持它的代币引入了另一种方式:用户不必上链发送一笔 approve,而是签署一条链下消息(一个 permit),授权一个特定的 spender、金额和截止时间。dApp 把这个签名和 swap 一起,在一笔交易中提交。

permit 更省 gas,作用域更受限(携带明确的金额和到期时间),也更不容易留下"挂着的"授权,因为截止时间会强制它过期。并不是所有 ERC-20 都支持——USDC 和 DAI 支持,许多更老的代币不支持——但在它可用之处,一般比长期挂着的 approve allowance 更安全。话虽如此,permit 签名本身也可能被钓鱼:一个让你"登录"的恶意站点,可能会在签名底下偷偷塞一个 permit。请看清楚自己在签什么。

这一切在 SSP 中意味着什么

SSP 是一个自我托管的 2-of-2 多签钱包:每一笔链上交易都由 SSP 浏览器扩展和 SSP Key 移动端共同签名。在 Ethereum 以及 SSP 支持的其它 EVM 网络(Polygon、Base、BNB Smart Chain、Avalanche)上,这通过一个带有 Schnorr 聚合签名的 ERC-4337 智能账户实现——但在应用层面,一次授权看起来和其它任何交易并无两样。

有几点值得记住:

  • 授权是一笔需要你的 2-of-2 共同签名的交易。 dApp 发起 approve 时,SSP 会像呈现普通 tx 那样把它呈现给你。确认前,你会在两台设备上同时看到 spender 地址和申请金额。
  • 一旦授权完成,spender 不再需要 SSP 就能行动。 多签保护的是授权那一刻,而不是之后的常驻许可。如果你给一个恶意合约授予了无限 allowance,多签救不了你之后被掏空的命。
  • 盯紧 spender 地址。 dApp 偶尔会升级 router;如果授权界面上的 spender 与你期望的合约不符,请停下并核实。
  • WalletConnect 发起的授权看起来完全一样。 不管 dApp 在自己的页面里弹窗,还是通过 WalletConnect 发起请求,流程和风险都是一致的。

值得养成的习惯

几条具体做法能让授权面保持在可控范围:

  • 优先选择尽量小的可用 allowance。 当 dApp 提供"精确金额"与"无限"两种选择时,对于你不会经常使用的合约,精确金额是更安全的默认值。
  • 把无限授权当成承诺。 只为你信任并经常使用的少数合约保留它(比如你主要用的 DEX router、主要用的借贷市场)。其余的,统统限定额度。
  • 定期审计。 每个季度一次,把每条链上的活跃授权列一遍,撤销所有不再使用的。revoke.cash 之类的工具能让这件事变成例行公事。
  • 对陌生 dApp 保持警惕。 一个没有审计记录的新协议,开口就要无限 allowance,是 DeFi 中最危险的组合之一。
  • 保护好那些用于发出授权的密钥。 SSP 的多签显著抬高了门槛,但常规的安全卫生习惯依旧适用——参见 助记词最佳实践

值得带走的心智模型

一次代币授权不是一次点击,而是一把钥匙。每一把都会一直插在锁里,直到你把它取下来;每一把都赋予持有者移动你尚未赚到的代币的能力。审慎使用时,allowance 是让整个 DeFi 得以运转的水管。被当作随手就丢的点击时,它们就是你早已忘记自己曾经承担过的、慢慢累积起来的风险。

理解你正在赋予的许可,在 dApp 允许时优先选择限定范围的授权,并按一定的节奏修剪你的常驻授权。想深入了解协议细节,规范级参考可看 ethereum.org 上的 ERC-20 标准文档。如果你刚开始在 Ethereum 上使用 SSP,我们的 SSP 中的 Ethereum 指南介绍了基础操作。

分享本文

相关文章