威胁建模入门:从“拍脑袋”到“有章法”
很多团队做安全,上来就翻漏洞库、找工具扫描。结果呢?修了一堆低危问题,核心业务逻辑却被人绕过去了。我见过太多这样的案例了。
威胁建模,说白了就是在系统还没写一行代码之前,先坐下来画张图,想想“谁会攻击我?从哪下手?”。它不是玄学,是一套结构化的思考方法。今天我们就把它拆开揉碎了讲清楚。
一、威胁建模到底是什么?
我个人习惯把威胁建模理解成“安全领域的架构评审”。它不关注具体的漏洞(比如 SQL 注入),而是关注系统里哪些组件、哪些数据流、哪些信任边界可能出问题。
举个例子。你设计了一个用户登录模块。如果只靠经验,你可能会说“嗯,密码要加密”。但用威胁建模,你会问:
- 密码在传输过程中会不会被截获?
- 数据库被拖库了怎么办?
- 攻击者能不能绕过登录直接访问后台接口?
你看,思考的维度完全不一样了。
二、STRIDE 模型详解:微软的“六脉神剑”
STRIDE 是微软提出的一套威胁分类模型。我刚开始用的时候觉得它太抽象,后来发现,它其实是把攻击者的手法分成了六类。你对着这六类去检查系统,基本不会漏掉大方向。
| 缩写 | 威胁类型 | 通俗理解 | 典型场景 |
|---|---|---|---|
| S | Spoofing(假冒) | 冒充别人身份 | 伪造 JWT Token、盗用 Session |
| T | Tampering(篡改) | 修改不该动的东西 | 篡改请求参数、修改数据库记录 |
| R | Repudiation(抵赖) | 做了不承认 | 用户说“我没下单”,但系统没日志 |
| I | Information Disclosure(信息泄露) | 不该看的被看到了 | API 返回了用户手机号、密码明文 |
| D | Denial of Service(拒绝服务) | 让系统没法用 | 刷验证码接口、耗尽连接池 |
| E | Elevation of Privilege(权限提升) | 普通用户干管理员的事 | 越权访问后台、水平越权看别人订单 |
三、数据流图(DFD):威胁建模的“地图”
没有地图,你怎么知道敌人从哪来?DFD 就是这张地图。它不关心代码细节,只关心数据怎么流动、谁在处理数据、数据存在哪。
DFD 有四个基本元素,我习惯用颜色来区分,这样画出来一目了然:
- 外部实体(External Entity):人、外部系统。数据从这来,或到这去。
- 过程(Process):对数据做处理的组件。比如登录服务、支付网关。
- 数据存储(Data Store):数据休息的地方。比如数据库、缓存、文件。
- 数据流(Data Flow):数据移动的路径。用箭头表示方向。
画 DFD 有个关键点:信任边界。比如你的 Web 服务器和数据库之间,就是一条信任边界。跨过这条边界的流量,必须被严格检查。
四、实战:画一张登录模块的 DFD
光说不练假把式。我们拿一个最简单的登录模块来画 DFD。假设系统有:浏览器、Nginx、登录服务、用户数据库、Redis 会话缓存。
下面这张 SVG 图,就是典型的 DFD 画法。注意看信任边界的划分:
画完这张图,我们就可以用 STRIDE 来分析了:
- S(假冒):用户能不能伪造请求头冒充他人?Nginx 和登录服务之间有没有双向认证?
- T(篡改):登录请求在传输过程中能不能被中间人篡改?
- I(信息泄露):用户 DB 返回的数据有没有包含密码哈希?Redis 里的会话能不能被其他服务读取?
- E(权限提升):登录服务有没有可能被利用来执行管理员操作?
你看,一张图 + 一个模型,威胁就变得可枚举、可讨论了。
五、画 DFD 的三个实用原则
画 DFD 不是艺术创作,别搞得太复杂。我总结了三句话:
- 原则一:只画一层。别试图把每个微服务里的子模块都画出来。先画系统级 DFD,再针对高风险区域画子 DFD。
- 原则二:标清信任边界。用虚线把不同信任等级的区域圈出来。跨边界的每一条数据流,都是潜在的攻击面。
- 原则三:数据流必须有名字。别只画箭头,写上“用户登录请求”、“返回用户信息”。这样别人一看就懂。
六、威胁建模的输出是什么?
很多人以为威胁建模的输出是一堆报告。其实不是。真正的输出是一份经过排序的威胁清单,以及对应的缓解措施。
我习惯用表格来记录:
| 威胁编号 | STRIDE 类型 | 威胁描述 | 影响 | 缓解措施 | 优先级 |
|---|---|---|---|---|---|
| T-001 | Spoofing | 攻击者伪造 JWT 登录 | 高 | JWT 使用 RS256 签名,并校验 iss/aud | P0 |
| T-002 | Tampering | 登录请求被中间人篡改 | 高 | 全链路启用 HTTPS,HSTS 强制 | P0 |
| T-003 | Info Disclosure | 登录接口返回密码强度信息 | 中 | 统一错误提示,不暴露具体字段 | P1 |
有了这张表,开发团队就知道先修什么、怎么修。安全需求也就从“我们要做安全”变成了“我们要修 T-001 和 T-002”。