4. 威胁建模实战
面试中一旦被问到“给你一个Web系统,现场做一次威胁建模”,很多候选人会立刻背出STRIDE六个字母,然后陷入沉默。面试官真正想看的不是定义复述,而是你能否在有限时间内,把一套方法论落到具体系统上,产出可执行的缓解措施。本节以一个真实的电商订单查询系统为对象,完整走一遍从建模到输出的过程。
先明确建模对象与边界
假设系统是一个面向外部用户的订单查询服务,典型架构为:浏览器 → CDN/WAF → Nginx反向代理 → 订单查询微服务(Java)→ MySQL主库/只读副本,同时微服务会调用用户中心(校验身份)和缓存(Redis)。数据流上,用户提交订单号与登录态,服务端校验后返回订单详情,包含收货地址、手机号、支付金额等敏感字段。
建模第一步不是套框架,而是画数据流图(DFD)并标注信任边界。信任边界至少有三条:互联网与DMZ之间、DMZ与应用内网之间、应用与数据层之间。每条边界都是威胁高发区,后续分析要围绕它们展开。这一步在面试中要口头说清楚,因为它决定了后面威胁是否“找得全”。
用STRIDE做系统性威胁枚举
STRIDE的价值在于“不遗漏类别”。针对上面的DFD,逐元素过一遍:
| STRIDE类别 | 对应安全属性 | 本系统具体威胁示例 |
|---|---|---|
| Spoofing 仿冒 | 认证 | 攻击者伪造他人登录态或重放token查询他人订单 |
| Tampering 篡改 | 完整性 | 篡改请求中的orderId越权访问;篡改返回数据 |
| Repudiation 抵赖 | 不可否认 | 查询敏感订单无审计日志,无法追溯谁查过 |
| Information Disclosure 信息泄露 | 机密性 | 越权IDOR导致订单、手机号、地址泄露;日志打印明文 |
| Denial of Service 拒绝服务 | 可用性 | 高频查询打满数据库连接;复杂查询拖垮服务 |
| Elevation of Privilege 权限提升 | 授权 | 普通用户通过参数构造访问管理接口或他人订单 |
注意,STRIDE是“枚举工具”,不是“排序工具”。它帮你把威胁列全,但哪个先修、哪个风险高,需要DREAD来辅助判断。
用DREAD给威胁排优先级
DREAD从五个维度打分(1-10分),取平均或加权。以“越权查询他人订单(IDOR)”为例,给出一个可复现的打分示例(以下为教学假设值,非实测):
威胁:通过修改orderId越权查询他人订单
D 潜在损害(Damage) = 9 (泄露手机号、地址、金额)
R 可复现性(Reproducibility)= 10 (改一个数字即可,稳定复现)
E 可利用性(Exploitability) = 8 (无需高深技术,工具即可)
A 受影响用户(Affected) = 9 (所有下单用户)
D 可发现性(Discoverability)= 7 (orderId规律性强,易枚举)
DREAD得分 = (9+10+8+9+7)/5 = 8.6 → 高风险,优先修复
对比另一个威胁“日志中打印明文手机号”,其可复现性和可利用性较低(需要拿到日志权限),DREAD可能只有5分左右,优先级自然靠后。面试中要强调:DREAD是主观打分,团队需统一标尺,否则分数没有可比性。它的作用是排序,不是精确度量。
用PASTA补上“攻击者视角”
STRIDE偏系统视角,PASTA(攻击模拟与威胁分析流程)则从攻击者动机出发,分七阶段。实战中不必全走完,重点用它的“攻击者中心”思路。针对本系统,可以问三个问题:攻击者是谁?动机是什么?最可能走哪条路径?
例如,黑产攻击者的动机是批量获取用户手机号用于营销或诈骗。其最可能路径是:注册普通账号 → 抓包发现orderId为自增数字 → 编写脚本遍历 → 批量拉取订单。这条路径直接指向“越权+可枚举”两个根因。PASTA的产出不是威胁清单,而是“攻击场景”,它让缓解措施更有针对性——比如把orderId改为不可枚举的UUID,并强制服务端校验订单归属。
用攻击树把单点威胁展开成路径
攻击树适合把一个高层目标拆成可操作的子步骤。以“获取他人订单信息”为根节点:
目标:获取他人订单信息
├── 路径A:越权访问
│ ├── A1 枚举orderId(自增/规律)
│ ├── A2 绕过归属校验(服务端未校验userId)
│ └── A3 利用管理接口未鉴权
├── 路径B:窃取凭证
│ ├── B1 XSS窃取token
│ └── B2 中间人截获(未强制HTTPS)
└── 路径C:数据库直连
├── C1 SQL注入
└── C2 配置泄露导致直连
攻击树的叶子节点就是具体攻击手法,每个叶子都可以对应一条缓解措施。这种结构在面试中非常加分,因为它展示了“从目标反推防御”的思维,而不是零散地罗列威胁。
输出缓解措施:从威胁到可执行动作
建模的终点是缓解措施。措施必须具体到“改什么、怎么改、怎么验证”,而不是“加强鉴权”这种空话。以下是一份可直接参考的缓解措施表(示例):
| 威胁 | 缓解措施 | 验证方式 |
|---|---|---|
| 越权查询(IDOR) | 服务端每次查询强制校验order.userId == 当前登录userId;orderId改为UUID | 用A账号token查B账号订单,返回403;抓包确认orderId非自增 |
| token重放 | token绑定设备指纹+短有效期+一次性nonce | 重放同一请求,第二次返回401 |
| 敏感信息泄露 | 返回字段最小化,手机号脱敏;日志禁止打印明文 | 检查响应体与日志文件,确认无完整手机号 |
| 高频查询DoS | 按用户+IP限流;查询走只读副本;复杂查询加超时 | 压测单用户高频请求,观察是否触发429 |
| SQL注入 | 全部使用参数化查询;WAF规则兜底 | 用sqlmap对查询接口扫描,确认无注入点 |
注意最后两列:缓解措施必须可验证。面试官常追问“你怎么知道修好了”,能答出验证方式,说明你真的做过,而不是纸上谈兵。
现场建模的时间分配建议
面试通常只有20-30分钟。建议:5分钟画DFD和信任边界,8分钟用STRIDE枚举,5分钟用DREAD排序,5分钟用攻击树展开最高风险项,最后5分钟输出缓解措施。PASTA可作为思路融入,不必单独走七阶段。关键是让面试官看到你有结构、有取舍、有落地。
最后提醒一点:威胁建模不是一次性活动。系统迭代、新接口上线、架构调整后都要重新过一遍。面试中如果能主动提到“建模要纳入DevSecOps流程,在需求评审阶段就介入”,会显著提升专业度。