惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The GitHub Blog
The GitHub Blog
L
Lohrmann on Cybersecurity
T
Threatpost
T
Threat Research - Cisco Blogs
C
Cybersecurity and Infrastructure Security Agency CISA
S
Schneier on Security
Engineering at Meta
Engineering at Meta
Scott Helme
Scott Helme
博客园 - 三生石上(FineUI控件)
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V
Visual Studio Blog
I
Intezer
L
LangChain Blog
Apple Machine Learning Research
Apple Machine Learning Research
S
Securelist
C
Cyber Attacks, Cyber Crime and Cyber Security
B
Blog RSS Feed
M
MIT News - Artificial intelligence
V
Vulnerabilities – Threatpost
T
The Exploit Database - CXSecurity.com
NISL@THU
NISL@THU
Cisco Talos Blog
Cisco Talos Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
Know Your Adversary
Know Your Adversary
H
Hackread – Cybersecurity News, Data Breaches, AI and More
阮一峰的网络日志
阮一峰的网络日志
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
The Cloudflare Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Vercel News
Vercel News
Stack Overflow Blog
Stack Overflow Blog
The Hacker News
The Hacker News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
The Register - Security
The Register - Security
Simon Willison's Weblog
Simon Willison's Weblog
Security Latest
Security Latest
C
Cisco Blogs
量子位
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
P
Proofpoint News Feed
Cyberwarzone
Cyberwarzone
Y
Y Combinator Blog
C
CERT Recently Published Vulnerability Notes
T
Tenable Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
AWS News Blog
AWS News Blog
Project Zero
Project Zero
D
Darknet – Hacking Tools, Hacker News & Cyber Security
A
Arctic Wolf
K
Kaspersky official blog

Tony Bai

Twitter之父再出手:Block开源Buzz,要让人类和AI Agent「同工同权」 Loop Engineering才火两个月,硅谷已经卷出“Graph Engineering”了 我开源了 cc-session-migrate :让 Claude Code 会话在多台机器之间自由迁移 从掌上设备的失败到AI时代的基石:Java官方纪录片,揭开一门语言30年的生死赌局 “皇帝的新衣”一年后:对话Thorsten Ball谈Agentic编程 告别标签页焦虑:我让 AI 帮我做了个浏览器插件 TabQueue Bun刚把Zig重写成Rust,这个团队却用487天反向重写 为了一个函数名,Go官方吵了两个月:maps.Same提案近日正式通过 Go 1.28 路线图首度曝光:Cgo 告别C工具链?泛型容器将入标准库? 掌控外环:为什么“循环工程”的边界必须由人类死守? 171个“已批准”却迟迟未实现的提案:Go语言的十年“欠账清单” 别再往 Go 里塞 Java 了:拆解 spf13 的 Idiomatic Go 信仰 AI 不在乎代码烂不烂,但你的Token账单在乎:一项660次实验揭示的编程新常识 10倍速 TypeScript 7.0 正式发布,前Go产品经理:Go才是AI智能体时代的“天选语言” Bun 重写为 Rust 后,Zig 之父罕见开炮:“我们早就等着看你重写” 全新 AI 技术栈:模型、Harness、Loop 与自我进化的智能体 AI 重写 Bun 为Rust全过程揭秘:101万行代码、11天、64个Claude并行开工 MCP Server 架构模式全解析:5 种模式、4 个反模式,与那条不能越过的“工具数量红线” 从手动 govanityurls + Nginx 迁移到 gvu:一次真实迁移记录 Go 私有模块拉取全解:凭据配置 + Vanity URL,个人与组织全覆盖 从“切歌小工具”到“零人工代码”:Claude Code 的诞生史,比科幻还科幻 如何使用 Claude Code 构建 AI 循环系统(Loops) 5 分钟上手 gvu:把 vanity import path 这件事,从“半天运维”变成一条命令 Go 对语言演化的保守态度,在未来 5 年是否仍然正确呢? 五年,三篇文章,一个我一直没真正解决的问题 别把“容易”当“简单”:Gin 框架作者撰文揭秘 88k Star 背后的架构哲学 每个 AI 工程师都应该知道的 20 个循环设计模式 cc-switch-cli:专为终端控与远程开发打造的 Claude Code 多模型切换工具! Andrej Karpathy 解析 Loop Engineering:构建“数日级”长程 Agent 的 9 条黄金法则 HashiCorp 创始人:AI 时代,我们为什么越来越需要有“品味”的程序员? HashiCorp 创始人:AI 时代,我们为什么越来越需要有“品味”的程序员? 一个 Rust 项目吃掉 75GB 硬盘?聊聊 Go 与 Rust 的“缓存焦虑”与拯救指南 折腾过各种语言后,我为什么总是回到 Go 语言? YC 揭秘 AI 原生组织:打造一家在睡梦中自我进化的公司 从 WordPress 到 Hugo:一个 20 年技术博客的迁移实录 偿还十年技术债:深度拆解 Go 1.27 的 GODEBUG 强力清理计划 浏览器里的“安全阴谋”:为什么 Go 1.27 的 UUIDv7 会离奇丧失随机性? Go 1.27新特性前瞻:泛型方法落地,标准库内建 UUID - Tony Bai AI 正在撕裂研发团队:狂欢的“托管派”与心碎的“守夜人” - Tony Bai 屠榜 CNCF!为什么在云原生时代,Go 语言能把 Java、C++ 和 Rust 堵在门外? 上千程序员自爆 AI 的“卧槽时刻”:是推开神界大门,还是跌入黑盒地狱? - Tony Bai 大模型正在见顶!传奇架构师:欢迎来到“平坦曲线时代” - Tony Bai Anthropic 40万大样本揭秘:AI 时代为什么“专家”身价暴涨? - Tony Bai 在 AI 编码时代,为什么我们依然选择 Go 而不是 Rust? DeepMind 亮出王炸:别再手写 Agent Harness 了,AI 已经学会自己写了! 为什么说“编译通过,就能运行”?Google 专家 Alice 揭秘 Rust 的工程美学与底层逻辑 谷歌 SRE 重磅白皮书:当 AI 自动写出 10 倍代码,谁来阻止系统崩溃? 别再省 Token 了!硅谷新共识:浪费算力才是唯一捷径 - Tony Bai Linux 内核顶级维护者:写了 35 年 C,是 Rust 让我重新找回了编程的乐趣 拒领上亿、封杀 AI:Zig 之父为什么 10 年不发 1.0? 写地道的 Go 语言,是否能让你成为了一个更好的开发者? - Tony Bai RSA 将死?Let’s Encrypt 押注 MTCs 迎战后量子时代 C++ 的权力游戏:一部关于妥协、背叛与重生的“史诗神剧” - Tony Bai 终结十年纠结:Go 新提案允许 Example 支持任意函数签名 - Tony Bai 2026年,大厂重构核心系统为何集体投向 Go? - Tony Bai “辛辛苦苦考上985,却发现AI能替代我90%的工作”:今天的高考,我们还在为什么而战? - Tony Bai 传奇黑客 Geohot 炮轰 AI Agent:这是软件工程史上代价最昂贵的灾难! 别把 Go 写成 Java:毁掉项目从过度架构开始 - Tony Bai 开源维护者的困境 - Tony Bai AI 时代如何真正掌握一门新技术?这份非主流学习指南建议永久收藏 - Tony Bai Go 生态17年大浪淘沙:2026年最值得引入的10个“神仙级”QoL工具包 - Tony Bai 再见样板代码!Go 官方新提案:函数一键转接口 - Tony Bai 写代码快 10 倍,不等于研发快 10 倍!Google 揭秘 AI 系统级瓶颈 Google I/O 2026:Jeff Dean 携 DeepMind 众神宣告,AI Agent 正在终结“标准化软件”时代 AI 优化 1.5ms,手写 0.02ms!Ghostty 作者痛批 AI 编程“平庸陷阱” Redis 之父吐槽现代前端的复杂性:我们到底是在解决问题,还是在制造问题? - Tony Bai 无痛消灭技术债:Google I/O 2026 开启 Go 自动重构时代 省下 10% CPU!Uber 揭秘 Go 栈扩容的隐秘代价 从 Go 迁移到 Rust - Tony Bai 悄悄用 Go 重写 AI 基础设施:NVIDIA 的 GPU 云平台为何选择 Go? Shopify 23,000 名工程师背后的 Claude Code 配置方案(你可以直接复刻的完整配置) Google 开源 AX 与 Agent Substrate:构建以 Agent 为核心的云原生计算底座 十年难题终获突破:揭秘 Go 1.27 接口逃逸分析优化 - Tony Bai
Go 密码学维护者放大招:把 Passkey 存成一行字符串,还顺手为 Go 1.28 写好了 API
Tony Bai · 2026-07-22 · via Tony Bai

本文永久链接https://tonybai.com/2026/07/22/go-passkey-record-crypto-passkey-api

大家好,我是Tony Bai。

【导读】 Go 官方密码学库维护者、age 加密工具作者 Filippo Valsorda 昨天丢出一枚"重磅提案":他认为 Passkey(无密码登录凭证)完全可以像密码哈希一样,被压缩成一行不透明字符串存进数据库。围绕这个新格式,他还顺手起草了一份可能进入 Go 1.28 标准库的 crypto/passkey API。这篇文章不仅给出了具体的字符串格式,还有一个反直觉的安全洞见:数据库里的 Credential ID,压根不需要跨账号做唯一性检查。

【文章要点】

  • Passkey 被视为当前信息安全领域最重要的进展,因为它是从协议层面杜绝网络钓鱼的少数方案之一;
  • 现有的 WebAuthn 凭证存储方案缺乏统一标准,Google、Adam Langley 等给出的建表建议各不相同,导致应用间数据库 schema 互不兼容;
  • Filippo Valsorda 提出 c2sp.org/passkey-record 规范草案,借用密码哈希字符串(PHC Strings)的语法,把 Passkey 凭证压缩成一行不透明字符串存储;
  • 该格式复用了 WebAuthn 规范中已有的 authenticator data CBOR 编码,仅需额外附加 transports 参数,无需重新设计数据结构;
  • 应用层只需负责维护“用户账号与 passkey record 的关联关系”,其余的元数据(昵称、时间戳等)不需要库做特殊处理,唯一例外是需要单独存储和更新的 backed_up 状态标志;
  • 基于这一存储格式,Filippo 起草了一份尚未实现、但接口设计完整的 crypto/passkey Go 标准库 API 草案,明确了注册和登录两条完整流程;
  • 该 API 目前处于征求社区反馈阶段,未来有可能作为正式提案进入 Go 1.28;
  • 文章提出一个反直觉的安全洞见:无需对不同账号的 Credential ID 做跨账号唯一性检查,因为该攻击本身依赖于 Credential ID 索引的存在——不建索引即可从根本上规避此类碰撞攻击。


如果要在“当下信息安全领域最重要的一件事”里选一个答案,Filippo Valsorda 的答案是:Passkey

理由很直接——网络钓鱼(phishing)几乎无法被“教育”或“警惕性”彻底解决,而 Passkey 是目前唯一一个从协议层面就能杜绝钓鱼的方案。这和内存安全语言解决内存破坏攻击是一个道理:不是让人更小心,而是让这类攻击从根上失效。

但问题也很现实:相比密码哈希,Passkey(也就是 WebAuthn)在服务端的实现体验要复杂得多。

一部分复杂度是无法避免的,因为 Passkey 的防钓鱼特性天然要求和浏览器交互;但另一部分复杂度,其实是可以通过一套标准化、可互操作的存储格式抹平的。

一个凭证,三种“官方建议”,各不相同

WebAuthn 规范里定义了一个抽象概念叫 credential record(凭证记录),里面包含 typeidpublicKeybackupStatetransports 等一堆字段。

问题是,具体怎么落到数据库表结构上,各家给出的建议五花八门:

  • Google 的建议:以 Credential ID 为主键,配上 public_keybacked_uptransports 几个字段;
  • Adam Langley(前 Google 密码学工程师)在《Tour of WebAuthn》里的建议:以 cred_id 为主键,但拆成 public_key_spkibacked_up 两个独立字段。

所有指南都会告诉你“用现成的库来处理 WebAuthn 认证流程”,但这仍然留下一个问题:不同应用、不同语言、不同库之间的数据库 schema 互不兼容。而且很多时候,把整个认证流程和数据库交互都甩给一个框架,也未必现实。

Filippo 给出的答案是:搞一套可互操作、规范明确的 Passkey 记录格式,让应用层像对待密码哈希一样,把它当成一个不透明字符串来处理——这正是密码哈希字符串(如 bcrypt、argon2 的存储格式)几十年来证明有效的思路。

passkey-record:借密码哈希字符串的“壳”,装 WebAuthn 的“核”

Filippo 提出的规范草案叫 c2sp.org/passkey-record,语法上直接借用了 PHC 字符串格式(Password Hashing Competition Strings,也就是常见密码哈希的那种 $算法$参数$哈希值 写法)。

一条记录长这样:

$webauthn$v=1$transports=hybrid+internal$<base64 authenticator data>

关键的巧思在于:这里的 payload 并不是重新设计的私有格式,而是复用了 WebAuthn 规范里本就存在的 authenticator data 编码——一段 CTAP2 CBOR 编码,本身就包含了凭证记录里绝大多数字段,并且已经被包含在 AuthenticatorAttestationResponse(也就是 navigator.credentials.create() 的返回值,即使不启用 attestation 也一样)的 JSON 编码里。

唯一缺失的字段是 transports(凭证支持的传输方式,如 hybridinternal),这个字段被作为 PHC 参数附加在字符串里。

这样一来,应用层唯一要做的事,就是记录并维护“某个用户账号关联了哪些 passkey record”——这件事其实和实现密码认证没什么本质区别(无非是一个账号可能对应多个 passkey)。这些不透明字符串可以直接传给库去验证登录断言,或者在生成注册请求时用来填充 excludedCredentials

有了这套统一、可互操作的存储格式,未来更换 Passkey 库(甚至更换后端语言)时,理论上可以完整保留原有的凭证数据库,不需要做数据迁移。

除了 passkey record,你可能还想存这些

除了 passkey record 本身,应用通常还会想存一些元数据,比如用户自定义的昵称、创建时间、最后使用时间,方便做出一个体验友好的 Passkey 管理界面。这些字段都不需要 WebAuthn 库做任何特殊处理。

唯一的例外,是“是否已备份”(backed up)这个状态标志。

Passkey 会向服务端报告自己是否已经被备份(比如同步到了 iCloud 钥匙串或 Google 账号),服务端可以利用这个信号,提示用户可以考虑移除密码、彻底转向无密码登录。

但这个标志有个特殊之处:它在每次登录时都可能变化,而 passkey record 本身是不可变的。所以它必须被单独存储,并且在每次登录时更新。

Filippo 在这里也表达了一个偏“实用主义”的态度:他认为这套逻辑对于普通网站来说其实被高估了——反正大部分网站还是会保留邮箱密码重置这条后路,过度设计这个信号的实际收益有限。

重头戏:一份可能写进 Go 1.28 的 crypto/passkey API

在 passkey record 这套存储格式的基础上,Filippo 起草了一份 crypto/passkey 无状态 Go 包 API 草案

注册流程:

  1. 调用 RelyingParty.NewRegistration,传入已登录(或已识别)用户的信息,以及该用户已有的 passkey record;
  2. 把返回的 JSON 传给浏览器端的 parseCreationOptionsFromJSON(),再传给 navigator.credentials.create()
  3. 把浏览器返回的、JSON 编码的 PublicKeyCredential 传给 RelyingParty.Register
  4. 把返回的 passkey record 存进数据库。

登录流程:

  1. 在生成登录页面时,调用 RelyingParty.NewLogin
  2. 把返回的 request 以 RequestID(request) 为 key,存进一个短 TTL 的键值缓存里,同时把返回的 JSON 传给 parseRequestOptionsFromJSON(),再传给 navigator.credentials.get()
  3. 把浏览器返回的 JSON 编码 PublicKeyCredential 传给 Inspect,用返回的 requestID 从缓存里取回 request,用返回的 userID 从数据库里取回该用户的 passkey record;
  4. 把 JSON PublicKeyCredential、request、passkey record 一起传给 RelyingParty.Login

从这两个流程可以看出,应用层真正需要负责的只有三件事:

  • 为每个用户关联一个不透明、永久、保护隐私的用户 ID;
  • 存储与用户关联的 passkey record;
  • 缓存由 RelyingParty.NewLogin 产生的 request 挑战值。

这个库返回的 JSON 值可以直接传给浏览器原生的 parseCreationOptionsFromJSON()parseRequestOptionsFromJSON(),也能直接接收调用 PublicKeyCredential.toJSON() 得到的返回值——中间不需要任何手动格式转换。

这套设计主要针对可发现凭证流程(discoverable credential,也就是我们常说的“Passkey”体验:认证器自己存好并向服务端提供用户 ID)。

不过 RelyingParty.NewLoginForUser 方法也支持用在二次验证或重新身份确认这类场景。同时,模态(modal)和条件 UI(autofill,也就是输入框自动弹出 Passkey 选项)两种交互方式,这套 API 都能覆盖。

此外还提供了几个辅助函数:从 passkey record 里提取信息的 AAGUIDBackedUp,以及从 JSON 编码的 PublicKeyCredential 里提取信息的 ResponseBackedUp

需要说明的是,这份 API 目前还没有实现,Filippo 表示希望先收集社区对 passkey record 格式和这份 Go API 设计的反馈,之后再考虑正式提案,争取进入 Go 1.28

反直觉的安全洞见:别让攻击者决定你的主键

文章最后一节,抛出了一个很多人可能没细想过的问题:这种存储模型下,没办法保证不同账号之间不会共享同一个 Credential ID——而 WebAuthn 规范里明确写着,服务端 SHOULD(应当)做这个检查。

先看这个检查存在的初衷:如果服务端用 Credential ID 做索引查找凭证,攻击者理论上可以故意在自己的账号下注册一个和别人 Credential ID 相同的凭证,制造 ID 碰撞,从而让查找逻辑“走错账号”,查到错误的公钥或用户 ID。

但 Filippo 指出了一个更根本的解法:这种攻击的前提,是你的系统里存在一个 Credential ID 索引。如果压根不建这个索引,攻击自然也就无从谈起——防御一个“因索引而生的攻击”最彻底的方式,就是不建索引。

在他设计的模型里,登录请求本身携带用户 ID,服务端用这个用户 ID 去查找该用户名下的 passkey record 进行校验。这种情况下,其他用户是否恰好有一个 Credential ID 相同的 Passkey,根本不重要——就像两个用户使用了相同的密码,也不影响系统安全性一样。

他把这个原则总结成一句很好记的话:

不要让攻击者决定你的 PRIMARY KEY,你就不会遇到 PRIMARY KEY 碰撞攻击。

小结

这篇文章没有发布任何正式的库或工具,而是一份“设计提案”:一套借鉴密码哈希字符串思路的 Passkey 存储格式,加上一份尚未实现、但已经把接口想清楚的 Go API 草案。

对于正在用 Go 做 WebAuthn 服务端集成的开发者来说,这份草案至少提供了一个值得参考的方向——把 Passkey 当成密码哈希一样简单地存起来,把索引设计的坑提前避开。

Filippo Valsorda 表示,他会在 Bluesky(@filippo.abyssdomain.expert)和 Mastodon(@filippo@abyssdomain.expert)持续更新 Go API 的后续进展,感兴趣的读者可以关注。

参考链接:


还在为写 Agent 框架频频死循环、上下文爆炸而束手无策?我的新专栏 从0 开始构建 Agent Harness 将带你:

  • 抛弃臃肿框架,回归“驾驭工程 (Harness Engineering)”的第一性原理
  • 用 Go 语言手写 ReAct 循环、并发拦截与上下文压缩引擎等,复刻极简OpenClaw
  • 构建坚不可摧的 Safety Middleware 与飞书人工审批防线
  • 在底层实现 Token 成本审计、链路追踪与自动化跑分评估
  • 从“调包侠”进化为掌控大模型边界的“AI 操作系统架构师”

扫描下方二维码,开启从 0 开始构建Agent Harness 的实战之旅。


还在为“复制粘贴喂AI”而烦恼?我的新专栏 AI原生开发工作流实战 将带你:

  • 告别低效,重塑开发范式
  • 驾驭AI Agent(Claude Code),实现工作流自动化
  • 从“AI使用者”进化为规范驱动开发的“工作流指挥家”

扫描下方二维码,开启你的AI原生开发之旅。


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。