STRIDE 威胁建模实战:pytm 自动化分析

威胁建模 STRIDE 是系统设计阶段识别安全风险的结构化方法,但很多团队止步于「画一张图、列几条风险」,模型与代码脱节、评审后无人跟进。本文给出威胁建模 STRIDE 的工程化落地路径:用 pytm 把数据流图写成 Python 代码,自动匹配威胁规则并输出威胁清单、DFD 图与序列图,最终纳入 CI 流水线,让威胁模型随架构变更持续更新。

适用场景

  • 新系统立项或架构评审前,需要系统化输出威胁清单与整改项,而不是靠个人经验零散提示。
  • 既有系统迭代变更(新增接口、新增第三方集成)时,需要快速评估变更带来的新增风险面。
  • 等保 2.0、ISO 27001 与安全开发生命周期(SDLC)要求提供威胁建模文档与整改记录。
  • 外包或采购系统验收时,需要独立复现对方的数据流与信任边界,验证其安全设计假设。

前置条件

  • Python 3.9 及以上版本,可安装第三方包。
  • 安装 pytm(威胁建模引擎)与 Graphviz(生成 DFD 与序列图)。
  • 一份可用的系统架构信息:外部实体、服务进程、数据存储、数据流方向与信任边界。
  • 版本控制仓库(Git),用于把威胁模型与代码同仓管理、在 CI 中运行。
  • 明确的风险评分标准(CVSS 或 DREAD),用于对自动生成的威胁做优先级排序。

原理说明

STRIDE 把威胁归纳为六类,每一类对应一个安全属性被破坏的情形:

  • Spoofing 假冒:身份可被伪造,破坏认证属性。
  • Tampering 篡改:数据或代码可被未授权修改,破坏完整性。
  • Repudiation 抵赖:操作无法追溯,破坏不可否认性。
  • Information Disclosure 信息泄露:数据被未授权读取,破坏机密性。
  • Denial of Service 拒绝服务:可用性被破坏。
  • Elevation of Privilege 权限提升:低权限主体获得高权限,破坏授权。

STRIDE 的分析载体是数据流图(DFD),其四类元素与 STRIDE 的对应关系是固定的:外部实体主要关注假冒与抵赖,进程关注全部六类,数据存储关注篡改、信息泄露与拒绝服务,数据流关注篡改、信息泄露与拒绝服务。信任边界(Boundary)之间的跨越点,是风险最集中的位置。

pytm 把这套方法代码化:用 Python 类描述 DFD 元素,并为元素设置安全属性(是否加密、是否校验输入、是否鉴权、是否加固等);pytm 内置一份威胁规则库(threatlib),逐条以条件表达式匹配元素属性,满足条件即输出对应威胁。这样威胁建模不再是「一次性文档」,而是可版本控制、可自动运行、可回归的代码资产。

操作步骤

步骤一:安装环境

# 安装 pytm 与 Graphviz
python3 -m pip install pytm
sudo apt update && sudo apt install -y graphviz

# 验证
python3 -c "import pytm; print(pytm.__version__ if hasattr(pytm,'__version__') else 'pytm ok')"
dot -V

步骤二:用 Python 描述数据流图

新建 tm/TM.py,按「边界 → 元素 → 数据流」的顺序定义。注意把安全属性显式写全,属性缺失会导致条件不成立、威胁被漏报。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""pytm 威胁模型:电商下单系统"""
from pytm import TM, Actor, Boundary, Dataflow, Datastore, Server

tm = TM("电商下单系统")
tm.description = "覆盖用户下单、订单 API 与订单库的数据流模型"
tm.isOrdered = True

# 1) 定义信任边界
internet = Boundary("Internet")
dmz      = Boundary("DMZ")
internal = Boundary("内部网络")

# 2) 定义元素及其安全属性
user = Actor("外部用户", inBoundary=internet)

web = Server("Web 前端", inBoundary=dmz)
web.OS = "Ubuntu 22.04"
web.isHardened = True          # 已做基线加固
web.validatesInput = True      # 已做输入校验
web.sanitizesInput = True

api = Server("订单 API", inBoundary=internal)
api.OS = "Ubuntu 22.04"
api.isHardened = True
api.authenticated = True       # 调用方需认证
api.authorizes = True          # 已做权限校验
api.validatesInput = True
api.sanitizesInput = True
api.usesEnvironmentVariables = True

db = Datastore("订单数据库", inBoundary=internal)
db.storesSensitiveData = True  # 存有个人与支付信息
db.isEncrypted = True
db.isSQL = True
db.validatesInput = True

# 3) 定义数据流
f1 = Dataflow(user, web, "下单请求")
f1.protocol = "HTTPS"
f1.isEncrypted = True

f2 = Dataflow(web, api, "内部 API 调用")
f2.protocol = "HTTPS"
f2.isEncrypted = True

f3 = Dataflow(api, db, "SQL 读写")
f3.protocol = "PostgreSQL"
f3.isEncrypted = True

tm.process()

步骤三:生成 DFD、序列图与威胁报告

cd tm

# 生成数据流图(需要 graphviz 的 dot)
python3 TM.py --dfd | dot -Tpng -o dfd.png

# 生成序列图,便于与开发对齐调用顺序
python3 TM.py --report seq | dot -Tpng -o seq.png

# 输出威胁报告(纯文本,无需 graphviz)
python3 TM.py --report threats | tee threats.txt

# 输出 JSON,便于后续自动统计与入库
python3 TM.py --json threats.json
jq 'length' threats.json

威胁报告每条包含编号(SID)、威胁描述、命中条件、严重度与整改建议。统计条目数可用:

# 按严重度分组统计
jq -r '.[].severity' threats.json | sort | uniq -c | sort -rn

步骤四:补充自定义威胁规则

内置规则覆盖通用场景,业务特有风险需自建规则。规则以 JSON 数组给出,条件字段是作用于目标元素的 Python 表达式。

cat > custom_threats.json <<'JSON'
[
  {
    "SID": "BIZ01",
    "target": ["Server"],
    "description": "订单金额由前端传入且服务端未二次校验",
    "details": "攻击者可篡改下单请求中的金额或折扣字段,造成资损。",
    "Likelihood Of Attack": "High",
    "severity": "High",
    "condition": "target.validatesInput is False or target.authorizes is False",
    "mitigations": "服务端按商品 SKU 重新计算价格与优惠,禁止信任前端金额字段;对关键字段做签名校验。"
  },
  {
    "SID": "BIZ02",
    "target": ["Dataflow"],
    "description": "跨信任边界的数据流未加密",
    "details": "DMZ 到内部网络的调用若为明文,可被横向嗅探。",
    "Likelihood Of Attack": "Medium",
    "severity": "High",
    "condition": "target.isEncrypted is False",
    "mitigations": "全链路启用 TLS,内网服务间使用 mTLS 或服务网格加密。"
  }
]
JSON

# 加载自定义规则(默认会与内置规则合并)
python3 TM.py --threats custom_threats.json --report threats | head -60

步骤五:风险排序与整改闭环

自动生成的威胁条目通常较多,直接全部修复不现实。可按「严重度 × 可达性」排序,优先处理跨信任边界且影响机密性与完整性的条目。建议把每条威胁映射到责任人、整改方案与截止时间,形成威胁跟踪表;整改后同步更新元素属性(如把 isEncrypted 置为 True),再次运行确认该威胁消失,验证整改有效。

步骤六:纳入 CI 流水线

# .github/workflows/threatmodel.yml
name: Threat Model
on: [push, pull_request]
jobs:
  pytm:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - run: pip install pytm
      - name: Generate threat report
        run: |
          cd tm
          python3 TM.py --report threats > threats.txt
          python3 TM.py --json threats.json
      - name: Fail on high severity threats
        run: |
          cd tm
          HIGH=$(jq '[.[] | select(.severity=="High")] | length' threats.json)
          echo "High severity threats: $HIGH"
          test "$HIGH" -eq 0
      - uses: actions/upload-artifact@v4
        with:
          name: threat-report
          path: tm/threats.txt

配置验证

  • python3 TM.py --dfd | dot -Tpng -o dfd.png 成功生成图片,且图中元素与边界与架构一致。
  • python3 TM.py --report threats 输出多条威胁,且包含自定义规则的 SID(如 BIZ01)。
  • 反向验证:把某个元素的 isEncrypted 由 True 改为 False 并重跑,报告应新增跨边界明文流的威胁条目,证明规则确实生效。
  • CI 验证:提交一次含高危威胁的改动,流水线应在「Fail on high severity threats」步骤失败。

常见问题(FAQ)

Q1:运行 pytm 报「dot: command not found」或图生成失败怎么办?

pytm 生成 DFD 与序列图依赖 Graphviz 提供的 dot 可执行程序,仅安装 Python 包不够。需单独安装 Graphviz 并确保 dot 在 PATH 中。若仅需威胁报告,可跳过 DFD 生成。

# Debian / Ubuntu
sudo apt install -y graphviz

# RHEL / Rocky
sudo dnf install -y graphviz

# 验证 dot 可用
which dot && dot -V

Q2:自动生成的威胁条目过多,评审时无法逐条讨论,如何落地?

建议做三层收敛:一是按目标元素筛选,只讨论跨信任边界的进程与数据流;二是按严重度排序并设定门槛(如只处理 High 与 Medium),其余登记为已知接受风险;三是把通用缓解措施标准化,例如「全链路 TLS」「统一输入校验」「统一鉴权中间件」,一次配置即可消除大批同类威胁。收敛后只保留需要产品与架构决策的少数条目进入评审。

Q3:威胁模型会不会因为属性写错而漏报威胁?

会,这是 pytm 类方法的主要局限:安全属性写得越乐观,漏报越多。缓解方式是三条纪律:元素属性必须由实际实现而非设计意图填写;把威胁模型产出纳入代码评审,由架构与安全双方共同确认;定期用反向验证(故意把属性置为不安全,确认威胁能被检出)检查规则是否仍然有效。

总结

威胁建模 STRIDE 的工程化落地,关键是把「文档」变成「代码」。pytm 让数据流图、威胁清单与整改状态都进入版本控制,可以随架构变更自动重跑,也能在 CI 中设置严重度门槛做增量拦截。实践顺序建议为:先定义边界与元素的真实安全属性,再运行内置规则得到基线清单,随后补充业务特有的自定义规则,最后把风险排序结果转化为可跟踪的整改任务并回归验证。这样威胁建模才真正进入研发流程,而不是评审会上的一次性材料。