Calcifer Calcifer 2 Calcifer 3 Calcifer 4
Teg

2Password Chrome 浏览器插件开发实战

2026/03/26 18:39 7 次阅读 王梓
打赏
✸ ✸ ✸

2Password Chrome 浏览器插件开发实战:从 Manifest V3 到 Touch ID 生物认证的完整实现

这是一篇 Chrome 浏览器扩展的完整开发实战。2Password 是一个完全本地运行、数据自主可控的浏览器密码管理器插件——安装到 Chrome 后,它能自动识别登录表单、一键填充账号密码、生成 TOTP 验证码,并通过 macOS Touch ID 保护所有数据。不依赖任何云服务,没有后端服务器,所有加密和存储都在浏览器本地完成。本文从 Chrome 扩展的架构设计(Manifest V3 + Service Worker + Content Script + Native Messaging)到每项核心功能的实现细节,完整拆解整个浏览器插件系统。

一、项目背景与技术选型

最终效果一览(左:自动填充 + 右:添加/编辑 + 下:自动登录成功)

2Password Chrome 扩展最终效果

密码管理器的核心诉求只有两个字:安全便捷。这两者天然矛盾——越安全往往越不方便。2Password 的设计目标就是在不依赖云端的前提下,通过浏览器扩展的原生能力和系统级集成来平衡这对矛盾。

2Password 是一个跨平台密码管理器系列,此前已经完成了两个平台的实现:

而本文介绍的 Chrome 浏览器扩展是第三个平台,也是最复杂的——它需要在浏览器的沙箱环境中实现与桌面端同等的安全能力,同时还要自动识别网页表单、在任意网站上完成密码填充。技术选型上,几个关键决策:

  • Chrome Manifest V3:Chrome 扩展的最新规范版本,使用 Service Worker 替代 V2 的 background page,更安全、更省资源
  • Web Crypto API:浏览器原生加密 API(window.crypto.subtle),无需第三方加密库,性能最优
  • IndexedDB:浏览器内置的 NoSQL 数据库,支持大容量结构化存储,相比 localStorage 容量更大、支持索引查询
  • Native Messaging:Chrome 官方的原生通信机制,通过 stdin/stdout 与系统级程序交换 JSON 消息,让扩展能调用系统 API
  • Swift:macOS 原生编程语言,直接调用 LocalAuthentication(生物识别)和 Security(Keychain)框架

为什么不用 WebAuthn / FIDO2?因为这些标准依赖服务端,而 2Password 的核心原则是纯本地、零服务端。macOS Keychain + Touch ID 是纯本地方案中最安全的选择。

关于 IndexedDB:上文提到 2Password 用 IndexedDB 存储密码数据。IndexedDB 是浏览器内置的 NoSQL 数据库——可以理解为 Chrome 自带的"本地 SQLite",只不过它存的是 JavaScript 对象而非 SQL 表格。相比更常见的 localStorage,它有三个关键优势:容量大(数百 MB 到数 GB,而 localStorage 只有约 5MB)、支持索引查询(可以按分类、网站快速搜索)、异步操作(不阻塞页面)。数据存在哪?以 macOS Chrome 为例,文件位于 ~/Library/Application Support/Google/Chrome/Default/IndexedDB/chrome-extension_[扩展ID].indexeddb.leveldb/。每个扩展的数据完全隔离;卸载扩展时自动删除;不会通过 Chrome Sync 同步到其他设备——正好符合"零云端"原则。2Password 的数据库叫 password_manager_db,包含 passwords(加密的密码记录)和 history(变更历史)两个对象仓库。

二、整体架构

Chrome 扩展由三大部分组成:Popup(用户界面)、Background(后台服务,即 Service Worker)、Content Script(页面注入脚本,可以读取和修改用户正在浏览的网页 DOM,但与页面自身 JS 隔离运行)。2Password 还多了一层 Native Host(系统原生程序),形成了四层架构:

2Password 四层架构 任意网页(如 github.com) Content Script 表单检测 字段识别 自动填充面板 浮动按钮 DOM 操作 事件模拟 MFA 自动填充 页面跳转监听 Popup(用户界面) popup.html + popup.js + popup.css 密码列表 / 添加编辑 / 搜索过滤 分类管理 / MFA 显示 / 导入导出 Background Service Worker 消息路由 / 状态管理 快捷键监听 / Native 桥接 会话同步 / 密码中转 Services 层(纯 JS,无外部依赖) EncryptionService AES-256-GCM 加解密 PBKDF2 密钥派生 Touch ID 状态管理 StorageService IndexedDB 封装 passwords + history 索引 category/favorite PasswordRepository 加密读写协调 历史记录追踪 搜索与分类过滤 TotpService TOTP 验证码生成 HMAC-SHA1 签名 Base32 编解码 Native Host 层(Swift,编译为独立二进制) TouchIDHost stdio JSON 协议 LocalAuthentication LAContext + Touch ID Security Framework macOS Keychain CRUD deviceKey Touch ID 保护 chrome.storage.local salt(盐值)| touchIdEnabled | sessionToken chrome.storage.session sessionUnlocked | sessionDeviceKey(浏览器关闭即清除) IndexedDB: password_manager_db passwords Store(加密的密码/备注/MFA Secret) history Store

 

三、Touch ID 生物认证实现

 

这是整个项目最有趣的技术点。Chrome 扩展运行在沙箱中,无法直接调用 macOS 的 Touch ID API。Chrome 提供了 Native Messaging 机制来解决这个问题——扩展可以启动一个系统级的原生程序(Swift 编译的二进制文件),通过操作系统的标准输入/输出(stdin/stdout)进行 JSON 通信。这是 Chrome 扩展突破沙箱限制的唯一官方方式。

 

3.1 完整调用链:从点击到指纹验证

 

用户在 Popup 中点击"解锁"后,一条消息要经过 4 层才能到达 Touch ID 硬件。让我们从最上层逐步往下看:

 

Touch ID 完整调用链(4 层穿透) 第 1 层:Popup (popup.js) 用户点击"解锁" → checkTouchIDAvailable() → 发送 {action: "get_key"} 通过 chrome.runtime.sendMessage() 发给 Background Service Worker sendMessage 第 2 层:Background (background.js) 收到 nativeMessage → chrome.runtime.connectNative("com.2password.touchid") 创建与 Swift 程序的连接,port.postMessage({action: "get_key"}) connectNative + postMessage 第 3 层:Swift Native Host (TouchIDHost) stdin 读取 JSON → 解析 action → 创建 LAContext 构建 Keychain 查询字典(含 kSecUseAuthenticationContext: LAContext) SecItemCopyMatching → 触发第 4 层 SecItemCopyMatching 第 4 层:macOS Secure Enclave 系统弹出 Touch ID 对话框 → 指纹传感器采集 → Secure Enclave 比对 → 返回结果 ← 返回路径(逆向逐层回传)→ Swift stdout: {"success": true, "key": "aGVsbG8..."} → Background port.onMessage → Popup callback → deviceKey 整个往返约 500ms-2s(取决于用户手指放置速度),超时阈值设为 10 秒

 

关键细节:Background 层使用的是 chrome.runtime.connectNative()(长连接端口模式),而非 sendNativeMessage()(一次性模式)。这是因为 connectNative 支持超时控制和端口断开监听,更可靠。但 Swift 程序仍然是"处理一条消息就退出"——每次认证请求都是一次新的进程启动。

 

3.2 Native Messaging 二进制协议

 

Chrome 与 Native Host 之间的通信协议很简单但严格:每条消息由 4 字节小端序长度头 + JSON 消息体组成。Chrome 会自动处理这个协议的编码和解码,开发者只需要关注 JSON 消息本身。

 

Native Messaging 二进制协议 Chrome Extension 4 bytes length 00 00 00 3A JSON body {"action":"get_key"} Swift stdin Swift stdout JSON response {"success":true,"key":"..."} 4 bytes length 00 00 01 2F Chrome Extension 协议特点:单次请求-响应模式,Swift 进程处理完毕后立即退出(无长连接保活) 开发者只需处理 JSON,Chrome 自动完成二进制帧的封装与解析

 

3.3 Swift 端 Keychain 查询与 Touch ID 弹出

 

Swift 程序收到请求后,核心操作是构建一个 Keychain 查询字典。关键技术在于 kSecUseAuthenticationContext 参数——它是 Touch ID 弹出的开关:

 

Keychain 查询:Touch ID 弹出的触发机制 Keychain 查询字典 kSecClass = kSecClassGenericPassword kSecAttrAccount = "encryption_key" kSecAttrService = "com.2password.touchid" kSecReturnData = true kSecUseAuthenticationContext = LAContext() /// 这一行是魔法所在 /// 传入 LAContext 后,macOS 会在 /// 读取前自动弹出 Touch ID 对话框 /// 用户验证通过后才返回数据 /// 否则返回 errSecAuthFailed 两种查询方式对比 不传 LAContext SecItemCopyMatching() → 直接返回数据 无 Touch ID 验证 任何进程可读取 传入 LAContext SecItemCopyMatching() → 弹出 Touch ID 需生物识别验证 只有本人可读取 Swift 响应结果 成功: {"success":true, "key":"base64..."} 失败: {"success":false, "error":"..."} → 指纹通过 → 取消/超时/失败 Background 设有 10 秒超时:超时后 port.disconnect() 防止用户忘记操作导致进程挂起

 

核心原理:macOS Keychain 支持对每条记录设置访问控制。当存储时指定了 SecAccessControlCreateFlagUserPresence,后续每次读取都必须通过生物识别或设备密码。Swift 程序通过传入 LAContext 告诉系统"我要做身份验证",系统就会自动弹出认证 UI。这意味着密钥永远不会离开系统安全边界——Chrome 扩展拿到的只是验证通过后的密钥值,无法绕过验证直接获取。

 

3.4 配置文件与安装

 

Chrome 通过一个 JSON 配置文件来发现 Native Host:

 

{
  "name": "com.2password.touchid",
  "description": "Touch ID auth for 2Password",
  "path": "/Users/.../NativeMessagingHosts/touchid_host",
  "type": "stdio",
  "allowed_origins": ["chrome-extension://YOUR_EXT_ID/"]
}

 

这个文件必须放在 ~/Library/Application Support/Google/Chrome/NativeMessagingHosts/,且 allowed_origins 中的扩展 ID 必须与实际匹配,否则 Chrome 会拒绝连接——这是 Chrome 的安全机制,防止恶意网站利用 Native Messaging。

 

3.5 数据安全模型

 

理解 2Password 的安全性,关键是搞清楚什么被保护、用什么保护、存在哪

 

2Password 数据安全模型 什么被加密? password(密码值) notes(备注信息) mfaSecret(TOTP 密钥) title / username / website category / favorite 明文字段用于搜索和域名匹配 即使泄露也无法直接登录账户 (攻击者仍需知道密码才能登录) 用什么保护? 加密层 AES-256-GCM(认证加密) 每条记录独立 IV(12字节随机) GCM 自带完整性校验(防篡改) 密钥层 PBKDF2 派生(100,000 迭代) 固定盐值 + 随机盐值双重保护 暴力破解成本: ~100K × 解密时间 认证层 Touch ID → macOS Keychain Secure Enclave 硬件级保护 deviceKey 不持久化到 JS 可访问的存储 (仅在 Keychain → Swift → Chrome 间传递) 存在哪里? chrome.storage.local salt(16字节) touchIdEnabled 标志 macOS Keychain deviceKey(Touch ID 保护) 系统级加密存储 IndexedDB 加密后的密码记录 密码 + 备注 + MFA Secret chrome.storage.session 会话密钥(浏览器关闭清除)

 

攻击场景分析:假设攻击者获得了用户电脑的文件访问权限:

 

  • 能拿到什么? IndexedDB 中的密文、chrome.storage.local 中的 salt
  • 拿不到什么? deviceKey(在 Keychain 中,Touch ID 保护)
  • 能破解吗? 没有 deviceKey 就无法派生 AES 密钥,密文无法解密。即使用 PBKDF2 暴力枚举所有可能的 deviceKey(2^256 种),100K 迭代的代价使其在物理上不可行
  • AES-GCM 的额外保障:即使知道部分明文(如已知某个密码格式),GCM 模式的认证标签会防止任何密文篡改

 

四、加密体系设计

 

密码管理器的加密方案需要回答三个问题:密钥从哪来怎么加密密钥怎么存

 

术语速览AES-256-GCM — 当前最广泛使用的对称加密方案,256 位密钥,GCM 模式会自动生成"认证标签"来检测密文是否被篡改。IV(初始化向量) — 加密时附加的一段随机字节,确保相同明文每次加密结果不同。PBKDF2 — "基于密码的密钥派生函数",通过反复哈希迭代(10 万次)来增加暴力破解成本。Salt(盐值) — 随机数据,与密钥拼接后一起哈希,防止"彩虹表攻击"。

 

4.1 密钥派生链路

 

2Password 采用"设备密钥 → PBKDF2 → AES 密钥"的两层派生方案:

 

密钥派生链路 deviceKey 32 字节随机数 crypto.getRandomValues() 拼接 拼接固定盐值 "PasswordManagerExtension_v2" PBKDF2 SHA-256 100,000 次迭代 + salt (16 bytes) AES Key CryptoKey 256-bit AES-GCM 密钥存储策略(两种模式) Touch ID 模式(推荐) deviceKey → macOS Keychain(Touch ID 保护) salt → chrome.storage.local 普通模式 deviceKey → chrome.storage.local salt → chrome.storage.local

 

为什么要拼接固定字符串 "PasswordManagerExtension_v2"?这是一种"域名隔离"技术——即使两个应用碰巧生成了相同的 deviceKey,因为拼接字符串不同,最终派生的 AES 密钥也不同,防止密钥碰撞。

 

4.2 加密存储格式

 

每条密码在 IndexedDB 中的存储结构:

 

IndexedDB 密码记录结构 PasswordEntity id: 1 (自增主键) title: "GitHub" (明文) username: "user@email.com" (明文) password: "a3F8kL...mN2pQ:R4sT6uV8wX" (AES-256-GCM 密文:IV) ← 加密存储 website: "https://github.com" (明文) category: "工作" notes: "encrypted...:IV" (加密) mfaSecret: "encrypted...:IV" (加密) ← 加密存储

 

注意只有 passwordnotesmfaSecret 三个字段加密。title、username、website 保留明文,因为自动填充需要根据网站域名匹配密码,搜索功能也需要搜索标题。

 

五、智能表单识别与自动填充

 

自动填充的难点不在于填充本身,而在于准确识别哪个输入框是用户名、哪个是密码。不同网站的表单结构千差万别,2Password 设计了一套评分系统来解决这个问题。

 

DOM(Document Object Model):浏览器将 HTML 文档解析成的树形结构,每个标签对应一个"节点"。自动填充本质上就是:找到代表用户名和密码的 DOM 节点,修改它们的值。不同网站用不同标签名和属性,所以需要"识别"。

 

5.1 字段评分系统

 

每个输入框会根据多个特征获得一个分数,最终选择得分最高的作为目标:

 

登录字段评分系统 输入框特征提取 1. HTML 属性 (attrs) name, id, placeholder className, autocomplete type, aria-label aria-labelledby, aria-describedby 2. 关联标签 (labelText) label[for="id"] 的文本 父级 label 的文本 3. 输入类型 password / text / email tel / url / hidden(disabled) 评分规则(按优先级排序) 密码字段评分 +150 autocomplete="current-password" +100 autocomplete="password" / attrs 含 "password" +30 type="password"(无其他特征) 用户名字段评分 +100 autocomplete="username/email/tel" +60 attrs 含 "user/email/login/account/name/phone" +50 type="email" +40 type="tel" TOTP 字段 +80 attrs 含 "totp/code/otp/mfa/验证码"

 

5.2 自动填充时序

 

从用户按下快捷键到密码填充完成,整个时序如下:

 

自动填充完整时序 时间 用户 Background Content Services IndexedDB 网页 DOM Cmd+Shift+L onCommand sendMessage openPanel() getPasswords 检查解锁 getAll 读取密文 返回 AES 解密 密码列表 渲染面板列表 点击"填充" autofillAndSubmit fillInput(username) focus → value input event change event blur() click 登录按钮 100ms 延迟后自动提交 如有 MFA → 等待跳转 → 检测 TOTP 字段 生成验证码 → 填充 → 提交

 

填充时有一个关键细节:不是简单地设置 input.value,而是依次触发 focus → value → input event → change event → blur。这是因为很多现代前端框架(React、Vue)监听的是事件而非属性变化。如果不触发这些事件,框架的状态不会更新,提交时可能会发送空值。

 

具体来说,fillInput() 函数只做 5 件事:

 

function fillInput(input, value) {
  input.focus();                                    // 1. 聚焦输入框(激活框架状态)
  input.value = value;                              // 2. 设置值
  input.dispatchEvent(new Event('input', {bubbles: true}));   // 3. 模拟输入事件(React onChange)
  input.dispatchEvent(new Event('change'));                    // 4. 模拟变更事件(Vue v-model)
  input.blur();                                     // 5. 失焦(触发 blur 验证)
}

 

其中 bubbles: true 是关键——React 依赖事件冒泡来捕获 input 事件。如果不设置 bubbles,React 的合成事件系统不会接收到这个事件。

 

5.3 三轮降级检测算法

 

不同网站的登录表单千差万别:有的用标准 autocomplete 属性,有的用自定义组件,有的连 <form> 标签都没有。2Password 采用三轮逐步降级的策略,从最可靠的特征开始,到最后的兜底方案:

 

三轮降级检测:从精准到兜底 第 1 轮 HTML 属性 + autocomplete 评分(最可靠) 遍历所有 input → 提取 name/id/placeholder/class/autocomplete/type/aria-* 属性 提取关联 label 文本 → 按评分规则打分 → 密码 +100~150,用户名 +40~100,TOTP +80 覆盖 90% 的现代网站(GitHub、Google 等标准表单) 第 2 轮 兜底密码框查找(第一轮未找到密码时触发) 再次遍历所有 input → 找 type="password" 但未被第一轮匹配的 → 给予 score=20 处理一些旧网站只用 type="password" 但没有其他属性的情况 第 3 轮 兜底用户名查找(仍未找到用户名时触发) 找第一个 type="text" 或 type="email" 的 input → score=10(最低优先级) 处理完全不规范的表单,可能有误判风险但聊胜于无 最终结果:每个候选列表按 score 降序排列,取 score 最高的作为目标字段

 

这种设计确保了"能用高精度方法就不降级"的原则。第一轮通过 autocomplete 属性能精准识别绝大多数标准表单;只有在标准方法失败时,才会使用更激进的兜底策略。

 

5.4 MFA 自动填充:MutationObserver 监听

 

很多网站在用户输入密码后会跳转到 MFA 验证页面。2Password 使用 MutationObserver(浏览器提供的 DOM 变化监听 API,可以检测页面中元素的添加、删除或属性变化)来监听这种页面变化,自动填充 TOTP 验证码:

 

MFA 自动填充流程(MutationObserver) 密码填充完成 检测到 mfaSecret 存在 启动 MutationObserver 监听 document.body DOM 变化 等待:URL 变化 or DOM 变化 每次 URL 变化重置尝试计数器 MutationObserver 回调逻辑 1. 检查 URL 是否变化 → 变化则重置 attempts = 0(页面跳转了,给新一轮机会) 2. attempts++ → 超过 50 次则 disconnect()(防止无限监听) 3. 调用 detectLoginFields() 检查是否有 TOTP 字段 → 有则触发填充 检测到 TOTP 字段 disconnect() 停止监听 生成 TOTP 验证码 delay 500ms(等页面加载) fillInput(totpField, code) delay 200ms → 点击验证按钮 → 清除状态 三重安全阀 ① 最多 50 次 DOM 变更检测 ② 最多监听 5 秒 ③ 填充完成后立即 disconnect + 清除 lastFilledPassword

 

5.5 网站匹配算法

 

自动填充面板打开时,密码列表需要按"当前网站优先"排序。匹配算法支持三级域名匹配:

 

域名匹配规则 密码库中的网站 github.com accounts.google.com example.com 当前页面 github.com/login hostname: github.com 匹配优先级 1. 精确匹配 (最高分) 2. 二级域名 (example.com) 3. 三级域名 (test.example.com)

 

5.6 登录按钮智能检测

 

自动填充的最后一步是点击登录按钮。2Password 用两层策略查找按钮:

 

第一层:语义匹配。遍历页面所有 buttoninput[type="submit"]a[role="button"],检查文本内容是否包含 登录/login/sign in/提交/submit 等关键词。支持中英文。

 

第二层:表单兜底。如果语义匹配没找到,查找当前表单内的 button[type="submit"]input[type="submit"]

 

MFA 页面的按钮检测更严格——先排除包含"返回/back"关键词的按钮(避免误点),再查找包含"验证/verify/confirm"的按钮。

 

六、TOTP MFA 实现

 

2Password 内置了 TOTP(基于时间的一次性密码,Time-based One-Time Password)生成器,完全兼容 Google Authenticator。实现原理:

 

TOTP 验证码生成流程 Base32 Secret JBSWY3DPEHPK3PXP Base32 解码 → Uint8Array key 时间步计算 T = floor(now/30) HMAC-SHA1 HMAC(key, T) → 20 bytes Web Crypto API 动态截取 offset % 10^6 847 293 每个验证码有效期 30 秒 每 30 秒自动生成新码 secret 存储在 IndexedDB(加密) 兼容 Google Authenticator 扫码 ⏱ 剩余 17 秒自动刷新 数学原理 code = (HMAC-SHA1(key, T))[offset : offset+4] % 10^6 → 6位数字

 

七、密码生成器与强度检测

 

2Password 内置了密码生成器,支持自定义长度和字符类型,并提供实时强度评估。密码生成使用 crypto.getRandomValues()(CSPRNG,密码学安全伪随机数生成器,从操作系统硬件熵源收集随机性,生成的随机数无法被预测),而非 Math.random(),确保密码的随机性达到密码学安全级别。

 

7.1 密码生成算法

 

密码生成器工作原理 用户配置 length: 16(默认) includeUppercase: true includeLowercase: true includeNumbers: true includeSymbols: true 字符池大小: 94 构建字符池 A-Z(26 个大写) a-z(26 个小写) 0-9(10 个数字) !@#$%...(32 个符号) charPool = "Aa1!..."(94字符) CSPRNG 采样 crypto.getRandomValues (Uint32Array(16)) 每个随机数对字符池取模: charPool[random % 94] 重复 16 次 注意: 存在微小取模偏差 输出 xK3#mP9 @nL2&qR 5vW8*jT = 16 位密码 94^16 种可能 约 2^105 熵

 

7.2 密码强度评估

 

强度评估采用多维度评分(满分 8 分),从"弱"到"非常强"共四个等级:

 

评分维度 条件 得分
长度 ≥8 / ≥12 / ≥16 / ≥20 各 +1(最高 +4)
字符多样性 大写 / 小写 / 数字 / 符号 各 +1(最高 +4)

 

评分与颜色映射:0-1 分 → 弱(红) | 2-3 分 → 中等(橙) | 4-5 分 → 强(绿) | 6-8 分 → 非常强(蓝)

 

八、会话保持机制

 

每次打开扩展都要 Touch ID 认证会非常烦。2Password 通过 chrome.storage.session(Chrome 扩展专用的内存级键值存储,浏览器关闭后数据自动清除)实现会话保持:解锁一次后,浏览器关闭前都不需要再次认证。

 

会话保持:Popup ↔ Background 状态同步 Popup 首次解锁 1. Touch ID → 获取 deviceKey 2. 派生 AES Key → 解密密码 3. chrome.storage.session.set {sessionDeviceKey, sessionUnlocked: true} sync Key+ Salt Background 同步 1. 接收 key + salt 2. 更新 passwordRepository 状态 3. isUnlocked = true 不再触发 Touch ID(避免双次认证) 后续打开扩展的恢复流程 Popup init → 检查 session.sessionUnlocked && session.sessionDeviceKey → 恢复 deviceKey → 派生 AES Key → 直接进入主界面 ✅ 无需再次 Touch ID ❌ 浏览器关闭后 session 清除,重新打开需 Touch ID

 

这里有一个容易踩的坑:Popup 解锁后,如果 Content Script 通过 Background 请求密码列表,Background 必须知道已解锁。所以 Popup 解锁后必须通过 syncUnlockState 消息同步密钥给 Background,而不是让 Background 自己再触发一次 Touch ID(否则用户会看到两次认证弹窗)。

 

九、数据完整性与历史追踪

 

每次密码的增删改都会自动记录历史,支持查看旧密码值。这对回溯"上个月我改了什么密码"非常有用。

 

历史记录追踪机制 密码表 (passwords) id: 1 title: "GitHub" password: [AES加密] updatedAt: 1711459200000 ← 只存最新状态 历史表 (history) action: "修改" account: "user@email.com" oldPassword: [AES密文] website: "github.com" ← 记录变更前后 记录的三种操作 ➕ 添加 - 记录新密码 ✏️ 修改 - 记录旧密码值 🗑️ 删除 - 记录被删的密码 密码也会加密存储

 

十、技术要点总结

 

技术点 实现方案 设计考量
加密算法 AES-256-GCM (Web Crypto API) 浏览器原生,零依赖,GCM 模式自带完整性校验
密钥派生 PBKDF2-SHA256, 100K 迭代 防暴力破解,deviceKey + salt + 固定字符串三重保护
Touch ID Native Messaging + Swift + Keychain Chrome 沙箱外运行,系统级安全,单次请求响应
数据存储 IndexedDB (密码) + chrome.storage (密钥) IndexedDB 大容量,session storage 自动过期
表单识别 多特征评分系统 (autocomplete/attrs/label) 覆盖主流框架,从最可靠到兜底逐级降级
MFA TOTP (HMAC-SHA1, 30s 周期) 兼容 Google Authenticator,secret 加密存储
会话保持 chrome.storage.session + 状态同步 避免双次 Touch ID,浏览器关闭自动失效
密码生成 crypto.getRandomValues (CSPRNG) 密码学安全随机数,多维度强度评估

 

2Password 虽然是一个个人项目,但在安全设计上借鉴了业界最佳实践。从加密方案到密钥管理,从表单识别到会话保持,每个细节都经过仔细考量。整个项目零外部依赖,纯原生 JavaScript 实现,代码量不到 2000 行,但功能完整度不输主流密码管理器的核心功能。

 

核心价值:完全本地运行 + Touch ID 系统级保护 + 浏览器内自动填充 + MFA 一站式管理。代码开源,数据自主,安全透明。

 


 

相关文章

 

✸ ✸ ✸

📜 版权声明

本文作者:王梓 | 原文链接:https://www.bthlt.com/note/369920595-Teg2Password Chrome 浏览器插件开发实战

出处:葫芦的运维日志 | 转载请注明出处并保留原文链接

📜 留言板

留言提交后需管理员审核通过才会显示