添加到 Chrome

工作原理

面向安全审阅者的技术说明。这里的每一条都可以对照源码核实——包括那些对我们不太有利的部分,我们选择写出来而不是略过。

架构

没有后端。本扩展是一个 Manifest V3 的 Chrome 扩展,使用 OTPAuth 在本地生成 TOTP/HOTP 代码。我们不运营服务器,不保存账户,也没有任何渠道能让用户数据传到我们手里。

既然没有服务器,也就没有服务端密钥材料、没有密钥托管,更没有由我们掌控的找回途径。如果用户忘记密码又丢失了恢复码,我们无能为力——这是设计使然。

加密

密码保护是可选项,默认关闭。开启后:

加密算法
AES-256-GCM,每条记录、每次重写都使用随机 96 位 IV
密钥派生
PBKDF2-HMAC-SHA256,600,000 次迭代,128 位随机盐(遵循 OWASP 建议)
主密钥
256 位,由 crypto.getRandomValues 一次性生成;密码只用于包装它
指纹
在 HKDF 派生的子密钥下使用 HMAC-SHA256,用于跨设备合并记录
解锁密钥的存放位置
chrome.storage.session——仅存于内存,从不写入磁盘,浏览器关闭即清除,内容脚本无法触及
自动锁定
每次打开时/闲置 5、15、60 分钟后/直到浏览器关闭
实现方式
只用 WebCrypto。没有任何自行实现的密码学原语,也不打包任何加密库。

为什么密钥分两层

数据从不直接用密码派生出的密钥来加密。记录由一个随机主密钥加密;PBKDF2 的输出只负责包装这个主密钥。由此带来两点结果,两点都很重要:

  • 更改密码只重写 32 字节,而不必把每条记录、每份备份、每个导出文件重新加密一遍。存储系统丢数据,往往正是发生在这种批量重写的时候。
  • 160 位的恢复码可以独立包装同一个主密钥,所以忘记密码仍有救。恢复码只显示一次,必须重新输入以确认,且每次使用后都会更换。在用户确认之前,不会向磁盘写入任何内容。

哪些加密,哪些不加密

开启密码保护后,除标识符和指纹外,整条账户记录都会被加密——服务名称也在其中,因此即便配置文件被窃取,也看不出用户在哪些服务上有账户。启用时,扩展会先加密记录,再通过解密比对来校验,确认无误后才删除所有明文副本:浏览器本地存储、同步存储,以及全部七份轮转备份快照。

直说无妨,因为这关系到你的评估:

  • 在密码保护关闭时,账户以未加密形式存储;若 Chrome 同步处于开启状态,还会通过用户自己的 Google 账号进行同步复制。这些数据永远不会到我们这里,但 Google 会持有。同步可以关闭,关闭时也会一并清除已经同步过去的内容。
  • 按站点记录的使用历史——哪个账户用在哪个域名上——保存在本地,在收集过程中并不受保险库保护。启用密码保护会删除它;也可以单独将其关闭。

威胁模型

可以防住

  • 浏览器配置文件目录被窃取或复制
  • 批量外传浏览器数据的信息窃取型恶意软件
  • 有人物理接触到无人看管的电脑
  • 账户记录经 Chrome 同步流向 Google
  • 备份文件丢失或被窃(受密码保护的导出文件)

防不住

  • 保险库处于解锁状态时,以用户身份运行的恶意软件
  • 在输入过程中截取密码的键盘记录器
  • 已被攻陷的浏览器或操作系统
  • 这些验证码所对应的第三方服务本身被攻破

简而言之:它保护的是静态存储的数据。对于使用期间已经落入攻击者控制的设备,它无法防护,也做不到防护。

权限

清单文件只声明了两项权限,且不含任何主机权限:

storage
账户与设置存于本地存储,解锁后的密钥存于会话存储,另有可选的同步副本
activeTab
读取当前标签页的主机名以突出显示匹配的账户;当用户从屏幕扫描二维码时截取该标签页画面

没有任何内容脚本,没有 tabscookieswebRequest 权限,也没有可供网页访问的资源。本扩展无法读取或修改任何页面的内容。

摄像头

用摄像头扫描二维码时,运行的是在标签页中打开的扩展页面,而不是弹出窗口——弹出窗口一旦失去焦点就会被销毁,而权限提示恰恰会夺走焦点。这无需在清单文件中声明任何权限:它使用浏览器标准的摄像头授权提示,按扩展来源授予,可在网站设置中撤销,并且在用户打开扫描器之前绝不会请求。视频在本地解码,从不传输也不存储。

外发网络请求

正常使用时扩展不会发出任何自动请求,而且 Manifest V3 禁止远程代码。它可能建立的全部连接如下:

主机何时是否携带用户数据?
worldtimeapi.org
timeapi.io
时钟偏差检查,带缓存,失败时静默跳过。时钟偏了 TOTP 就会失效。
authenticator.sh安装时打开欢迎页;卸载或评分时打开反馈页。否(仅普通 Web 服务器日志)

字体、脚本、样式和图片都不会从第三方主机加载。渲染界面所需的一切都随扩展包一起提供。

验证我们发布的内容

以上内容都不必只凭信任。扩展是开源的,每个版本都可复现:

  1. 从 Chrome 应用商店下载已发布的 .crx 并解压
  2. 切换到对应的 git 标签
  3. 在 Node 20 LTS 上执行 npm ci && npm run build
  4. 把得到的 dist/ 与解压出来的包进行比对

每个 GitHub 版本都会随附构建产物 dist/ 中每个文件的 SHA-256,文件名为 SHA256SUMS-v<version>.txt,采用 sha256sum 格式,所以第 4 步只需运行一次 sha256sum -c。差异应当仅限于压缩包内的文件顺序,以及不同 Node 补丁版本下压缩输出中的空白字符。

运行时依赖刻意保持很少——OTPAuth、React、jsQR、Zustand、Framer Motion 和 Lucide——并由提交入库的 lockfile 固定版本。如有需要,可提供 CycloneDX 格式的 SBOM。

查看源码

我们没有的东西

我们是一家独立的小团队。如果下面任何一项是贵方流程中的硬性要求,与其评估进行到第三周才发现,不如现在就知道:

  • 没有 SOC 2、ISO 27001 或同类认证
  • 迄今未委托第三方进行渗透测试
  • 没有付费的漏洞赏金计划

我们能提供的是:完全公开的源码、可验证的构建、最小化的权限面,以及根本不存在、也就无从保存你数据的服务端设施。

联系我们

漏洞报告与安全问题请联系 security@authenticator.sh。我们的披露政策、适用范围、响应时限和安全港条款见安全政策页面;哪些数据会被保存、哪些会离开设备,则写在隐私政策中。

我们乐于填写书面的供应商评估问卷,也可以陪同安全团队一起走查代码。

凡与安全无关的事项——安装、账户找回、部署中的计费问题——请见支持页面。请不要把漏洞报告发到那里;那个邮箱不按机密方式处理。