威胁建模基础:从“拍脑袋”到“有章法”
说实话,我见过太多团队做安全的方式了。需求评审时问一句“这个功能安全吗?”,大家面面相觑,最后说“应该没问题吧”。然后呢?上线后被薅羊毛、被越权、被注入,再紧急修复。
这种“拍脑袋”式的安全,说白了就是靠运气。而威胁建模,就是要把运气变成确定性。我做了十几年安全架构,最深的体会就是:没有威胁建模的项目,就像蒙着眼睛过马路。
核心观点:威胁建模不是“做不做”的问题,而是“什么时候做、怎么做”的问题。越早做,成本越低;越晚做,代价越高。
威胁建模的目的与价值
先问个问题:你为什么要做威胁建模?
我个人习惯把威胁建模的价值归纳为三点:
- 提前发现风险——在代码还没写、架构还没定死的时候,就把可能出问题的地方找出来。我在项目中遇到过,一个支付系统的架构评审,威胁建模发现“订单金额在客户端计算”这个设计缺陷,改起来只花了半天。要是上线后才发现,那得动多少代码?
- 统一团队认知——开发、测试、产品、安全,大家对“什么是安全的”理解往往不一样。威胁建模提供了一个共同的语言和框架,让所有人站在同一页上。
- 降低修复成本——这个道理很简单:设计阶段改一个架构决策,成本是1;开发阶段改代码,成本是10;上线后修复漏洞,成本是100。威胁建模就是帮你把成本锁定在1的阶段。
我的经验:威胁建模最大的价值不是“找出所有威胁”,而是“让团队开始思考安全”。很多团队做完第一次威胁建模后,开发同学会主动说:“这个接口是不是应该加鉴权?”——这种意识上的转变,比任何工具都重要。
STRIDE模型详解
说到威胁建模,就绕不开STRIDE。这是微软提出的一套威胁分类模型,名字由六种威胁类型的首字母组成。
我刚开始学STRIDE时,总觉得它就是个分类标签。后来用多了才发现,STRIDE的真正价值是提供了一个“检查清单”——你对着这六类去审视系统,基本不会漏掉什么。
| 威胁类型 | 英文 | 核心问题 | 典型场景 |
|---|---|---|---|
| S 欺骗 | Spoofing | 谁能假装成别人? | 伪造用户身份、伪造服务器 |
| T 篡改 | Tampering | 数据能被非法修改吗? | 修改请求参数、篡改数据库 |
| R 抵赖 | Repudiation | 做了事能赖账吗? | 缺少操作日志、日志可被删除 |
| I 信息泄露 | Information Disclosure | 敏感数据能被看到吗? | 明文传输密码、API返回过多信息 |
| D 拒绝服务 | Denial of Service | 系统能被搞瘫痪吗? | 流量攻击、资源耗尽 |
| E 权限提升 | Elevation of Privilege | 普通用户能干管理员的事吗? | 越权操作、未授权访问 |
你想想看,这六类几乎覆盖了所有常见的安全问题。我在做威胁建模时,习惯把每个组件、每条数据流都过一遍STRIDE,就像安检一样,一个一个查。
注意:STRIDE不是银弹。它更适用于“应用层”的威胁分析,对于物理安全、社会工程学等场景,需要结合其他模型。我曾经在一个IoT项目中只用了STRIDE,结果漏掉了“设备被物理拆解”的风险——后来补了攻击树分析才补上。
威胁建模的流程
理论说完了,咱们来点实操。威胁建模的流程,我一般分成五步。这五步不是死规矩,但新手照着做,基本不会跑偏。
第一步:定义范围
这一步最容易被忽略。很多人上来就画图、找威胁,结果发现讨论了半天,连“这个系统到底包含哪些模块”都没对齐。
定义范围要回答三个问题:
- 我们要分析的系统是什么?(边界在哪?)
- 谁在使用这个系统?(用户角色有哪些?)
- 系统依赖哪些外部服务?(第三方API、数据库、缓存等)
我个人习惯用一张简单的表格来记录范围定义的结果:
| 维度 | 内容 |
|---|---|
| 系统名称 | 用户订单服务 |
| 边界 | 从API网关到数据库,不包括前端页面 |
| 用户角色 | 普通用户、商家、管理员 |
| 外部依赖 | 支付网关、短信服务、物流API |
第二步:分解系统
范围定好了,接下来就是把系统拆开,看清楚里面到底有什么。这一步的核心产出是数据流图(DFD)。
数据流图要画清楚:
- 外部实体(用户、第三方系统)
- 处理过程(业务逻辑模块)
- 数据存储(数据库、缓存、文件)
- 数据流(数据怎么流动的)
- 信任边界(哪里是可信的,哪里是不可信的)
嗯,这里要注意:信任边界是威胁建模的关键。数据每跨一次信任边界,就可能引入新的威胁。比如用户请求从公网进入内网,这就是一次信任边界的跨越。
第三步:识别威胁
系统分解好了,数据流图画出来了,接下来就是对着STRIDE,一个一个找威胁。
我常用的方法是:对每个数据流、每个处理过程、每个数据存储,都问一遍STRIDE的六个问题。比如:
- 这个数据流会不会被篡改?
- 这个处理过程会不会泄露用户信息?
- 这个数据存储会不会被DoS攻击?
我曾经在一个电商项目中,用这个方法找出了37个潜在威胁。其中有一个是“用户下单时,订单金额在客户端计算后提交”——这就是典型的篡改威胁。后来我们改成了服务端计算金额,堵住了这个漏洞。
小技巧:识别威胁时,不要只盯着技术层面。业务逻辑上的威胁往往更隐蔽。比如“优惠券可以无限叠加使用”,这属于业务逻辑漏洞,但STRIDE里的“篡改”和“权限提升”都能覆盖到。
第四步:确定风险
威胁找出来了,但不可能全部修复。资源有限,时间有限,你得知道哪些威胁最要命。
确定风险,我一般用两个维度:可能性和影响程度。简单来说:
- 可能性高 + 影响大 = 优先处理
- 可能性低 + 影响小 = 可以接受
- 其他情况 = 根据实际情况权衡
你可以用一张风险矩阵表来记录:
| 威胁描述 | 可能性 | 影响程度 | 风险等级 | 处理策略 |
|---|---|---|---|---|
| 用户可篡改订单金额 | 高 | 高 | 严重 | 立即修复 |
| 日志记录不完整 | 中 | 中 | 中等 | 计划修复 |
| API返回过多用户信息 | 低 | 高 | 中等 | 评估后修复 |
第五步:制定缓解措施
最后一步,也是最实在的一步——怎么修?
缓解措施要具体、可落地。不要写“加强安全防护”这种废话,要写“在订单接口增加服务端金额校验”、“所有API响应中移除用户手机号字段”。
我个人习惯把缓解措施分成三类:
- 设计层面——比如修改架构、增加鉴权层、引入加密
- 技术层面——比如加WAF、做输入校验、加限流
- 管理层面——比如增加安全评审、做渗透测试、培训开发人员
避坑指南:我曾经在一个项目中,团队花了两周时间做威胁建模,找出了20多个威胁,但最后只修复了5个。为什么?因为缓解措施写得太模糊,开发不知道怎么做。后来我改了做法:每个威胁必须对应一个具体的、可验证的缓解措施,并且指定负责人和截止时间。这样才真正落地。
总结一下
威胁建模不是什么高深的技术,它就是一个结构化的思考过程。你不需要成为安全专家,只要掌握STRIDE和五步流程,就能把安全从“拍脑袋”变成“有章法”。
嗯,最后说一句:威胁建模不是一次性的活动。系统在变,业务在变,威胁也在变。我建议每个大版本迭代都做一次威胁建模,哪怕只是快速过一遍,也比不做强。