钱包弹窗跳出来的时候,你面对的不是一个问题,而是四个不同性质的动作。
它们长得都像「确认一下」,但交出去的东西完全不一样:有的只是你的地址,有的是一个不上链的签名,有的是让整笔交易上链的授权,还有的是直接允许别人动你的余额。
本文把这四件事拆开讲。只讲它们分别是什么、区别在哪,不涉及被授权之后怎么撤销。
一、先分成四件事
要区分它们,先记住一句话:交易是来自账户的、经过密码学签名的指令。 所有动作都围绕这句话展开。
| 动作 | 你交出了什么 | 会不会上链 |
|---|---|---|
| 连接钱包 | 你的地址 | 不会 |
| 消息签名 | 一段证明「这个地址是你的」的签名 | 不会 |
| 交易签名 | 一笔已签名的、待广播的交易 | 签名本身不会,广播后才会上链 |
| 代币授权 | 一个允许某地址提取你代币的额度 | 会,它本身就是一笔交易 |
下面逐个展开。
二、连接钱包:它交出的是地址,不是权限
连接钱包是这四件事里最容易理解、也最容易被过度警惕的一件事。
以太坊的接口规范里,连接这个动作对应的调用是 eth_requestAccounts。规范原文对它的描述是:
Calling this method may trigger a user interface that allows the user to approve or reject account access for a given dapp. This method returns a Promise that is resolved with an Array of accounts.
也就是说:它会弹一个界面让你同意或拒绝,然后把一个地址数组返回给这个网站。
关于为什么要这样设计,提供方接口规范里有一句说明:为了保护用户隐私,建议默认不暴露任何账户,而是通过 eth_requestAccounts 这类方法显式请求账户访问权限。
所以「连接」的准确含义是:这个网站从此知道你的地址是什么、能看到你持有什么。它不产生任何链上动作,不转移任何资产,也不给你任何额外的义务。
但这不是「所以没关系」。 连接本身就是一个隐私边界——你把这个地址的全部持仓暴露给了一个网站。用主钱包连一个没听说过的站点,暴露的信息量和风险,和你只是「点了一下」的感觉并不匹配。这也是为什么很多人会用一个专门的小额钱包去试新东西。
三、签名是怎么产生的:私钥签,任何人验
要理解后面三件事,先要理解签名这件事本身。官方文档里有一段说明写得最完整:
账户由一对密码学密钥组成:公钥和私钥。它们有助于证明交易确实是由发送者签名的,并防止伪造。您的私钥用于对交易进行签名,因此它赋予您对与账户相关联的资金的保管权。……可以从您的私钥派生出新的公钥,但不能从公钥派生出私钥。……您需要私钥来对消息和交易进行签名,从而输出签名。然后,其他人可以使用该签名来派生您的公钥,从而证明消息的作者。
把这段话拆成三个要点:
- 私钥是签名的那一支。 没有它签不了名,而签名能力就等于资金保管权。
- 单向性。 私钥能推出公钥,公钥推不出私钥。这就是为什么公开自己的地址是安全的。
- 验证不需要你的私钥。 别人拿你的签名就能反推出公钥,从而确认「这条消息确实来自这个账户」。
第三条是整套机制得以成立的原因,也是本文最该记住的一条安全边界:任何需要你提供私钥或助记词才能「验证」的流程,在技术上都是不成立的。 验证从来不需要它们。
私钥和助记词在任何情况下都不应该给出去。 没有例外情况,没有「客服帮你处理一下」的特殊通道,也没有「只是读一下不会动」的说法。
四、消息签名:不上链的那一类
消息签名和交易签名在技术上用的是同一套密码学,区别在于签出来的东西拿去做什么。
官方文档把消息签名归为链下签名(off-chain message signing),并说明了它的好处:节省 gas、减少链上交易的数量。
典型的用途是「证明我是这个地址的主人」——比如登录某个应用时,不需要发起一笔链上交易,只要签一段消息。
针对这类签名,以太坊有一个专门的签名数据标准(EIP-191),它的机制值得知道,因为它解释了你为什么会在签名内容里看到一堆看起来像乱码的前缀。
简单说,这个标准要求签名时的数据以特定字节开头,从而保证任何一个这类签名都不可能恰好是一笔合法的以太坊交易。官方文档在讲 eth_sign 这个方法时说明了它的目的:
通过在消息中添加前缀,可以使计算出的签名被识别为以太坊特定的签名。这可以防止恶意去中心化应用 (dapp) 签署任意数据(例如交易)并使用该签名冒充受害者的滥用行为。
换句话说:这个前缀是为了防止「把你的消息签名当成交易签名用」而存在的。 它挡住的是这一类滥用,不是所有滥用。
所以「消息签名不上链」这句话是对的,但它不构成「所以随便签」。 签名的用途取决于要你签的那个应用怎么用它。签名之前该看的,是内容,不是它的类别。
五、为什么要看签名内容:盲签这件事
上一节留下的问题是:既然消息签名不上链,代价是不是小一点?
真正的问题在于你看不看得懂你在签什么。官方标准文件里对这件事有过一段很直白的描述,大意是:目前签出来的消息对用户来说往往是一串不透明的十六进制,几乎没有关于这条消息由哪些内容构成的上下文。
为改善这一点,后来有了结构化的签名数据标准(EIP-712),它做的事情是把结构和数据一起编码,让钱包能在你签之前把内容展示出来给你核对。这个标准的动机部分写得很清楚:让钱包能把内容呈现给用户,而不是只给一串看不懂的字符。
但结构化了不等于看得懂。 业界正在推的「清晰签名」标准(ERC-7730,目前是草案)在动机部分承认:大多数待签数据,即便附带了数据结构描述,也不足以让用户正确地核对。这个标准的主张只有一句:
a transaction should be readable by a human before it’s signed. What you see is what you sign.
它配的官方站点上还有一句更形象的话,大意是:签署一笔你读不懂的交易,就像签一张空白支票。
这一节要说的是:把「这个签名不上链,所以风险小一点」当成判断依据是靠不住的。真正的判断依据是你能不能读懂它要做什么。读不懂的时候,不签比签错强。
六、交易签名:签名不等于发送
交易签名是这四件事里被误解最深的一件。官方文档对交易的定义是「来自账户的经过密码学签名的指令」,交易的字段里有一个签名栏,说明它是「在发送者的私钥对交易进行签名并确认发送者已授权此交易时生成的」。
关键在于签名和发送是两步。官方文档在介绍 eth_signTransaction 这个方法时写得很清楚:
签名一笔交易,该交易可以在稍后使用 eth_sendRawTransaction 提交到网络。
注意「可以在稍后」这四个字。签名只是生成了一份已经授权的指令,它要真正生效,还需要被广播到网络、被打包进区块、并且支付 gas。
这也解释了链上交易和消息签名的另一个结构性差别:交易有一个序号(nonce)——官方文档把它描述为一个顺序递增的计数器,用于指示来自该账户的交易编号,作用是防止重放攻击,也就是防止一笔已经签好的交易被反复广播和重复执行。
对照来看:
| 消息签名 | 交易签名 | |
|---|---|---|
| 是否上链 | 官方归类为链下签名 | 签名后可广播上链 |
| 是否花 gas | 官方说明链下签名节省 gas | 需要支付 gas |
| 是否带序号 | 不作为签名消息的组成部分 | 交易对象必须包含 |
(这张表是把官方几处分散的说明放在一起对照的。官方文档里没有逐字写过「消息签名不上链、不花 gas、没有序号」这三句否定式表述,所以这里不把它们当作引文。)
七、代币授权:approve 和 allowance 在做什么
现在讲四件事里唯一直接关系到你余额的那一件。
在 ERC-20 代币规范里,授权由 approve 这个函数完成。官方规范对它的定义是:
Allows
_spenderto withdraw from your account multiple times, up to the_valueamount. If this function is called again it overwrites the current allowance with_value.
三个要点:
- 它允许某个地址从你的账户里多次提取。
- 提取上限是你设定的那个额度。
- 再次调用会把当前额度整个覆盖掉——不是叠加,是替换。
配套的 allowance 函数负责查询:「返回 spender 还能从 owner 那里提取多少」。
而真正把钱划走的动作是 transferFrom。规范里对它的说明是:从 _from 转到 _to,并且除非 _from 已经通过某种机制刻意授权了这个发送方,否则它应该报错。
把这三个函数连起来看,就是授权的完整链条:
- 你调用
approve,写下一个额度 - 某个合约因此获得了从你账户提币的资格
- 它调用
transferFrom,在额度内把代币划走
所以「授权」不是签个名那么轻。 它就是那个真正让第三方能动你余额的动作,而且它在链上留下了永久的记录。
关于「无限授权」为什么更危险:额度一旦设成一个极大值,这条通道在金额上就没有上限了。规范里还有一条实用的提示,大意是出于安全考虑,客户端界面应该先把额度置为 0 再设置新值——这说明连额度覆盖这个动作本身都有被利用的空间。
本文到这里为止,不涉及已被授权之后如何查看和撤销——那是另一个题目,本文不做重复。
八、四件事的风险各不相同
把前面几节收拢成一张判断表:
| 动作 | 代价大致是什么 | 该看什么 |
|---|---|---|
| 连接钱包 | 暴露地址和持仓,属于隐私代价 | 这个站是什么来路 |
| 消息签名 | 不上链,但内容可能被用于登录或其他用途 | 签的到底是什么内容 |
| 交易签名 | 签了还没发,但发出去就是一笔真实交易 | 这笔交易会改变什么状态 |
| 代币授权 | 允许对方在额度内动你的余额 | 授权给谁、额度是多少 |
一句话概括:这四件事的风险不是从低到高排一条线,而是四种不同性质的东西。 把它们统一说成「签名很危险」或者「连接一下没关系」,都不准确。
九、风险提示
不要把所有签名都说成安全的,也不要把所有签名都说成会转走资产。 本文第一节那张表就是为这件事准备的:连接不产生链上动作,消息签名不上链,交易签名要广播才生效,代币授权才是真正放开余额的那一步。混为一谈,判断一定出错。
私钥和助记词在任何情况下都不给。 这一条没有例外。官方文档写得很清楚:私钥赋予你对账户资金的保管权,且必须保持私密。任何索要它们的流程,在技术上都不需要它们——验证只需要签名,不需要私钥。
看不懂的签名不签。 这是本文最实用的一条。官方标准文件自己就承认,多数待签数据不足以让用户正确核对。当你看不懂那串内容在做什么的时候,「先签了再说」的期望收益是负的。
连接也要当回事。 它不转移资产,但它把你这个地址的全部持仓交给了一个网站。用哪个钱包去连,值得先想一下。
本文只讲这四件事分别是什么,不涉及已经授权之后怎么处理。 如果你怀疑自己已经授出了不该授的权限,处置方式属于另一个题目,本文不展开。
本文不构成投资建议,也不构成任何形式的收益承诺。链上操作不可逆,请自行核对后再执行。
十、本文依据的官方资料
下面几页全部来自以太坊官方文档与以太坊改进提案(EIP)标准文件,是写这篇文章时直接打开的原始来源:
- 账户与交易——账户密钥对的定义、私钥签名的单向性、交易是「经过密码学签名的指令」、nonce 与重放攻击
- JSON-RPC 接口文档——
eth_sign的前缀机制与它防的那类滥用、eth_signTransaction的「可以在稍后提交到网络」 - EIP-191:Signed Data Standard——签名数据的前缀规范,以及它如何保证这类签名不可能是一笔合法交易
- EIP-712:Typed structured data hashing and signing——把结构与数据一起编码、让钱包能把内容展示给用户核对的动机
- EIP-20:代币标准——
approve、allowance、transferFrom三个函数的官方定义 - EIP-1102与 EIP-1193——连接钱包对应的接口,以及「默认不暴露账户」这条隐私建议
- ERC-7730:Structured Data Clear Signing Format——草案阶段,讲待签数据为什么不足以让用户核对,以及「签署前应当可读」这一主张
两点说明。 第一,「消息签名不上链、不花 gas、没有序号」这三句否定式表述,官方没有逐字写过;本文把它们写成由官方几处说明推出的对照关系,而不是引文。第二,「签名本身不会转移资产」这句也没有官方逐字表述,本文的写法是区分「签名只是授权声明」和「改变链上状态需要广播并进块」这两件事。
如果你还没有钱包、想先搞清楚助记词和私钥的关系,见助记词、私钥和钱包密码有什么区别;装 App 时怎么确认来源可靠,见Binance App 下载与安装;账户层面的安全设置见账户安全与加密交易风险。
vip2017 vip2017 常见问题
连接钱包就等于把资产交给网站了吗?
不是。连接钱包这一步做的事情是把你的地址告诉那个网站。按照以太坊官方的接口规范,这一动作触发一个界面让你同意或拒绝,返回的是一个地址数组。它本身不产生任何链上动作,也不转移任何资产。但它确实是隐私边界:那个网站从此知道了你是谁、持有什么。
消息签名会不会转走我的币?
消息签名本身不产生链上交易。以太坊官方文档把消息签名归为链下签名,并说明它的好处正是节省 gas、减少链上交易数量。但要注意,「不上链」不等于「没风险」——有些场景会拿你的签名去做登录或其他用途,所以签之前应该看清签的是什么内容,而不是因为它不上链就闭眼签。
代币授权和签名有什么区别?
授权(approve)是一次具体的链上交易,它写入的是一个额度:允许某个地址从你的账户提取最多多少代币。之后对方用 transferFrom 就能在你授权过的额度内把代币划走。所以授权不是「签个名」那么轻——它就是那个真正让第三方能动你余额的动作。
「无限授权」到底危险在哪?
因为它把可提取的额度设成了一个极大值。ERC-20 规范里 approve 的作用是允许 spender 从你的账户多次提取、上限为设定的额度,并且再次调用会把当前额度整个覆盖。额度设成无限,等于把这条通道的期限和金额都去掉了上限,剩下的完全取决于那个合约会不会被滥用或攻破。
钱包弹窗里那一长串十六进制,我应该看吗?
应该,而且这正是问题所在——官方标准文件里承认,大多数待签数据即便配上结构描述,也不足以让用户正确核对。业界为此在推「清晰签名」(Clear Signing)的标准,核心主张就是一句话:一笔交易在签署之前应当是常人可读的。在钱包真正把内容翻译成人话之前,看不懂的签名不该签。
有人要我的助记词或私钥,说是帮我验证,能给吗?
绝对不能。官方文档写得很明确:私钥用于对交易进行签名,因此它赋予你对账户资金的保管权;公钥可以从私钥派生出来,反过来不行,所以私钥必须保持私密。任何人以任何理由索要助记词或私钥,都不是在帮你,而是在拿走你的账户。
签名之前最该看的是什么?
三个问题:这个网站是什么、这次签名要做什么、签完之后谁能动我的东西。前两个决定你要不要签,第三个决定万一判断错了代价有多大。本文讲的是怎么区分这四类动作,不涉及已经被授权之后怎么撤销。