关于 threat-modeling
面向 Bitwarden 工程团队的安全威胁建模技能,覆盖初步评估并辅助后续审查与验证。结合 STRIDE、数据流图和 Bitwarden 安全定义,强调威胁范围与目标的一致性。
主要功能
- 01生成 Mermaid 数据流图
- 02按 STRIDE 识别威胁
- 03撰写安全定义与目标
- 04检查架构决策记录对齐
- 05评估目标状态与风险
适用场景
- 01为新服务开展初步安全评估
- 02梳理跨服务数据流和信任边界
- 03准备 AppSec 审查材料
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ bitwarden/ ai-plugins --skill threat-modeling安装后在 Claude Code 中输入/threat-modeling确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
examples/data-flow-diagram.mdsecurity-definition-document.mdthreat-catalog.mdreferences/bitwarden-vocabulary.mdsecurity-principles.mdstride-framework.mdwriting-quality-sds.md详细介绍
Bitwarden 的参与模型
Bitwarden 的安全工作采用 4 阶段参与模型。此技能主要支持第 1 阶段(工程团队负责),并协助准备第 2 至第 4 阶段的材料。
第 1 阶段:初始安全评估(工程团队)
- 检查 Bitwarden 的架构决策记录,了解其中是否已有涵盖待审查系统或组件的决策(参见
${CLAUDE_PLUGIN_ROOT}/references/adr-alignment.md)——威胁模型应与已接受的架构保持一致,而不是默默重新推导或与之矛盾 - 创建数据流图(Mermaid)
- 将安全要求与产品要求分开定义
- 提出安全定义(威胁模型 + 安全目标)
- 使用 STRIDE 识别初始威胁(参见
references/stride-framework.md)
第 2 阶段:AppSec 团队审查(AppSec + 工程团队)
- 提前分享数据流图和安全定义
- 协作梳理系统架构
- 验证或完善拟定的安全定义
- 识别其他威胁并评估风险
- 不要假设外部缓解措施已经存在
第 3 阶段:实施(工程团队)
- 实施必要的安全缓解措施
- 针对尚无现有保护措施的威胁创建 Jira 后续任务
- 将安全考量纳入冲刺规划
第 4 阶段:测试与验证(工程团队 + AppSec)
- 验证缓解措施是否按预期生效
- 在代码审查中采用对抗性思维
- 通过逆向推演来检验假设(例如:“我能绕过 SSO 吗?”)
- 随着系统演进更新安全定义
安全定义
安全定义(SD)是 Bitwarden 用于传达系统安全态势的正式结构。每项定义都包含三个部分:威胁模型(攻击者能力)、安全目标(系统作出的保证)以及已接受的目标状态(诚实评估当前是否已达成目标)。
编写定义时,请使用 Bitwarden 的标准术语——完整词汇表参见 references/bitwarden-vocabulary.md。安全目标应与 Bitwarden 的安全原则(P01-P06)保持一致——参见 references/security-principles.md。
威胁模型组件
描述攻击者的能力和限制——他们能做什么、不能做什么。务必同时说明两方面,以准确界定范围:
- “攻击者可以在用户的客户端注销后运行用户空间进程” + “攻击者无法访问安全存储机制”
- “攻击者可以访问数据库,并读取和写入 Send 表” + “攻击者无法访问 ASP.NET Core Data Protection 加密密钥”
必要时提供具体示例(例如,“一个例子是设备失窃”)。不要假设已有外部缓解措施——即使获取身份验证令牌很困难,也要探讨攻击者持有令牌时会发生什么。
界定威胁模型范围时,遵循以下规则:
- 删去被支配的威胁。 如果你描述的攻击者能力严格弱于已接受为范围外的某项能力,请删除该 SD——其剩余风险说明会沦为“相当于完全入侵用户账户”之类的同义反复。有关被支配威胁反模式以及
references/writing-quality-sds.md中的 Dominated Threat 一词,请参阅该文档,以及references/bitwarden-vocabulary.md。 - 纳入被动观察者,而不只是对手。 对于任何传输至外部服务的秘密或受保护数据(LLM 提供商、日志聚合器、分析管道、训练数据收集器),至少编写一个 SD,将攻击者设定为诚实但好奇。机密性损害往往源自_可见性_,而非恶意——仅以对抗性为背景会遗漏基本风险。请参阅词汇表中的 Passive Observer 条目。
- 依据目标平台验证“攻击者无法访问 X”这一限制。 每项限制在范围涵盖的每个 OS/运行时上都必须属实。一个常见陷阱是,误以为某项能力需要内核级权限,但实际上在 Linux 和 Windows 上无需特权即可实现(例如,读取其他进程的环境变量)。如果限制不成立,该 SD 的范围界定就有误。
安全目标组件
针对威胁模型,陈述简洁、可测试且不可发生的情况。具体指出相关资产(令牌、密钥、保险库数据):
- “用户的客户端注销后,攻击者无法访问有效令牌”
- “攻击者无法获取任何不属于自己的已解密 MasterKeys”
- “攻击者只能读取加密的电子邮件地址列表”
每项目标都必须附带理由——分为三个部分,每部分一行:
- 原则——该目标落实了哪项 Bitwarden 原则(P01–P06)。请参阅
references/security-principles.md。 - 资产——要保护的具体数据、密钥或令牌。
- 危害——目标若未实现,用户可感知的后果(例如,“主密码暴露给第三方 LLM 提供商,并可能进入其训练管道”)。
没有理由的目标只是主张,而非要求。理由能让审查者判断该目标是否不可或缺,或是否可以删去。
关于目标表述的另外两条规则:
- 根据运行时检验目标是否切实可行。 对于垃圾回收、字符串驻留的运行时(JavaScript、.NET、JVM、Python),声称秘密会“从内存中清除”“归零”或“不被保留”的目标无法落实。如果运行时无法保障该目标,应改述为运行时_能够_保障的内容(缩小作用域、使用短生命周期引用、进程隔离),或明确标记 Accepted Goal Status 为未达成,并链接至系统性限制。不要编写语言本身无法保障的目标。
- 传递秘密时,优先使用 stdin 或文件描述符,而非环境变量/命令行参数。 如果目标禁止将秘密暴露于
process.env或argv,实现就必须使用 stdin 或继承的文件描述符。若 SD 的目标禁止暴露于环境变量,但实现却通过环境变量传递秘密,则前后矛盾——请修改设计或目标,但不要两者兼而有之。
已接受的目标状态组件
如实评估当前状态:
- 目标已达成 — 说明如何达成(例如:“清除用户状态时会从磁盘中删除已存储的令牌”)
- 目标部分达成 — 分别说明哪些方面有效、哪些无效,并为每个方面使用单独的指标
- 目标未达成 — 说明差距以及接受该差距的原因
- 尽力而为 — 对于取决于平台能力的目标(例如:“对于无法访问安全存储的客户端,例如 Web 和浏览器客户端,此目标无法实现”)
如果已知某个目标存在问题,请链接到相关的跟踪问题。注明范围方面的注意事项(例如:“这些定义不适用于将 Vault Timeout 设为 Never 的情况”)。
另外两条规则:
- 量化“短暂”或“短期存在”的理由。 如果接受残余风险的依据是“暴露时间很短”,请说明具体时限。例如:“机密信息会在子进程的环境变量中保留,直至
bw unlock执行完毕;时长随 KDF 迭代次数和保管库大小而变化——在具有代表性的硬件上观察到的时长为 1 到 8 秒。”_不带数字的“短暂”不算可接受的状态,而只是一种希望。_请参阅“暴露窗口”词汇条目。 - 确保内部一致。 威胁模型、安全目标和已接受的目标状态必须相互一致。如果威胁模型将能力 X 纳入范围,目标就必须防御 X,状态也必须说明该防御是否有效。如果目标禁止通过环境变量暴露信息,而实现却使用了环境变量,那么安全定义就是错误的——请选择这三者之一进行修改,并据此更改。不一致并非风格问题,而是安全定义未能描述系统。
编写安全定义
- 出错没关系——目的是开启讨论,看看这些定义能否被攻破
- 从系统 SHOULD 保证的内容入手,然后通过威胁分析进行验证
- 将宏观层面的定义(例如端到端加密)与特定于功能的微观定义分开
- 按顺序为定义编号(SD1、SD2、SD3)——每条定义都是一个独立单元
- 如果功能引入了特定领域的词汇,请附上功能专用术语表
- 按影响而非编号优先排序。 一份列出实际影响设计的 3–5 个威胁的简短文档,比一份包含 15 条安全定义、却将重要威胁埋没在冗余信息中的文档更有用。添加安全定义前,请先问:“如果这个威胁不存在,设计会改变吗?”如果答案是否定的,它很可能只是代码质量方面的说明,而非安全定义。
- 为每条安全定义标注关键性级别(Critical / High / Medium / Low),并按关键性从高到低排列文档,让审阅者先看到支撑设计的关键安全定义。优先级判断方法请参阅
references/writing-quality-sds.md。 - 冗长也是一种失误模式。 早期大模型代码审查中常见的反模式——冗长而信息量低的清单——同样困扰着生成的安全定义。删去仅描述实现细节的安全定义(例如,未来维护者将常量修改为包含 shell 元字符的内容),除非它们对设计至关重要。
工件生成
生成工件时,使用 examples/ 中的模板:
examples/security-definition-document.md— 完整的 SD 文档模板,包含术语表、编号定义、关键性标记、目标依据和已接受的目标状态examples/data-flow-diagram.md— 带信任边界的 Mermaid DFD 模板examples/threat-catalog.md— 威胁目录表和缓解措施跟踪模板
编写或审查 SD 时,请参考以下资料:
references/writing-quality-sds.md— 反模式(占主导地位的威胁、仅考虑对抗者的攻击者、无法强制执行的目标、理想化的限制、shell 引号 SD、“短暂暴露”陷阱)和自洽性检查清单references/bitwarden-vocabulary.md— 标准术语,包括 被动观察者、占主导地位的威胁 和 暴露窗口references/security-principles.md— P01–P06,每个目标的依据行都会引用这些原则references/stride-framework.md— 用于结构化威胁识别的 STRIDE 类别${CLAUDE_PLUGIN_ROOT}/references/adr-alignment.md— 安全工程师技能之间通用的架构决策记录(ADR)对齐检查
何时联系 AppSec
遇到以下情况时,团队应启动与 AppSec 团队(#team-eng-appsec)的完整协作:
- 新建项目或新服务
- 数据共享变更(组织成员资格、Send、共享功能)
- 组件之间新增 IPC 通道
- 跨域或跨源功能
- 不确定安全影响 — 首先进行初步安全评估,并将发现发布到 #team-eng-appsec,同时注明是否需要完整协作尚不确定
快速提问(例如,对第三方库或编码实践的疑虑)不需要完整协作 — 直接发布到 #team-eng-appsec 即可。
关键规则
- 在技术拆解中,将产品需求与安全需求分开。两者目的不同,相关利益方也不同。
- 安全定义是持续演进的文档。 功能变更、出现新威胁或发现安全问题时,应重新审视这些定义。
- 复杂性会增加漏洞风险。 将过于复杂的安全关键代码标记为技术债务。依赖项众多、逻辑错综复杂的代码极难保障安全。
- 威胁建模无法识别所有漏洞。 它只是众多工具之一。应结合代码分析、安全测试和对抗性审查。
- 不要假设外部缓解措施一定有效。 定义威胁模型时,应考虑攻击者绕过外部控制措施后会发生什么。
- 占主导地位或实现上不言自明的威胁都是噪声。 删除那些残余风险描述可归结为“等同于完全攻陷用户账户”,或唯一缓解措施是“审查者注意到某个常量被修改”的 SD。它们会降低信噪比,并掩盖真正重要的威胁。
- 每个安全目标都必须说明依据。 将每个目标与 Bitwarden 原则(P01–P06)、受保护的资产和用户可见的危害关联起来。没有依据的目标无法确定优先级,也无法评估其必要性,而且往往只是因惯性而非价值通过审查并保留下来。
最终确定一组 SD 之前,请应用 references/writing-quality-sds.md 中的自洽性检查清单。