
我们先把一个反直觉的事实摆在前面大多数安全问题不是“写代码时引入的”而是在设计阶段就已经埋下的。很多团队的安全流程是这样的代码写完、功能测试通过然后丢给安全团队或者第三方做一轮渗透测试。扫出来漏洞开发再排期修复。运气好修复成本是一两个晚上运气差涉及认证、授权、数据流重构可能要把模块重写一遍。这种“事后补救”模式在单体时代勉强能运转。但在微服务、云原生、AI 应用大面积落地的今天攻击面从一个进程变成了几十个服务、几百个 API、多条异步链路。测试人员不可能覆盖所有组合代码审计速度跟不上迭代速度。我们真正缺的不是更多扫描器而是一张足够清晰的安全地图。这张地图就是威胁建模Threat Modeling。最近安全圈有一个值得关注的事经典著作《Threat Modeling: Designing for Security》正在筹备第二版并以社区共创的方式向全球开发者开放参与。我的判断是这绝不只是“一本书出新版”那么简单。它意味着威胁建模这套方法论正在从安全专家的手艺变成普通开发团队也能日常使用的工程能力。这篇文章会用一篇 CSDN 技术博客该有的方式把这方面讲透威胁建模到底是什么、核心方法有哪些、和过去相比第二版为什么值得关注、一个真实的订单服务应该怎么做威胁建模、如何用一套模板加脚本把它固化到日常开发里以及最常见的坑在哪里。文中的所有代码和配置都可以直接复制使用。1. 威胁建模为什么值得重新学这篇文章要解决的问题先说清楚一个容易混淆的概念。威胁建模不是漏洞扫描也不是渗透测试。它的目标不是“找到某个具体漏洞”而是在系统还没写代码、或者刚写完设计文档的时候系统地回答四个问题我们正在构建什么哪些地方可能出问题针对这些问题我们准备怎么办我们做得够不够好这四个问题就是 Adam Shostack 在《Threat Modeling: Designing for Security》中反复强调的“四个问题”框架。第一版在 2014 年出版后直接把威胁建模从微软内部的安全方法论变成了全球软件工程社区可以学习和落地的一套公开实践。那为什么现在要重新学因为环境变了。第一攻击面变了。以前一个系统就是一台服务器、一个数据库、一个 Web 应用。现在是 API 网关、服务网格、消息队列、对象存储、第三方支付、身份提供商每一个组件都有单独的信任边界。威胁建模的对象不再是“一个应用”而是“一张网”。第二威胁类型变了。AI 应用的提示注入、训练数据投毒、供应链依赖投毒这些都是传统安全测试工具不容易覆盖的威胁类别。它们恰恰需要设计层面的分析而不是代码层面的修补。第三合规压力变了。很多行业的安全合规标准开始要求“设计阶段的安全评审”而威胁建模是满足这类评审最成熟的手段之一。这篇文章适合的读者很明确正在做微服务或云原生项目的后端开发、负责系统设计的架构师、刚接手安全工作的安全工程师以及希望把安全左移到设计阶段的研发负责人。读完这篇文章你能独立完成一个中小型服务的威胁建模并有一套可以放进仓库、随着代码一起维护的模板和脚本。2. 威胁建模核心概念STRIDE、DFD 与信任边界要理解威胁建模必须掌握三个基础概念威胁分类、数据流图、信任边界。2.1 STRIDE一套威胁分类清单STRIDE 是微软提出的一套威胁分类方法几乎成了威胁建模的代名词。它把常见的威胁分成六类每个字母代表一类字母威胁类型英文含义通俗解释典型例子S仿冒Spoofing冒充别人伪造 JWT Token 冒充用户登录T篡改Tampering修改数据篡改订单金额字段R抵赖Repudiation做了不认账用户否认下过某笔订单I信息泄露Information Disclosure不该看的看到了越权读取他人订单详情D拒绝服务Denial of Service让系统不可用刷接口拖垮订单服务E提权Elevation of Privilege拿到更高权限从普通用户变成管理员STRIDE 的价值在于它提供了一张“检查清单”让分析者不会只盯着自己熟悉的那几类威胁。很多新手做完威胁建模发现结果很单薄原因往往是脑子里只想着“SQL 注入”“XSS”这类实现层面的漏洞而 STRIDE 逼着你从攻击者的目标出发把每一类都过一遍。2.2 DFD先画数据流再谈威胁威胁建模的第二个关键动作是画数据流图Data Flow DiagramDFD。DFD 的核心元素不多外部实体、进程、数据存储、数据流。它的价值不在于画得好看而在于强迫你回答一个问题数据从哪里来经过哪些处理最终存到哪里去每一段数据流都是一条潜在的攻击路径。很多团队跳过画图直接列威胁结果往往是凭感觉分析漏掉大量边界情况。画 DFD 看起来多花了一个小时但实际上是把整个系统在团队面前重新描述了一遍——这个动作本身就能暴露出很多“我以为你接了这个服务其实根本没有”的协作问题。2.3 信任边界威胁从哪里开始信任边界Trust Boundary是 DFD 上划分不同信任等级的分界线。跨过信任边界的数据流是威胁建模的第一分析重点。举个例子用户浏览器到 API 网关之间是“不可信到半可信”的边界API 网关到订单服务之间是“外部到内部”的边界订单服务到数据库之间是“内部可信区”的边界。每一层边界的假设不同需要的防护也不同。信任边界画得越清楚威胁的优先级就越容易定。那些跨越多条信任边界的数据流往往就是最需要防护的高风险链路。到这里可以给一个明确的小结论STRIDE 决定你分析什么DFD 决定你在哪里分析信任边界决定哪些部分值得优先分析。三者缺一威胁建模就容易流于形式。3. 从第一版到第二版这本书为什么值得关注很多读者可能只知道 STRIDE 是微软提出的却不知道把 STRIDE 从微软内部方法论变成公开工程实践的关键人物之一就是 Adam Shostack。他在微软负责过安全设计相关工作参与推动了不少安全工具和流程的建设。2014 年他出版了《Threat Modeling: Designing for Security》Wiley 出版。这本书是第一本系统地把威胁建模讲成“工程实践”的专著而不是停留在理论层面。它把前面提到的“四个问题”框架、STRIDE 分类、数据流图方法整合成一套可操作的流程让开发团队可以照着做。第一版出版后的十年恰恰是软件架构剧烈变化的十年。容器化、微服务、云原生、Serverless、大模型应用陆续成为主流。原来书里很多示例基于传统的 Web 和客户端架构已经不能完整覆盖今天团队遇到的实际问题。这正是第二版要解决的。从公开信息看第二版的筹备采用了社区共创的方式发起在正式出版前就面向安全从业者征集参与。这意味着第二版的内容不是出版社单方面打磨出来的而是由大量一线安全工程师和开发者的反馈共同塑造的。这种模式本身也说明了一件事威胁建模不是某个公司或某个专家的私有方法论而是一套需要社区持续迭代的公共知识。第二版扩展的主要方向业界普遍预期会覆盖以下几点云原生架构下的威胁建模比如容器、Kubernetes、服务网格API 经济下的接口安全分析与威胁识别AI/ML 系统特有的威胁类型比如提示注入、模型窃取、训练数据投毒软件供应链安全的建模思路更贴近敏捷开发和 DevOps 流程的轻量级实践方式。我在这里要给出一个明确的判断第二版不是第一版的勘误或者增补而是一次面向新架构的重写。如果你过去学过第一版现在也应该重新关注第二版的变化尤其是云原生和 AI 这两块很可能是内容增量最大的部分。同时对中文开发者来说这本书还有一个额外价值它提供了一套统一的“安全词汇表”。团队里所有人讨论安全风险时说的是同一种语言——STRIDE、DFD、信任边界、缓解措施。这种语言统一比任何安全工具带来的效率提升都更明显。4. 主流威胁建模方法对比怎么选并不是所有团队都必须用 STRIDE。业界发展了多年已经沉淀出多套威胁建模方法。选错了方法容易陷入“方法论很高级落地很痛苦”的窘境。下面用表格做一个横向对比。方法提出方核心思路适用场景主要局限STRIDEMicrosoft按六类威胁逐项分析软件系统设计评审最通用需要经验才能控制分析粒度DREADMicrosoft对威胁进行风险打分威胁排序与决策打分主观Microsoft 已不推荐PASTA风险分析领域以攻击为中心七步流程对齐业务大型企业、业务风险驱动流程重小团队难消化LINDDUN隐私保护社区以隐私威胁为维度涉及个人数据、GDPR 合规只覆盖隐私不覆盖全部安全VAST安全咨询领域支持敏捷规模化集成与敏捷/DevOps 深度绑定依赖配套工具链OCTAVE卡内基梅隆大学从组织风险出发企业整体风险管理偏管理不适合单服务分析选择标准很简单如果你的目标是“把一个具体服务的威胁分析清楚”STRIDE 是默认选择它最通用、最容易被团队接受。如果你的系统涉及大量个人隐私数据比如医疗、金融建议在 STRIDE 之外补做一轮LINDDUN专门看隐私维度。如果你是集团层面的安全负责人需要从业务风险角度做全局规划再看PASTA 或 OCTAVE。如果你的团队已经深度使用敏捷和 DevOps想每两个迭代跑一次轻量级威胁建模VAST的思路值得参考。需要特别提醒的是方法本身不是越复杂越好。对绝大多数中小团队来说STRIDE 加数据流图已经能覆盖 80% 的实战需求。先把这套跑熟再根据系统特点扩展其他方法是最稳妥的路径。5. 落地流程威胁建模在项目里怎么跑起来理论说完接下来是很多人最关心的问题威胁建模到底怎么在自己的项目里跑起来下面是一套经过了多个团队验证的轻量级流程按一次典型的设计阶段威胁建模来设计。5.1 明确范围和目标开始前先确定这次建模的范围。是一个新服务还是一个上线半年的大模块重构范围越大分析越容易泛泛而谈。建议一次只覆盖一个服务或者一个业务场景时间控制在两小时以内。5.2 画数据流图召集参与设计的同学一起画出这个服务的数据流图。不用追求工具统一白板、draw.io、Excalidraw 都可以。重点是让所有参与者对数据流向达成一致。画图时要回答外部哪些实体能访问这个系统数据经过哪些处理组件数据最终存储在哪些地方哪些环节跨越了信任边界5.3 用 STRIDE 逐项过威胁对数据流图上的每个元素依次问六类问题谁能仿冒这个元素数据能不能被篡改有没有可能抵赖哪些数据存在泄露风险能不能被打到不可用有没有可能存在越权这一步的产出是一张威胁清单建议用一个统一的结构化文件维护而不是散落在会议纪要里。5.4 定优先级不是所有威胁都要立即处理。可以用两个维度粗筛影响程度如果这个威胁被利用会造成什么业务损失发生可能性这个威胁利用难度高不高对外暴露面大不大影响高、可能性高的威胁必须进入本期迭代的缓解措施影响低、可能性低的威胁记录在案后续跟踪即可。5.5 制定缓解措施并跟踪每条威胁至少要有一条对应的缓解措施并且要有明确的负责人和验证方式。这一步如果省略威胁建模就会变成一场“讨论得很热烈结束后什么都不变”的会议。5.6 验证缓解措施上线后要通过安全测试、代码评审或配置检查来验证它真的生效。同时威胁模型文件要随着代码一起维护不能只在设计阶段画一次就再也不更新。这套流程的核心理念是“够用就好”。一次两小时的威胁建模会议通常能产出 10 到 30 条有效威胁其中需要立即处理的往往不超过 5 条。关键在于把威胁建模变成设计流程的一部分而不是额外的负担。6. 完整示例订单服务的 STRIDE 威胁建模为了把这套流程讲透我用一个电商订单服务作为示例完整演示从数据流描述到威胁清单、再到缓解措施的全过程。这个示例里的代码和文件可以直接作为团队模板使用。6.1 业务场景与数据流假设我们的订单服务架构如下[用户浏览器] --HTTPS-- [API网关] --HTTPS-- [订单服务] --SQL-- [订单数据库] | | | --HTTPS-- [支付网关] | | --HTTPS-- [支付网关回调]业务流程是用户通过浏览器访问 API 网关创建订单订单服务写入订单数据库随后调用支付网关发起支付支付完成后支付网关通过异步回调通知订单服务更新订单状态。这里有一个特别值得关注的信任边界支付网关的回调是从“外部可信第三方”进入“内部服务”的数据流。如果验签不严攻击者可以直接伪造回调把订单状态改成已支付。6.2 威胁模型结构化文件我建议用一个 YAML 文件来维护威胁模型好处是结构化、可版本管理、可被脚本校验。文件路径建议放在docs/threat-model.yaml和代码仓库一起维护。# 文件路径docs/threat-model.yaml model: name: order-service owner: team-checkout version: 0.1.0 last_reviewed: 2025-01-15 scope: 订单创建、支付回调、订单状态查询 assets: - id: A1 name: order_database description: 订单主库包含用户订单、支付快照、收货地址 classification: 敏感 - id: A2 name: payment_gateway_client description: 对接第三方支付网关的客户端密钥与证书 classification: 机密 entry_points: - id: E1 name: create_order_api description: POST /api/v1/orders接受用户下单请求 trust_level: 外部不可信 - id: E2 name: payment_callback description: 支付网关支付结果异步回调 trust_level: 部分可信依赖验签 data_flows: - id: F1 from: E1 to: order_service protocol: HTTPS/JSON data: 用户信息、商品明细、收货地址 trust_boundary: 外部 - 内网 - id: F2 from: E2 to: order_service protocol: HTTPS/JSON data: 支付结果、支付单号、签名 trust_boundary: 外部第三方 - 内网 threats: - id: T1 stride: S asset: A2 title: 伪造支付回调 description: 攻击者直接伪造支付成功回调绕过真实支付流程 impact: high likelihood: medium mitigations: - 对回调请求做 HMAC 验签验签失败直接拒绝 - 回调接口 IP 白名单限制为支付网关出口 IP - 订单状态变更以平台查询结果为准回调只做异步通知 status: planned - id: T2 stride: I asset: A1 title: 越权查看他人订单 description: 普通用户修改订单 ID 越权读取他人订单详情 impact: high likelihood: high mitigations: - 订单查询接口强制校验当前用户与订单归属关系 - 订单 ID 使用不可枚举的随机串避免连续数字 - 对异常访问频率做限流和告警 status: planned - id: T3 stride: D asset: A1 title: 订单创建接口被刷 description: 攻击者批量调用下单接口耗尽数据库连接 impact: medium likelihood: high mitigations: - API 网关按用户维度限流 - 下单接口增加图形验证码或设备指纹校验 - 数据库连接池设置合理上限 status: planned这个文件维护起来成本很低但价值很高。它把设计阶段的分析结果固化成了资产后续任何参与该服务开发的人都可以快速了解系统有哪些已知风险、哪些缓解措施已经落地、哪些还在排期。6.3 STRIDE 威胁分析表上面的 YAML 文件是机器可读的版本但在评审会议上通常还需要一张人可读的汇总表方便快速浏览。威胁 IDSTRIDE 分类涉及资产威胁描述影响可能性缓解措施状态T1SA2伪造支付回调高中验签、IP 白名单、状态以平台为准已规划T2IA1越权查看他人订单高高归属校验、不可枚举 ID、异常告警已规划T3DA1下单接口被刷中高网关限流、验证码、连接池上限已规划这张表的好处是评审时一眼就能看到重点。你可以在每次迭代评审时把这张表拿出来逐条确认状态变化。6.4 如何运行和验证把 YAML 文件提交到仓库后可以用下面的 Python 脚本做基本校验确保文件结构合法、威胁分类正确、每条威胁都有缓解措施。# 文件路径scripts/threat_model_check.py #!/usr/bin/env python3 威胁模型文件基础校验脚本 用法: python scripts/threat_model_check.py docs/threat-model.yaml import sys import yaml REQUIRED_TOP_KEYS {assets, entry_points, data_flows, threats} STRIDE set(STRIDE) def main(path: str) - int: with open(path, r, encodingutf-8) as f: data yaml.safe_load(f) errors [] model data.get(model, {}) if not model.get(name): errors.append(model.name 不能为空) missing REQUIRED_TOP_KEYS - set(data.keys()) if missing: errors.append(f缺少顶层字段: {missing}) threats data.get(threats, []) if not threats: errors.append(threats 列表为空请至少记录一条威胁) for threat in threats: stride threat.get(stride, ) if stride not in STRIDE: errors.append(f威胁 {threat.get(id)} 的 stride 字段非法: {stride}) if not threat.get(mitigations): errors.append(f威胁 {threat.get(id)} 没有缓解措施) if errors: print(威胁模型校验失败:) for error in errors: print( -, error) return 1 print(威胁模型校验通过) return 0 if __name__ __main__: sys.exit(main(sys.argv[1]))运行方式pip install pyyaml python scripts/threat_model_check.py docs/threat-model.yaml预期输出威胁模型校验通过如果出现“威胁 xxx 没有缓解措施”这样的提示说明威胁清单里还有只发现问题、没有解决方案的条目这正是威胁建模最常见的执行漏洞。7. 运行验证与 CI 集成让威胁建模可持续威胁建模最大的敌人不是难度而是“一次性”。很多团队在设计评审时做了威胁建模之后就再也不碰了。等到半年后系统大改那张威胁模型图已经和实际架构完全对不上。要解决这个问题最有效的方法是把威胁建模纳入日常开发流程。具体有三件事可以做。7.1 威胁模型文件进仓库第一条刚才已经提到威胁模型以 YAML 或 Markdown 形式放进代码仓库和代码一起走版本管理。这样每次架构变更、每次 MR都能看到威胁模型是否需要同步更新。7.2 在 CI 里加一个检查任务第二条是用 CI 把基础校验自动化。下面是一个 GitLab CI 片段当威胁模型文件或校验脚本发生变化时自动运行校验。# 文件路径.gitlab-ci.yml threat-model-check: stage: test script: - pip install pyyaml - python scripts/threat_model_check.py docs/threat-model.yaml only: changes: - docs/threat-model.yaml - scripts/threat_model_check.py如果用的是 GitHub Actions原理一样只是配置文件格式不同。这个检查不能保证威胁模型的质量但能保证它不会因为手误变成一堆无效内容。7.3 定期评审与代码评审联动第三条是在代码评审模板里增加一栏“本次变更是否影响现有威胁模型”。如果答案是“是”MR 必须附带威胁模型的更新或者至少说明为什么不需要更新。一年后再回头看这一条往往比前两条更能保证威胁模型的长期有效性。因为它把“威胁模型是否过期”这个问题变成了每个开发者在日常协作中都必须面对的常规问题。7.4 如何验证威胁建模本身做得好不好验证威胁建模的产出质量可以从三个角度入手覆盖率数据流图上的每个跨信任边界的数据流是否都有对应的威胁分析可执行性每条威胁是否有明确的缓解措施和负责人时效性威胁模型是否和当前代码架构保持一致如果这三个角度都过关说明威胁建模真正进入了工程实践而不是一张挂在墙上的装饰图。8. 威胁建模常见问题与排查思路以下问题是我在实际团队中反复看到的做成表格方便快速对照。问题现象可能原因排查方式解决方案威胁建模做完后没人更新模型文件散落在文档目录和代码脱节检查威胁模型文件是否在代码仓库将威胁模型文件纳入仓库和代码一起评审威胁清单太长达不到重点分析粒度没有控制把实现细节当成威胁检查是否对每个类都展开过度只关注跨信任边界的数据流和关键资产做一次耗时太长团队抵触范围定得太大一次分析整个系统检查会议参加者和建模范围缩小到单服务或单场景控制在两小时内威胁模型和实际架构不一致架构变更后没有同步更新对比威胁模型与当前部署架构在 MR 模板中增加威胁模型更新选项不知道优先级怎么定缺少风险判断标准检查是否有统一的评分规则用“影响 × 可能性”双维度分类先处理高风险领导觉得威胁建模没有价值产出物没有和业务风险关联检查是否只有威胁没有业务影响说明每条威胁补充业务影响量化展示画图工具维护成本高工具选择不当图越来越大检查图是否超过一屏拆分为多张子图或改用 Markdown/YAML 文本维护缓解措施一直没有落地缺少跟踪机制检查威胁状态是否有负责人每轮迭代评审时逐条确认状态这里要特别提醒的一点是威胁建模分析的是你自己负责或有授权评估的系统目的是防御性设计而不是攻击他人系统。所有分析工作都应在合法授权范围内进行。9. 最佳实践与工程建议最后把威胁建模在工程中真正跑好的经验总结成几条建议。9.1 从一个最小的可用威胁模型开始不要一开始就追求“完整”。第一个威胁建模选一个上线不到三个月的小服务画一张简单的数据流图列出 10 条以内的威胁跑通“分析—缓解—验证”的闭环。有了第一次的成功经验团队才会愿意持续做。9.2 把威胁建模嵌入设计评审而不是独立会议独立的安全会议往往没人愿意参加但设计评审是团队本来就要开的。把威胁建模作为设计评审的一个固定环节从一开始就参与比事后单独补一次会议要自然得多。9.3 模板统一格式标准化建议团队维护一套统一的威胁模型模板包含资产、入口点、数据流、威胁清单、缓解措施、状态这几部分。统一的格式让不同服务之间可以横向对比也让脚本校验成为可能。本文的 YAML 模板可以直接作为起点。9.4 威胁建模和安全测试相互印证威胁建模负责“找出可能出问题的地方”渗透测试和安全扫描负责“验证这些地方是不是真的有问题”。两者是配合关系不是替代关系。建模时发现的疑问可以转成后续测试用例测试发现的漏洞也可以反向补充到威胁模型里。9.5 按风险分级不要试图解决所有威胁如果威胁模型列出了 30 条威胁正确的做法不是全部修复而是分类处理高影响高可能性立即处理进入本期迭代高影响低可能性排期处理做好监测低影响高可能性通过标准安全基线缓解低影响低可能性记录在案定期复查。这个分类过程比威胁清单本身更重要。9.6 明确所有权每条威胁都要有明确的负责人。没有所有者的缓解措施等于没有缓解措施。建议在威胁模型文件中增加owner字段并将威胁状态跟踪纳入迭代评审。9.7 安全边界提醒威胁建模涉及的系统分析、攻击面梳理请务必只针对自己负责或有明确授权评估的系统进行。任何安全相关工作都应该遵循合法合规原则这是工程底线。10. 总结与后续学习方向这篇文章从头到尾把威胁建模这条线梳理了一遍。核心信息可以浓缩成三句话威胁建模解决的是设计阶段的风险结构问题它的价值在于让团队在攻击者之前把系统的薄弱环节想清楚而不是多扫出几个漏洞。STRIDE 加数据流图是最通用、最值得先掌握的组合并配合一套结构化模板和校验脚本才能真正在团队里落地。威胁建模的长期有效性取决于它是否嵌入日常开发流程而不是取决于一次分析做得多完美。如果你读了这篇文章还没动手我建议你直接做一件小事找一个你最近负责的服务花两小时画一张数据流图用 STRIDE 过一遍把结果按本文的 YAML 模板写下来。做完这一次你就能判断威胁建模适不适合你的团队。对于想继续深入的同学下一步可以按这几个方向扩展一是学习 LINDDUN 方法补充隐私威胁的分析能力二是研究威胁建模工具比如 Microsoft Threat Modeling Tool、OWASP Threat Dragon、绘制数据流图配合自动化工具三是关注威胁情报把真实的攻击手法反向映射到威胁模型里让分析更有依据。威胁建模不是一个一次性的安全活动而是一种持续的设计思维方式。希望这篇文章能帮你把这张安全地图真正画起来并且让它和代码一起长期保持新鲜。建议收藏备用下次做新服务设计时直接照着跑一遍。