代表性面试主题

前端面试:如何存储不可导出的 Web Crypto 密钥?

前端困难
Offer.cc 编辑团队发布 更新

题干

Web 应用要加密本地草稿,避免 XSS 直接从存储读取明文密钥。你如何设计,还存在哪些限制?

题目与场景

应用在浏览器中加密本地数据,并希望跨会话使用密钥。设计应降低密钥暴露,但必须说明限制:同源脚本仍可能调用允许的操作,用户也可能失去恢复能力。

面试官在考察什么

  • 理解安全上下文、CryptoKey 可导出性和密钥用途。
  • 分离加密数据存储、密钥恢复与威胁建模。
  • 解释浏览器密码学不能让 XSS 无害。

作答前的澄清问题

  • 威胁是被盗存储记录、被动攻击者,还是主动同源脚本?
  • 注销、设备丢失、密码重置和浏览器配置删除后数据是否必须保留?
  • 能否用用户口令或 WebAuthn 凭据解锁包裹密钥?
  • 需要哪些算法、用途、浏览器支持和迁移路径?

30 秒回答框架

我会要求 HTTPS,生成或导入 CryptoKey,把 extractable 设为 false,只授予必要用途,并把浏览器管理的密钥句柄存入 IndexedDB,而不是导出原始字节。密文、随机数、算法参数和版本与密钥分开保存。同时配置 CSP、依赖审查和恢复方案,并说明应用打开时同源脚本仍可能调用解密 API 或读取内存中的明文。

分步深挖

1. 定义威胁模型

不可导出性限制意外导出和部分存储盗窃路径,但不能阻止在同源执行的脚本请求应用解密或读取内存明文。承诺安全性前先声明边界。

2. 创建或导入密钥

使用受支持算法和专用用途,例如加密与解密。在安全上下文生成密钥,或导入包裹材料并设置目标可导出性。拒绝异常算法参数,不把原始密钥材料放进 localStorage。

3. 安全持久化密文

保存密文、每次加密的新随机数、认证元数据、密钥版本和数据模式版本。使用 AES-GCM 等认证加密,并保证同一密钥下每条记录的随机数唯一。把租户或用户范围放进关联数据,而不是隐含信任决策。

4. 规划恢复与轮换

浏览器配置删除或设备丢失可能让不可导出密钥无法使用。上线前提供明确恢复路径,例如口令派生的包裹密钥或服务端重新加密流程,不能静默降级为明文。密钥版本化并事务性迁移记录。

5. 测试与运营

测试不支持算法、不安全上下文、配额错误、中断写入、随机数复用、版本迁移、注销和恢复失败。配置 CSP、审查依赖、不记录敏感日志,只统计解密失败而不记录明文。

高质量示范回答

“我会要求 HTTPS,生成用途受限且 extractable 为 false 的 CryptoKey,只把浏览器管理的句柄放进 IndexedDB。每条记录保存密文、唯一随机数、认证元数据和密钥版本。由于配置丢失可能导致不可导出密钥无法恢复,我会在上线前定义恢复流程。CSP 与依赖控制能降低主动脚本风险,但同源 XSS 仍可能调用允许的解密操作或读取应用打开时的明文。”

常见失误

  • 把原始密钥放入 localStorage → 存储被盗就能解密 → 持久化不可导出密钥句柄。
  • AES-GCM 复用随机数 → 机密性与完整性可能失效 → 每个密钥和记录使用唯一随机数。
  • 声称解决了 XSS → 同源代码仍能使用应用权限 → 说明主动脚本限制。
  • 跳过恢复设计 → 配置丢失会毁掉数据访问 → 定义包裹、重置和迁移流程。

追问与回答

IndexedDB 能让密钥免受 XSS 吗?

不能。它避免把原始字节放进简单存储 API,但同源脚本仍可能访问数据库或调用应用代码。应配置 CSP、审查依赖并采用现实威胁模型。

用户丢设备后如何恢复?

用用户持有的秘密或恢复凭据派生密钥包裹数据密钥,或通过认证服务端流程重新加密。解释离线与重置取舍,不能静默生成无法解密旧数据的新密钥。

轮换时可以导出密钥吗?

只有策略允许才可以。更推荐生成新密钥,在两个版本都可用时迁移记录;需要包裹时保护包裹密钥并审计转换。

公开来源

同类题目