Appearance
调研:网站登录弹出填充、密码生成、管理界面(2026-11-16)
结论:没有一条路径能覆盖所有浏览器和系统。v1 做 Manifest V3 浏览器扩展(Chrome / Edge / Firefox),通过 native messaging 小程序连到 Rust 后台进程。密码生成放在 Rust 核心里,管理界面用 Tauri v2。各系统自带的自动填充以后逐个加。
A. 自动填充
浏览器扩展 + native messaging:跨平台主路径
- KeePassXC-Browser(GPL,只能参考):
- 用 NaCl box,三对密钥:每次会话的客户端密钥、每次会话的宿主密钥、用户只需确认一次的长期身份密钥(
associate)。 - 一个很小的代理程序把 stdio 转发到本地 socket。
- 用 NaCl box,三对密钥:每次会话的客户端密钥、每次会话的宿主密钥、用户只需确认一次的长期身份密钥(
- Bitwarden(GPL,只能参考):
- 扩展生成 RSA 密钥对,桌面端用它加密一把共享密钥发回来,用户核对指纹。
- 转发程序是用 Rust 写的。
- Native messaging 的规则:
- 宿主清单里要列出允许的扩展 ID,不能用通配符。
- 调用方的 origin 作为 argv[1] 传入。
- 宿主发给浏览器的单条消息上限 1 MB。
- 清单在 macOS 和 Linux 上放在各浏览器自己的目录,在 Windows 上写注册表。
- 识别登录表单(都是启发式):
- KeePassXC 把用户名和它之后的第一个密码框配对,尊重
autocomplete=username/new-password,还能识别"一格一位"的 TOTP 输入框。 - Bitwarden 把
autocomplete标记和关键词组合起来判断:登录、注册、改密码、银行卡,再加提交按钮的关键词。
- KeePassXC 把用户名和它之后的第一个密码框配对,尊重
- 页面内弹出菜单的隔离:
- Bitwarden:封闭的 shadow root 里放一个扩展页面的 iframe,用
popover="manual"浮在页面最上层,z-index 设为 2147483647;再用 MutationObserver 监视 html 和 body,页面一改透明度或可见性就关掉菜单。 - KeePassXC:封闭的 shadow root,加最小透明度检查和
isTrusted检查。 - 这些都是为了应对 DEF CON 33 披露的 DOM 点击劫持,当时 11 个密码管理器里有 10 个中招。
- Bitwarden:封闭的 shadow root 里放一个扩展页面的 iframe,用
- 域名匹配:
- KeePassXC 要求主域名相同:要么主机名完全一致,要么网站主机名以
.条目主机名结尾。端口和协议也要检查。 - Bitwarden 用 tldts,提供多种模式:Domain(默认)、Host、Starts-with、Exact、Regex、Never。
- KeePassXC 要求主域名相同:要么主机名完全一致,要么网站主机名以
- Safari 没有 stdio 宿主。扩展必须打包在 Xcode App 里,消息经
sendNativeMessage发给 App 扩展。 - Linux 上 Flatpak 和 Snap 版浏览器用不了 native messaging(Ubuntu 的 Firefox Snap 例外),相关 portal 至今没合并。
系统级自动填充(以后再加)
macOS / iOS: ASCredentialProviderViewController。
- 支持范围:密码从 macOS 11 起,通行密钥从 14 起,验证码从 15 起。原生 App 里填密码也走同一个扩展。
- 代价:要写 Swift 沙盒
.appex,加 App Group 和描述文件。用 Developer ID 分发即可,不必上 App Store。 - 参考:Bitwarden 的这个扩展目前在代码里只支持通行密钥。KeePassium(GPL)和 Strongbox(AGPL)有完整实现。
浏览器用不用 macOS 的系统 provider:
| 浏览器 | 情况 |
|---|---|
| Safari | 用 |
| Chrome | 没找到证据表明它会用第三方 provider 填密码(未核实) |
| Firefox / Edge / Arc | 没找到证据(未核实) |
Windows 11: 从 2025 年 11 月起有通行密钥插件 API。只支持通行密钥,要求 MSIX 打包,没有填密码的 API。
Linux: 没有系统级 API,只能靠浏览器扩展。
B. 密码生成
可以直接复用的数据和库:
- apple/password-manager-resources(MIT):
password-rules.json:各网站的密码规则。shared-credentials.json:共用账号的域名组。change-password-URLs.json:改密码页面地址。websites-that-append-2fa-to-password.json:要求把验证码接在密码后面的网站。- 做法:把这些数据收进仓库,用 CI 定期更新。
password-rules-parser1.1.0(Apache-2.0,1Password 出品):解析上面的规则,也能解析页面上的passwordrules属性。
随机数和强度:
rand0.10。注意改名:OsRng变成了SysRng,thread_rng()变成了rand::rng()。用random_range做无偏采样。- 保证每类字符的最少数量:先把必需的字符放进去,再整体打乱。
- 口令短语用 EFF 长词表(CC-BY-3.0,要注明出处)。
- 生成的密码显示精确熵值(log2);用户自己输入的密码用
zxcvbn3.1.1(MIT)估算强度。 - 参考 Bitwarden 生成器的选项:每类字符最少几个、排除易混淆字符(
I O l 0 1)。
C. 管理界面
别人怎么选:
| 项目 | 界面技术 |
|---|---|
| KeePassXC | Qt |
| Bitwarden | Electron |
| KeePassium / Strongbox | 原生 |
| Padloc(AGPL) | 有 Tauri 版 |
用 Tauri 的密码管理器大多是个人小项目。
Tauri v2(MIT/Apache):
- 版本:最新稳定版 v2.12.5(2026-10),v3 在 alpha。
- 安全:v1 和 v2 都经过 Radically Open Security 审计。
- 权限:capability 系统能限制 webview 能调用哪些 IPC。
UniFFI(MPL-2.0,可以作为依赖):
- 版本 0.32。
- 使用者:Firefox、Bitwarden SDK、Proton Pass 移动端。
- 成熟度:可用于生产,但升级时可能有破坏性变化。
推荐的 v1 架构
后台进程:
- 监听 Unix socket 或 Windows 命名管道,并校验调用方进程。
Native messaging 宿主:
- Rust 写的 stdio 转发程序,校验 argv[1] 里的 origin。
- 配对:X25519 + XChaCha20-Poly1305,在界面上确认一次。用的是 KeePassXC 的思路,但代码自己写。
浏览器扩展: Manifest V3,TypeScript,一套代码支持 Chrome / Edge / Firefox。
- 匹配逻辑放在 Rust 核心里,不放在扩展里。默认按 eTLD+1 匹配,用
pslcrate(MIT,包含私有段);另有主机后缀匹配和精确匹配;再加上 PMR 的共用账号域名组。 - 页面内菜单:封闭 shadow root + 扩展页 iframe + popover,并检测页面篡改。只在用户真实点击后填充,绝不在页面加载时自动填。
- 提交表单后,在隔离的横幅里提示保存或更新。
生成器: 放在核心里,扩展、管理界面和 agent 都调用同一份。
管理界面: Tauri v2,只是后台进程的一个客户端。
- 明文留在 Rust 侧,按需显示或复制。
- 剪贴板由 Rust 负责定时清空。
- CSP 和 capability 要配严。
要注意的坑
- 点击劫持: 透明度和可见性监视、封闭 shadow DOM、iframe + popover 顶层、
isTrusted检查。触发填充的那次点击绝不能落在页面自己的元素上。 - 子域名:
- 条目
example.com可以匹配a.example.com,反过来不行。 - 用 PSL 私有段,保证
x.github.io不会匹配y.github.io。 - 统一 punycode,检查端口,禁止 HTTPS 降级到 HTTP。
- 条目
- iframe: 跨域 frame 只有在它自己的 origin 和凭据匹配时才填,否则给出警告。
- HTTP Basic 认证: 用
webRequest.onAuthRequired加webRequestAuthProvider权限;代理认证也要处理。 - TOTP 填充: 处理
one-time-code、"一格一位"的输入框,以及要求把验证码接在密码后面的网站。 - Native messaging 的限制: 单条消息 1 MB 上限;Linux 的 Flatpak / Snap 浏览器用不了;Windows 上要写注册表。
- Tauri 打包 macOS
.appex: 没有现成办法,要自己写嵌入和重签名的步骤(未核实)。