跳到主要内容

从倡议到工程:Passkey 原生账户与下一代钱包设计

Robert Mao
BlockchainSecurityIdentityVerifiabilityAgent Identity

在《Crypto 不能再这样下去》里,我呼吁这个行业共同改进基础设施。现在,我们先从钱包做起,把已经建立的 Passkey 原生账户基础,以及正在完善的下一代钱包设计公开出来。这是我们从倡议走向工程行动的第一步。

我希望其他做钱包、做链的人,都能从这里拿走一些可用的方法:怎样减少应用接触私钥的机会,怎样让一次签名只获得有限的权限,怎样让设备坏了、前端被攻破或服务停了之后,用户仍有办法保护自己的资产。每个团队可以选择自己的实现。

我们的方向是把成熟认证技术带到区块链里,同时重新设计授权、执行和恢复。Passkey 是起点;一个完整的钱包,还必须回答签名之后会发生什么。

ArcBlock 在 v1.19.x 已经加入原生 Passkey 账户支持,升级文档保留了这个过程。我们在这个基础上继续做多签、交易验证和账户保护。下一代钱包产品仍在开发,本文会区分已有基础、已有组件和后续设计。既有的软件密钥、助记词钱包与硬件钱包使用路径继续兼容,用户可以按自己的需要选择升级。

钱包已经够复杂了,用户还要负责多少事情?

我用过不同的硬件钱包。很让我头痛的一件事,是隔一段时间又要升级,升级前再被提醒确认恢复备份。钱包本来应该让人安心,到了这一步,却又要问自己:备份放在哪里?还能不能用?这次升级万一出问题怎么办?

Trezor 的固件更新指南明确要求准备好钱包备份,并说明更新异常可能擦除设备内存,需要通过备份恢复。[1] 对厂商来说,这是负责任的风险提示;对使用者来说,恢复这个沉重的任务依然在自己身上。

再看看我们的备份方式:先把助记词抄在纸上,担心纸会坏,再把它刻到钢板上。密码学走了这么远,最后用户却得像保存一张藏宝图一样,守着一张纸或一块钢板。我每次想到这里,都觉得这个画面有些荒诞。

纸和钢板并非没有用。离线备份可以避开远程攻击,钢板可以提高耐火、耐水和耐久能力。可是它们保护的是恢复秘密的保存,解决不了错误授权、被诱导签名,或者一把钥匙拥有过大权限的问题。用户还得安排防盗、防丢、分开放置,以及自己发生意外之后的恢复。

安全工程可以继续进步,用户却不该被要求把一生都变成备份管理员。

用户面对纸质助记词与金属备份板,以及硬件钱包升级和恢复准备的概念漫画。

纸和钢板保护恢复秘密;用户还需要承担保存、升级和恢复的工作。概念插画,不是真实产品界面。

软件钱包:加密保存之后,签名时怎么办?

典型的软件钱包会把种子或私钥加密保存,解锁后再由软件完成签名。密钥材料在什么进程、什么时刻出现,取决于实现:有的在 JavaScript 或应用内存里,有的在隔离的签名进程里,有的利用系统密钥服务。不能把所有软件钱包都当成同一种结构。

需要追问的是:应用能否拿到原始签名私钥?恶意依赖、扩展或同域脚本能否接触它?如果攻击者拿走这把钥匙,后续签名还需要用户参与吗?账户又能否限制这把钥匙的能力?

密钥被复制走,和密钥没有被复制、却被攻击者调用去签名,是两种不同的失败。 前一种需要收紧密钥材料的边界,后一种还需要收紧授权与支出边界。只把存储加密做得更好,回答不了全部问题。

硬件钱包:隔离了钥匙,还要处理意图与恢复

硬件钱包的重要贡献,是让签名密钥留在独立设备,并提供一条可以与主机分开的确认路径。可信屏幕很有价值,尤其当它准确展示了实际要签的内容时。

但主机送来的交易是否能被完整解释?设备展示的金额、收款人和权限变更是否与执行内容一致?复杂授权是否仍会退回到用户看不懂的字节?这些都影响保护能走多远。设备坏了,恢复材料怎样保存、谁能拿到,也是另一层问题。硬件钱包已有不同的恢复设计,例如 Trezor 支持阈值恢复份额,不能笼统地说所有产品都只依赖一份 24 词备份。[2]

固件升级同样需要认真看待。签名算法相对稳定,设备里的实现、通信协议、解析器和安全边界仍可能需要修复。认证器也有生命周期:Yubico 采用不可升级固件的设计,但其安全公告同样记录过需要风险评估和设备处置的硬件问题。[3]

我想借鉴的,是银行卡芯片、企业认证器和安全密钥那种更稳定的使用分工:业务系统可以持续演进,用户不必为每一次业务变化重新处理根密钥。把认证根做小、做稳定,把变化留在适合变化的层里,再把失效后的替换与恢复设计好。 这是我们希望钱包获得的 peace of mind。

Passkey 怎样成为一个链上账户?

Passkey 是一种基于公开密钥的认证凭证,WebAuthn 定义浏览器与认证器之间的调用和断言格式。本文主要讨论我们采用的 ES256,也就是基于 P-256 的 ECDSA 路径;WebAuthn 本身还可以协商其他算法。[4]

普通钱包把一段交易数据交给签名算法。WebAuthn 多了一层结构:应用提供 challenge,浏览器形成包含 challenge、origin 等信息的 clientDataJSON,认证器对下面的数据签名:

text
authenticatorData || SHA256(clientDataJSON)

链上验证器需要理解这个结构,不能只把拿到的签名当成一份普通的椭圆曲线签名。它还必须知道,这次断言到底在授权什么。

ArcBlock 的既有路径,是由 Passkey 的公开密钥派生 did:abt: 账户标识,再由交易验证管道识别相应签名类型。这让 Passkey 可以直接对应链上账户,参与交易签名验证,不要求先为这个账户部署一份钱包合约。这个选择把一部分认证能力放到了协议层,也使协议维护者承担了相应的兼容与升级责任。

“原生”描述的是能力放在哪里。它不会自动证明实现更安全,也不消除协议升级的成本。其他体系也在进步:Safe 已有 Passkey 签名器,Ethereum 的 EIP-7951 定义了 P-256 验签预编译,不能再把合约账户或 EVM 路线一概描述成不能支持 Passkey、或者必然需要极高的验签开销。[5][6]

我们真正关心的是:一个应用、一个认证器和一条链之间,哪些事实由谁验证,哪些权限由谁约束。

下一代钱包的职责分层:认证器提供断言,钱包解释意图,会话携带有限授权,账户执行策略决定资产能否转移。图为设计目标。

设计目标:认证、可读意图、授权与资产执行分别承担责任。原生 Passkey 账户已有支持;图中的完整钱包仍在开发。

Passkey 钱包的五个常见误区

这些判断看起来顺理成章,却把不同层的保障混在了一起。要把 Passkey 用好,先要拆开这五个误区,再决定每一层应该承担什么责任。

误区一:“用了 Passkey,私钥就永远锁在一块硬件芯片里”

云同步 Passkey 减少了单台设备丢失带来的困难。设备绑定凭证则把可用性更集中在具体认证器上。两者有不同的恢复方式和信任依赖,不能用同一个“私钥永不离开芯片”的说法概括。

WebAuthn 的 BE 表示凭证是否可备份,BS 表示当前是否已备份。可备份不等于此刻已经完成备份,BE=0 也不能单独证明使用了某一型号的安全芯片。若账户保护依赖特定硬件保障,还需要注册时的设备证明和可信认证器策略。UP、UV 分别说明用户在场、完成了用户验证,也不表示用户已经看懂交易;用户验证还可能采用设备 PIN。[7]

我们的设计应当允许日常便利与高权限保护分开选择。例如,日常身份使用同步凭证,关键管理动作再要求独立认证器或额外等待。这里的“独立”要落到真实的失陷边界:同一份凭证同步到两台设备,不能直接算作两个独立的多签因子。

误区二:“私钥不进网页内存,前端被攻破也拿不走资产”

普通 WebAuthn 没有规定把 challenge 对应的金额、收款人和操作内容展示给用户。操作系统确认了某个认证动作,用户未必知道它会产生哪笔链上交易。W3C 的 Secure Payment Confirmation 正是在支付场景中处理可信交易显示,但它也不是现成的通用区块链交易确认方案。[8]

因此,我们需要可读意图:明确列出网络、资产、金额、收款对象、授权范围、费用边界和有效期,并让这些内容与实际执行数据绑定。高权限操作还需要独立确认通道。若展示和签名都受同一个已经失陷的前端控制,再漂亮的确认页也不能独立证明用户看到了什么。

challenge 的域分离很有必要。它应绑定协议用途、链、签名者与交易摘要,避免一种场景的签名被另一种场景误用。但控制合法前端的攻击者,同样可能构造格式正确的恶意交易。可读意图和资产约束仍然需要各自站住。

误区三:“Passkey 要支持多个地址,就必须用 PRF 派生私钥”

WebAuthn 的 PRF 扩展可以为客户端提供伪随机输出,它可以用于加密或解锁数据。问题在于输出之后怎么使用。

如果把输出当成种子,在应用内派生长期交易签名私钥,那么应用又重新接触了签名秘密。认证器虽然保护了上游操作,派生出来的钥匙仍要面对软件环境的风险。我们希望在自有链的 Passkey 根签名路径上避免这个结果:让认证器直接完成签名,让公开信息负责账户寻址,不为了多地址重新制造一批应用可读取的私钥。

一种正在完善的设计是 SubAccountSalt:使用规范化公开密钥、公开的子账户标识和明确的域分离编码派生账户地址,再由协议验证根密钥与子账户的绑定。它派生的是地址,不是私钥。

这也限定了它的用途。多个子地址可以分开组织账户状态和策略,共用同一个根密钥时,根的失陷仍可能影响所有子账户;公开密钥与盐值也不自动提供匿名性。这套能力需要协议实现和兼容验证,本文把它作为后续设计介绍。

误区四:“不用助记词,设备一丢就再也无法恢复”

恢复不只有助记词这一种方式。同步凭证、预先登记的独立备用认证器,以及按明确规则更换凭证,都可以成为恢复设计的一部分。但 Seedless 本身并不保证恢复已经可靠。我们希望用户可以登记多个凭证,明确日常、管理和恢复分别需要哪些条件,在设备丢失时更换凭证,而不是重新抄下一份可以控制一切的秘密。

这里必须同时面对失窃和失联。云账户被接管怎么办?备用认证器也不在了怎么办?钱包服务停了,原来绑定的依赖方(RP)域名还能不能使用?用户能否从独立客户端发起恢复,并核验结果?只有设备还在,不代表依赖的域名、服务和广播路径一定可用。

恢复还涉及治理。降低保护、增加高权限凭证或替换控制根,应有独立授权和可观察的等待期;紧急收紧权限,可以走不同的条件。谁能否决恢复,也要写清楚。如果已经失陷的日常凭证能够无限次阻止合法恢复,保护机制本身就可能造成锁死。

误区五:“每一笔操作都刷脸确认,才是最安全的”

弹窗次数不是安全指标。每次都刷脸,仍不等于每次都看懂。无差别的确认还可能带来授权疲劳,让真正重要的权限变更淹没在日常提示里。我们希望把确认集中在建立授权、扩大权限和关键资产操作上,让有限的会话授权承担日常小额操作和 Agent 自动化。

不过,会话钥匙也不能只靠“不可导出”三个字获得信任。

WebCrypto 的 extractable:false 可以禁止通过导出 API 取得原始私钥,但不保证它一定在硬件里,也不阻止取得句柄的同域脚本调用 sign()。在一个最小实验中,一把不可导出的 P-256 私钥拒绝导出,却仍可以正常签名和验签。这正是这个 API 的功能边界。[9]

因此,会话保护必须由账户执行规则继续约束:能做什么、对谁、使用哪些资产、累计多少、何时到期、如何撤销。会话密钥失陷后,攻击者最多能消耗多少剩余额度,是比“用了不可导出密钥”更有意义的安全指标。

下一代钱包:把签名后的执行也纳入保护

我们的设计分成四层:认证器保管根凭证;钱包把交易解释成可读意图;会话承载有限权限;账户的执行层落实策略。恢复和策略变更贯穿这四层,需要单独的授权条件。

在此基础上,AccountGuard 是我们正在建设的声明式账户保护方法。它用可验证的规则表达单笔阈值、滚动窗口额度、允许去向、凭证权限、等待期与紧急停止条件,让规则参与执行判断。相关 DSL 与策略引擎已经有实现基础;完整钱包还需要连接认证、持久化状态与共识,并确保所有资产执行入口都执行这些规则。

小额便利,大额有明确的等待和管理条件

下面是一组便于解释的设计示例,不是已经发布的产品默认参数:

  • 一把日常凭证只能给已批准的对象付款,使用指定资产,并受滚动累计额度约束。
  • 具备足够权限、但超过即时执行阈值的操作进入等待队列;真正超出可授予权限的操作直接拒绝,等待不会自动使它合法。
  • 提高额度、改变关键去向或更换管理根,需要独立授权和等待,日常凭证不能独自关闭保护。
  • 在实际执行前,具备预设紧急权限的凭证可以提交否决;执行时仍要重验当前策略、撤销状态、期限和额度。

设计中的交易生命周期:完成验签和授权后,策略可以拒绝、准许立即执行或进入等待;等待期间可按权限否决,到期仍需重新校验,最终执行后不再属于这个撤销窗口。

等待发生在资产实际执行之前。否决交易也需要被链及时接受;已经完成最终结算的转账,不能靠这条机制倒退。

时间锁创造的是反应窗口。它不能保证用户一定收到通知、一定在线,或者紧急请求一定赶在攻击交易之前确认。产品还需要独立通知、紧急操作的可用路径、费用安排和压力下的演练。把“有 Veto 按钮”写成“任何时候都能救回资产”,会掩盖真正困难的部分。

限额也要承受组合攻击。排队交易是否已经占用额度?几笔并发交易会不会各自读到同一份剩余额度?窗口跨日、重启和故障重试之后,累计状态是否仍然一致?只检查页面上的单笔金额,远远不够。

规则约束的是全部可改变资产控制权的入口

转账只是最容易看见的入口。授权额度、合约调用、NFT 转移、批处理、委托、多签配置、账户迁移和软件升级,都可能改变资产能被谁处置。

一个可靠的保护层必须定义覆盖范围,并说明例外。如果日常钥匙不能大额转账,却能修改多签门槛或给另一个地址无限授权,限额就会从另一条路被绕过。保护规则本身怎样变更,应该接受与支出同等级的审查。

我们倾向于用小而明确的规则表达账户安全条件,尽量缩小需要解释的状态空间。声明式规则仍可能有漏洞。规则解释器、整数精度、状态持久化和版本升级,都进入安全边界,仍需要独立审查。

哪些已经做了,哪些还要继续做?

写工程文章,不能把设计完成、组件实现和用户已经能用混成一件事。当前阶段可以这样理解:

层次当前基础本文中的状态
Passkey 原生账户公开文档已有 v1.19.x 的账户与交易支持既有能力,持续改进
多签与交易验证已有逐签名 WebAuthn 元数据支持、交易规范性检查与签名无关去重等实现协议组件,需结合实际版本与激活配置
账户策略已有声明式规则、累计额度与等待队列等策略引擎基础已有组件,完整钱包的执行保护仍需集成与验证
子账户、验证版本与换钥公开信息派生子地址、用途绑定、防降级与控制根迁移设计正在完善,按实际实现与验收更新
下一代钱包与恢复体验将上述能力组织成日常使用、管理、紧急停止与恢复流程产品仍在开发
外链控制复用目标链认可的签名与成熟账户机制后续探索,需要逐链设计和验证

下一阶段的协议设计尤其需要处理几个问题。

公钥编码必须稳定。 同一个椭圆曲线点可以有不同的外部表示;如果地址从公钥字节派生,就需要明确合法点、编码、字段集合和规范化规则,同时照顾已存在的地址,不能在升级时重新解释旧账户。

交易身份不能被签名包装随意改变。 ECDSA 存在签名表示的可延展性,WebAuthn 又有额外的断言数据。去重需要识别实际授权的操作,签名规范化只是其中一层。参与者、授权范围和业务载荷仍必须被正确承诺,不能在去掉签名数据时顺手去掉授权含义。

新验证规则要有明确的激活和防降级方式。 历史交易怎样重放,旧账户怎样继续工作,升级后的账户能否被删字段降回旧规则,这些都需要协议定义。钱包界面上的一个“已升级”标签不能代替链上状态。

更换钥匙要验证新钥匙确实可用。 新凭证持有证明、用户可操作性检查和恢复演练可以降低误锁风险。旧地址继续存在、通过迁移关系转向新地址,以及在原地址替换控制权,是不同的协议语义。我们会按实际落地的方式说明,不把它们都叫作“无损升级”。

跨链安全,必须承认每条链的验证边界

把同一套账户理念带到其他链,是我们考虑的方向。这里最容易低估的,是签名与执行模型的差异。

WebAuthn 的 P-256 签名,不能直接当作 Bitcoin Taproot 要求的 secp256k1 Schnorr 签名。Safe 的 Passkey 支持依赖相应验证器;Squads 也是运行在 Solana 上的程序。复用成熟实现可以减少新增自定义逻辑,但不会让合约、适配器或外链验证条件消失。[10][11][12]

因此,后续跨链设计需要逐条回答:谁持有什么类型的钥匙?目标链验证哪些字节?负责检查规则的策略协签服务,怎样把批准绑定到最终执行内容?它的确认凭证怎样变成外链接受的授权?服务停机时,用户通过什么路径退出?

一个普通的 2-of-3 例子就能看出取舍。假设 A 是用户日常钥匙,B 是策略协签器,C 是离线恢复钥匙:

可用组合可以带来的能力必须接受的边界
A + B日常路径由用户和策略共同批准依赖策略服务可用,必须正确绑定实际交易
A + C策略服务失联时,用户仍可能恢复控制这也是绕过 B 的路径,需要独立保护 C
B + C满足普通任意两把钥匙的门槛可能不需要 A,必须确认是否符合用户预期

如果所有支出都必须经过 B,就不能同时声称 A+C 随时能直接提走资产。若需要等待后恢复,必须由目标链真正认可的时间条件和签名路径实现。时间锁也不是一把新的钥匙。

这部分仍需要逐链工程验证。我们会优先复用已有机制,并把新增信任、恢复条件和失败方式写清楚。

兼容旧钱包,给用户一条自愿的演进路径

下一代钱包以 Passkey 为主要入口,不等于让过去的钱包和账户失去作用。我们要保留已有密钥类型与使用路径,让用户按需求选择。

兼容至少有四层含义:旧账户仍能操作;历史交易仍按对应规则验证;开发者知道哪些 API 或协议需要升级;用户主动选择迁移时,知道地址、资产关系与凭证引用会怎样处理。早期 v1.19 的文档也记录了增加 Passkey 后部分 API 变为异步,这说明增加一种签名能力,同样需要清楚的开发者迁移说明。

我们希望新的默认体验减少助记词负担,同时让老用户有可检查、可演练的迁移过程。账户控制权、资产引用和恢复关系都确认之后,才能谈替换旧凭证。不会因为产品方向变了,就要求所有用户同时重新安排自己的资产。

比较钱包,比较的是这些能力

下面比较的是实现方式与设计目标,具体产品可能组合多种方式。关于我们钱包的条目,描述的是正在建设的目标,不是已经发布的保证。

应用是否接触签名秘密

方案能力与边界
软件密钥钱包依实现,可能接触解锁后的种子或私钥
传统硬件钱包通常由设备完成签名,主机不取出原始私钥
Passkey 合约账户或托管/协签方案取决于直接断言、MPC 或 PRF 后的实际用法
我们的原生 Passkey 钱包方向根签名不向应用交出原始私钥;会话另设边界

用户是否知道签了什么

方案能力与边界
软件密钥钱包依赖交易解析与可信展示
传统硬件钱包独立屏幕有优势,解析覆盖仍重要
Passkey 合约账户或托管/协签方案WebAuthn 本身不提供通用交易明细显示
我们的原生 Passkey 钱包方向可读意图绑定实际数据,高权限引入独立确认

有效签名能处置多少资产

方案能力与边界
软件密钥钱包取决于账户权限,未必有限额
传统硬件钱包设备隔离本身不自动限制账户权限
Passkey 合约账户或托管/协签方案可以有 guards、session keys、恢复或服务策略
我们的原生 Passkey 钱包方向将有限权限与账户执行约束结合,并验证覆盖面

设备损坏或失联后怎么办

方案能力与边界
软件密钥钱包依赖备份、其他凭证或恢复服务
传统硬件钱包依赖备份、份额或其他恢复安排
Passkey 合约账户或托管/协签方案依赖具体恢复设计及服务/合约可用性
我们的原生 Passkey 钱包方向多凭证、轮换、等待与独立恢复演练

日常与 Agent 自动化

方案能力与边界
软件密钥钱包可以自动签名,需要限制失陷影响
传统硬件钱包常需要额外授权或会话层
Passkey 合约账户或托管/协签方案已有不同形式的会话与委托方案
我们的原生 Passkey 钱包方向根凭证低频管理,日常使用限额、限期的授权

硬件钱包的可信显示值得学习,成熟合约钱包的恢复、会话和权限模块也值得学习。我们选择原生账户,是希望在自己的协议里把这些责任组织得更清楚;最终仍要由实际实现和攻击验证说明结果。

把这些设计变成别人可以检验的工作

公开这篇文章,是把我们自己的工作向外打开。要让其他钱包和链从中受益,还需要把保护条件变成可重复执行的验收场景。

我们认为,至少应该逐步公开下面这些场景及其结果:

失陷或故障场景需要证明的结果
前端显示正常收款人,实际请求被替换独立确认可以识别实际意图,账户策略限制未经授权的执行
会话密钥被恶意脚本调用操作范围、去向、期限和累计预算仍受执行层限制
攻击者拆单、并发提交或堆积等待交易总体暴露不超过策略定义;排队、重试与重启不重复释放额度
日常凭证试图提高额度或替换管理者需要预设的独立授权与等待,不能自行解除保护
手机丢失、云同步不可用或硬件认证器损坏用户能按预设条件恢复,过程中可以核验新凭证并处理旧授权
钱包服务或 RP 域名失联独立客户端与恢复路径能够按承诺工作,或明确说明限制
保护服务停机、延迟、拒绝协签或错误批准账户按事先约定的失败方式工作,退出条件不依赖临时善意
旧账户升级、旧区块重放与新规则激活兼容范围可核验,升级后不能被降回不允许的验证规则

这些是我们愿意接受的工程检验。我们会按实际完成的范围公开结果,也希望逐步形成可以共享的规范、向量和测试。

我不希望下一次钱包出问题时,行业的回答仍然只有“你有没有抄好助记词”。用户值得拥有更好的工具,也值得知道工具能保护到哪里。

我们已经有了原生 Passkey 账户这个起点,接下来要把签名、意图、权限、执行和恢复连成一个可以被认真检验的系统。把这套思路写出来,让同行可以讨论、反驳、采用并独立实现,就是我们现在愿意迈出的第一步。

参考资料


  1. Trezor:Update Trezor firmware。说明更新前准备备份及异常恢复的要求。 ↩
  2. Trezor:What is Shamir backup?。阈值备份及其恢复边界。 ↩
  3. Yubico:Security Advisory YSA-2024-03。认证器固件、设备风险与生命周期取舍。 ↩
  4. FIDO Alliance:Passkeys。Passkey 及同步与设备绑定凭证的背景。 ↩
  5. Safe:Safe and Passkeys。基于合约验证器的 Passkey 支持。 ↩
  6. Ethereum:EIP-7951: Precompile for secp256r1 Curve Support。P-256 验签预编译的规范。 ↩
  7. W3C:Web Authentication Level 3,尤其是认证器数据、备份状态和断言验证部分。 ↩
  8. W3C:Secure Payment Confirmation。普通 WebAuthn 与可信支付明细显示的边界;该规范仍有其适用范围与实现条件。 ↩
  9. W3C:Web Cryptography API,密钥存储、安全考虑与 extractable 语义。 ↩
  10. Safe:Smart Account Concepts。账户所有者、阈值、模块和交易验证。 ↩
  11. Squads Protocol:v4。多签程序及其权限与恢复相关条件。 ↩
  12. Bitcoin:BIP 340: Schnorr Signatures for secp256k1。Taproot 所用签名体系的基础。 ↩