钥匙串 + Passkeys 全链路:3MB 浏览器如何把密码安全做到系统级
钥匙串 Passkeys 全链路3MB 浏览器如何把密码安全做到系统级【免费下载链接】SearchA small, fast WebKit browser for macOS, by Office Commun.项目地址: https://gitcode.com/gh_mirrors/search59/Search一台只有 3MB 的浏览器凭什么敢谈系统级安全Search 给出的答案不是自己造一个加密保险箱而是把密码直接交给 macOS 登录钥匙串、把 Passkeys 流程从 WebKit 手里接管过来自己执行五重安全校验后再调用系统 AuthenticationServices。没有自有账本、没有云同步、没有遥测——所有秘密只存在于操作系统的保险库里解锁靠 Touch ID 与系统账户而不是浏览器自己的任何一道门。这篇文章从源码出发逐层拆解这条从表单提交到钥匙串写入、从页面请求到系统通行证的完整链路。密码全部入钥匙串标签隔离与生物识别校验不造账本直接把密码写进系统保险库多数浏览器把密码管理做成自有数据库 自带加密层密码先经自己的主密钥加密封存进 SQLite 账本再落进用户目录下的文件里。Search 选择了完全不同的一条路——Vault.swift 的文件头注释写得很直白Where passwords live: the macOS keychain, under this apps own name, as internet passwords keyed by site and account. Nothing is written to disk by this app in any other form, and nothing is ever logged.密码以kSecClassInternetPassword条目存进系统登录钥匙串由 site account 两个属性标识读写全部走SecItemCopyMatching/SecItemUpdate/SecItemAdd。文件头还点破了一个关键区别Safari 的钥匙串条目被 Apple 用专属 entitlement 隔开其他浏览器拿不到而 Search 的条目就在同一个系统保险库里只是以Search标签归拢——同一个保险柜不同的抽屉。抽屉的隔离不止是标签。写入时除了kSecAttrServer、kSecAttrAccount和kSecAttrLabel三个身份字段还额外带上kSecAttrAuthenticationTypeHTMLForm与协议标记。注释解释了原因服务器名 账户名在钥匙串眼里也会匹配到其他 app 的同站条目——比如 git 为 github.com 存的 token——不加这层身份一次更新就会把别人家的密码覆盖掉。列表与秘密分离四百条密码不是四百次解密钥匙串的一次调用要么列出条目、要么交出一个 secret两者不可兼得而SecItemCopyMatching同时索取全部数据时会静默返回errSecParam。这个坑在 Vault.swift 里被记录为一个真实的教训for a while this app saved passwords it could never read back。于是有了类型层面的隔离Login持有完整密码只用于填充表单与判断是否已保存Kept只有 host/user/used/clear 四个字段不含密码专门给列表和面板用。Vault.all()列出的[Kept]一行秘密都没有密码列表 UI 也就无从泄密每个 secret 是一次独立的secret(of:)调用只在显示或复制的那一下才发生。一个装了四百个密码的抽屉否则要在面板画出来之前做四百次钥匙串调用——这就是设计取舍读列表永远不碰秘密秘密永远按需现取。生物识别是显示的唯一入场券密码面板 Passwords.swift 的注释定下纪律a password is never shown until you have proved you are you。点击 Show 的路径是private func reveal() { Vault.prove(show the password for \(login.host)) { ok in guard ok, let password Vault.secret(of: login) else { return } secret password shown true // Long enough to read or type across, and not a minute more. let work DispatchWorkItem { conceal() } hide?.cancel() hide work DispatchQueue.main.asyncAfter(deadline: .now() 15, execute: work) } }Vault.prove底层是LAContext().evaluatePolicy(.deviceOwnerAuthentication)——也就是 macOS 本身的那道门Touch ID、Apple Watch 或账户密码系统怎么说就怎么算。密码只在屏幕上停留 15 秒然后连secret变量一并清空conceal()里secret nil这是全代码里唯一的秘密持有点。复制的路径更讲究Browser.copy(_:)在生物识别通过后把密码写入剪贴板时同时打上org.nspasteboard.ConcealedType与TransientType两个标记——前者告诉剪贴板管理器别收进历史后者让密码在 90 秒后自动从剪贴板消失。一个面向别人可能看到你屏幕的场景连密码的位数都不会暴露面板上永远是十个点行不知道自己存的是什么直到秘密被读出来。只在登录真正成功后保存保存时机同样拒绝抢跑。表单脚本 Forms.swift 监听 submit、回车与按钮点击把用户名密码桥接给浏览器Tab.swift 的sentSignIn先记下刚刚发出的登录settleSignIn则在页面跳转后确认密码框已经消失——即登录真的成功了——才触发保存询问45 秒内有效。密码框还在说明服务器拒绝了此时弹出的保存offer 存的是错密码。私密标签页、扩展自己的页面、用户说过never的站点、以及已被密码管理扩展接管的保存全部被排除在 offer 之外。自动填充同样克制点击输入框才从输入框下方挂出账户列表绝不主动填。Passkeys 五重校验从接管到调用系统 AuthenticationServices为什么一个浏览器要自己扛下整个 ceremonyPasskeys 在非 Safari 浏览器上的默认路径有个隐蔽的坑。文件头注释记录了一次真实的踩雷2026 年 9 月 24 日把 conditional mediation 交给 WebKit它会让 macOS 的 AuthenticationServicesAgent 持有一个 AutoFill 操作不释放一旦 Search 中途退出agent 就会拒绝此后的一切 passkey 请求报Request already in progress for specified application identifier所有站点登录全部失败直到重启 Mac。于是 Search 的决定是自己扛 ceremony像 Chrome 和 Firefox 在 Mac 上做的那样从页面收下请求逐项校验再通过专为浏览器设计的 API 交给 AuthenticationServices。五重校验每一道都针对一类攻击Passkeys.swift 的perform是完整的安检线顺序严格安全上下文只有https或本机localhost/127.0.0.1才放行否则NotAllowedError——明文页面上任何人都能改写请求前台焦点NSApp.isActive caller.window?.isKeyWindow后台标签页、后台窗口、乃至 Search 自身被遮挡时都不允许弹出系统面板盖在你正在看的内容之上frame 来源caller.mainFrame || caller.pageHost host跨站 iframe 的请求一律拒绝——另一个站点的 frame 不能替这个页面索要 passkeyRelying Party 归属fits(rp, host)要求 RP ID 是当前域名本身或其上级可注册域后缀且拒绝com、co.uk、github.io这类公开后缀publicSuffix直接动态加载了 CFNetwork 里_CFHostIsDomainTopLevel的私有符号没有它页面自己的 host 就是它唯一能拿到的 RPchallenge 必填guard let challenge Passkeys.data(body[challenge]), !challenge.isEmpty。校验通过后clientData 由 Search 自己写——origin 取的是 WebKit 报告的 frame origin从来不是页面自述的那个。这正是钓鱼防护的落点页面说什么都不算浏览器看见的才算数。权限链entitlement 系统隐私开关能走到系统层前提是两道权限。一道在构建期Prefs.entitledToPasskeys通过SecTaskCreateFromSelf读取运行进程自身的签名检查com.apple.developer.web-browser.public-key-credentialentitlement——profile 文件放在 bundle 里什么都不证明只有签名才算数。另一道在运行时Passkeys.access查询ASAuthorizationWebBrowserPublicKeyCredentialManager的授权状态首次请求时用requestAuthorizationForPublicKeyCredentials弹系统授权回答保存在系统设置里设置面板 Settings.swift 会如实显示三种状态——没 entitlement、被 macOS 拒绝、正常可用。conditional mediation先列清单绝不先弹面板navigator.credentials.get({mediation: conditional})的请求走wait(_:)先用platformCredentials(forRelyingParty:)问系统这台 Mac 为该站点持有哪些 passkey一次无界面的静默查询过滤allowCredentials白名单后最多列出 8 个挂在输入框下方与密码账户并列。在你亲手挑选之前什么都不会弹、什么都不会发生挑中一个之后才为这一个 credential 单独打开系统的 Touch ID / iCloud 钥匙串面板。等待中的请求若遇到页面离开、新请求顶替或标签页关闭都会被妥善终结。页面侧由注入在atDocumentStart的脚本接管navigator.credentials.get/create用 window 事件桥接PasskeyRelay.page/bridge浏览器侧则在PasskeyRelay里拿到message.frameInfo.securityOrigin——frame 来源由 WebKit 说了算事件本身说了不算。系统调用层还做了双路并行平台 passkeymacOS 15.0 起的 PRF 扩展也在这里挂上与安全密钥ASAuthorizationSecurityKeyPublicKeyCredentialProvidermacOS 14.4同时发起USB/NFC/BLE 传输逐项映射。回传的 attestation object 用一段自写的轻量 CBOR 解析器拆解把 P-256 与 Ed25519 公钥按 WebAuthn 标准重新编码成 DER 交给页面——包括 GitHub 这类库直接调用getPublicKey()的场景。甚至 PRF 扩展的输出都做了端到端保护页面脚本生成一次性 ECDH P-256 密钥对浏览器侧结果用 HKDF-SHA256 AES-GCM 密封后回传没有那把一次性钥匙谁都无法打开。无明文落盘、无遥测这套设计与 Chrome 的账本式存储对比存储模型的分水岭Chromium 系浏览器的密码是账本式的profile 目录下的Login DataSQLite 里每条记录以主密钥加密的 blob 存放主密钥又锁在操作系统的保险库里。这意味着密码最终仍是一个文件里的加密账本读账本、取密钥、解密是三道独立的工序安全边界由浏览器自己的代码维持。Search 直接跳过了整个账本层——秘密只在钥匙串条目里存在浏览器的进程里连一份明文副本都没有。这不只是实现差异而是信任模型差异加密、解锁、存储全部由操作系统完成浏览器只负责问系统要。连带的好处是迁移成本趋近于零换机、重装、备份钥匙串跟着系统走即便有人拿到了 Application Support 目录里面也只有历史、书签这类 JSONREADME.md 的隐私表格写得很清楚密码一个字节都不在。导入路径反而成了账本式存储的活证据有意思的是这个仓库里最生动的Chrome 账本证据来自导入功能本身。Import.swift 为了把用户从其他浏览器带过来不得不实现完整的逆向读取Chromium 系走Login DataSQLite encrypted_value字段、Firefox 走logins.jsonkey4.db从 key4.db 解出主密钥、用空主密码校验、再逐条解密甚至要连带复制-wal/-shm旁挂文件才能读到最新写入的密码——这正是账本式存储的日常样貌。导入完成后所有条目统一落进钥匙串Vault.take(csv:)对 Safari 导出的明文 CSV 尤其谨慎读完即弃、不留副本界面还会专门提示导出文件里的密码是明文请立即删除。这套方案还有一层签名级隔离钥匙串按应用签名区分条目自己./build.sh打出来的未签名 build 与官方发布版各占一格你自己的 build 的密码与签名版 Search 的互不相通。没有遥测比没有同步更进一步无同步只是不把数据送出去无遥测则是不把任何行为送出去。Search 的隐私承诺是离开 Mac 的只有你主动请求的页面、页面图标以及每天一次检查更新的小请求。密码面板、passkey ceremony 全程无日志记录nothing is ever loggedOSLog 只记事件计数与 refused 原因不记秘密。对比 Chrome 生态中与账号体系捆绑的密码同步、密码安全检查这类云端功能这里的取舍不是做得更少而是把安全边界重新画在了本机操作系统这条线上——浏览器退回到门童的角色验证你是谁、把请求递给系统、把系统的答案递回页面仅此而已。从钥匙串条目的标签隔离到显示密码时的生物识别从五重校验后接管 Passkeys到把 clientData 的 origin 牢牢握在 WebKit 手里——3MB 的体积没有省掉任何一道安全工序它只是把每道工序都推给了 macOS 本身。密码安全做到系统级本质上是承认一个朴素的事实浏览器不应该是秘密的主人它只该是秘密的搬运工。【免费下载链接】SearchA small, fast WebKit browser for macOS, by Office Commun.项目地址: https://gitcode.com/gh_mirrors/search59/Search创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

MySQL用户创建与授权实战:从CREATE USER到GRANT权限管理

MySQL用户创建与授权实战:从CREATE USER到GRANT权限管理

很多人刚开始用MySQL的时候,最容易在用户权限这个环节卡住。明明CREATE USER执行成功了,GRANT也没有报错,可换台机器一连接就是Access denied,或者能连上了却什么都干不了。这个问题说大不大,说小不小,但它…

2026/10/11 22:28:20 阅读更多 →
Agent技能工程:可验证、可监控、可复用的智能体能力单元设计

Agent技能工程:可验证、可监控、可复用的智能体能力单元设计

1. “agent-skills”不是新词,而是智能体能力工程的实践切口“agent-skills”这个词乍看像某个开源库的包名,或是某次技术分享里一闪而过的术语缩写。但过去两年在多个跨领域项目中反复遇到它——不是作为概念被宣讲,而是作为实际开发中必须拆…

2026/10/11 22:27:17 阅读更多 →
模塑玻璃瓶缺陷识别数据集:28类缺陷与YOLOv5实战

模塑玻璃瓶缺陷识别数据集:28类缺陷与YOLOv5实战

简介:这份资源是面向工业质检与计算机视觉方向的模塑玻璃瓶缺陷识别数据集,适合从事缺陷检测算法研发、YOLO模型训练及产线视觉方案验证的工程师与学习者使用。数据集覆盖黑点、泡泡颈、破损、刮痕、裂缝等28类常见玻璃瓶缺陷,标注信息完整&a…

2026/10/11 22:27:17 阅读更多 →

最新新闻

Vibe Coding 的边界:从“70% 问题“到“80% 墙“,AI 编程五大局限性与人机分工深度解析

Vibe Coding 的边界:从“70% 问题“到“80% 墙“,AI 编程五大局限性与人机分工深度解析

文档教程Vibe Coding示例工程 【免费下载链接】vibe-vibe The First Systematic Vibe Coding Open-Source Tutorial | From Zero to Full-Stack, Empowering Everyone to Build Products with AI | Live at: www.vibevibe.cn ;首个系统化 Vibe Coding 开源教程 | 零…

2026/10/12 0:53:26 阅读更多 →
不用模拟器也能玩PS5游戏?拆解AnyPS5的“非模拟器魔法“:relinker重链接+PRX库+RDNA到SPIR-V

不用模拟器也能玩PS5游戏?拆解AnyPS5的“非模拟器魔法“:relinker重链接+PRX库+RDNA到SPIR-V

不用模拟器也能玩PS5游戏?拆解AnyPS5的"非模拟器魔法":relinker重链接PRX库RDNA到SPIR-V 【免费下载链接】AnyPS5 Tool for automatic PS5 executables porting to Linux and Windows 项目地址: https://gitcode.com/GitHub_Trending/an/Any…

2026/10/12 0:53:26 阅读更多 →
基于A星算法的无人机三维路径规划Matlab实现与优化

基于A星算法的无人机三维路径规划Matlab实现与优化

做无人机的人基本都绕不开路径规划这道坎。“基于A星算法的无人机三维路径规划算法研究(Matlab代码实现)” 这个题目看着规整,但真正落地的时候,坑比想象的多:地图怎么建、邻居节点怎么扩展、启发函数怎么写才能既快又…

2026/10/12 0:51:25 阅读更多 →
VS Code 中直接使用 Codex 教程及连接失败解决方案:TaoToken 统一 Key 接入与排错实录

VS Code 中直接使用 Codex 教程及连接失败解决方案:TaoToken 统一 Key 接入与排错实录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 0:50:24 阅读更多 →
企业 Agent 提示词注入防御实战:双重护栏与对抗语义检测

企业 Agent 提示词注入防御实战:双重护栏与对抗语义检测

在企业将多智能体(Multi-Agent)系统接入客服咨询、内部知识检索或自动化办公流后,安全攻防的对抗维度发生了一场根本性范式转移:传统的 SQL 注入或跨站脚本攻击(XSS)正在退居二线,而以自然语言为…

2026/10/12 0:47:23 阅读更多 →
Cursor怎么使用:3分钟上手Cursor键盘快捷键速查,用TaoToken统一Key接入GPT4与Claude 3.5辅助编程

Cursor怎么使用:3分钟上手Cursor键盘快捷键速查,用TaoToken统一Key接入GPT4与Claude 3.5辅助编程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 0:46:23 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →