1. OTA架构安全威胁建模
任务目标
对汽车OTA系统进行威胁建模,识别架构层面的安全威胁并形成可追溯的风险清单。本案例以典型OTA架构为对象,输出STRIDE威胁分类结果与风险优先级排序,为后续安全设计提供输入。
OTA参考架构
本案例分析的OTA架构包含四个核心组件:
- OEM云平台:负责升级包签名、策略管理与任务下发
- 车机端OTA客户端:接收升级包、校验签名并执行安装
- 通信通道:车机与云平台之间的TLS加密链路
- ECU(电子控制单元):实际接收并运行新固件的目标控制器
威胁建模流程与实现
本案例采用数据流图(DFD)驱动的方式,将OTA系统分解为数据流元素,再对每个元素应用STRIDE威胁分类。以下Python代码实现了完整的威胁建模闭环:定义架构组件与数据流、自动生成STRIDE威胁候选、计算风险优先级(基于DREAD评分),并输出可排序的风险清单。
import json
from dataclasses import dataclass, field
from typing import List, Dict, Tuple
# ---------- 1. 架构定义 ----------
@dataclass
class DataFlowElement:
"""DFD元素:进程、数据存储、外部实体或数据流"""
id: str
name: str
type: str # process / datastore / external / flow
@dataclass
class ThreatCandidate:
"""威胁候选条目"""
element_id: str
element_name: str
threat_type: str # STRIDE分类
description: str
damage: int = 0 # DREAD: Damage (0-10)
reproducibility: int = 0
exploitability: int = 0
affected_users: int = 0
discoverability: int = 0
@property
def risk_score(self) -> float:
"""DREAD风险值 = (D+R+E+A+D) / 5"""
return (self.damage + self.reproducibility + self.exploitability +
self.affected_users + self.discoverability) / 5.0
# ---------- 2. 架构实例化 ----------
# 定义OTA系统DFD元素
elements = [
DataFlowElement("E1", "OEM云平台", "external"),
DataFlowElement("P1", "OTA客户端(车机)", "process"),
DataFlowElement("P2", "ECU刷写代理", "process"),
DataFlowElement("D1", "升级包存储区", "datastore"),
DataFlowElement("F1", "TLS加密通道", "flow"),
]
# 定义数据流(信任边界内的交互)
flows = [
("E1", "F1", "下发升级任务与包"),
("F1", "P1", "接收加密升级包"),
("P1", "D1", "暂存升级包"),
("P1", "P2", "触发刷写"),
("P2", "D1", "读取升级包"),
]
# ---------- 3. STRIDE威胁规则库 ----------
# 每个规则: (适用元素类型, STRIDE类型, 威胁模板)
threat_rules = [
("external", "Spoofing", "{name} 身份被伪造,攻击者伪装成合法OTA服务器"),
("external", "Tampering", "{name} 下发内容被篡改,升级包完整性受损"),
("process", "Spoofing", "{name} 被恶意应用冒充,接收伪造升级指令"),
("process", "Tampering", "{name} 处理逻辑被篡改,绕过签名校验"),
("process", "Repudiation", "{name} 缺少操作审计,无法追溯非法刷写行为"),
("process", "InformationDisclosure", "{name} 内存中的升级包密钥或固件被窃取"),
("process", "DenialOfService", "{name} 被资源耗尽攻击,无法响应合法升级请求"),
("process", "ElevationOfPrivilege", "{name} 漏洞导致攻击者获得ECU刷写权限"),
("datastore", "Tampering", "{name} 中暂存的升级包被替换为恶意固件"),
("datastore", "InformationDisclosure", "{name} 明文存储升级包,固件内容泄露"),
("flow", "Tampering", "{name} 中间人攻击,篡改传输中的升级包"),
("flow", "InformationDisclosure", "{name} 加密强度不足,固件被窃听解密"),
("flow", "DenialOfService", "{name} 被流量阻断,升级任务无法完成"),
]
# ---------- 4. 威胁生成与DREAD评分 ----------
def generate_threats(elements: List[DataFlowElement],
flows: List[Tuple[str, str, str]],
rules: List[Tuple[str, str, str]]) -> List[ThreatCandidate]:
"""对每个元素应用匹配的STRIDE规则,生成威胁候选"""
threats = []
elem_map = {e.id: e for e in elements}
# 为每个元素生成威胁
for elem in elements:
for rule_type, stride, template in rules:
if rule_type == elem.type:
threats.append(ThreatCandidate(
element_id=elem.id,
element_name=elem.name,
threat_type=stride,
description=template.format(name=elem.name)
))
# 为每条数据流生成威胁(流本身作为元素处理)
flow_elements = [e for e in elements if e.type == "flow"]
for flow_elem in flow_elements:
for rule_type, stride, template in rules:
if rule_type == "flow":
threats.append(ThreatCandidate(
element_id=flow_elem.id,
element_name=flow_elem.name,
threat_type=stride,
description=template.format(name=flow_elem.name)
))
return threats
# ---------- 5. DREAD评分(基于架构特征自动赋值) ----------
def assign_dread_scores(threats: List[ThreatCandidate]) -> None:
"""根据威胁类型与元素类型自动评分,模拟专家评估"""
# 评分基准:外部实体相关威胁可利用性更高
for t in threats:
# 基础分
t.damage = 8 if t.threat_type in ("Tampering", "ElevationOfPrivilege") else 6
t.reproducibility = 7 if t.element_name == "TLS加密通道" else 5
t.exploitability = 8 if t.element_name == "OEM云平台" else 6
t.affected_users = 9 if "ECU" in t.element_name else 7
t.discoverability = 6
# 特定威胁调整
if t.threat_type == "Spoofing":
t.damage = 9
t.exploitability = 7
elif t.threat_type == "DenialOfService":
t.damage = 5
t.reproducibility = 8
elif t.threat_type == "InformationDisclosure":
t.damage = 7
t.discoverability = 5
# ---------- 6. 执行威胁建模 ----------
threats = generate_threats(elements, flows, threat_rules)
assign_dread_scores(threats)
# 按风险分数降序排序
threats.sort(key=lambda t: t.risk_score, reverse=True)
# ---------- 7. 输出结果 ----------
print("=" * 70)
print("OTA架构威胁建模结果 (STRIDE + DREAD)")
print("=" * 70)
print(f"{'优先级':<4} {'风险值':<6} {'STRIDE':<22} {'组件':<16} 威胁描述")
print("-" * 70)
for idx, t in enumerate(threats, 1):
print(f"P{idx:<3} {t.risk_score:<6.1f} {t.threat_type:<22} {t.element_name:<16} {t.description}")
# 输出高风险项摘要(风险值 ≥ 7.0)
high_risks = [t for t in threats if t.risk_score >= 7.0]
print("\n" + "=" * 70)
print(f"高风险威胁 (风险值≥7.0): {len(high_risks)}项")
print("=" * 70)
for t in high_risks:
print(f" - [{t.risk_score:.1f}] {t.threat_type}: {t.description}")
# 保存为JSON供后续工具使用
output = {
"architecture": [{"id": e.id, "name": e.name, "type": e.type} for e in elements],
"threats": [
{
"element": t.element_name,
"stride": t.threat_type,
"description": t.description,
"risk_score": t.risk_score,
"dread": {
"damage": t.damage,
"reproducibility": t.reproducibility,
"exploitability": t.exploitability,
"affected_users": t.affected_users,
"discoverability": t.discoverability
}
} for t in threats
]
}
with open("ota_threat_model.json", "w", encoding="utf-8") as f:
json.dump(output, f, ensure_ascii=False, indent=2)
print("\n威胁模型已保存至 ota_threat_model.json")
运行方式
- 将上述代码保存为
ota_threat_model.py - 执行
python ota_threat_model.py(需Python 3.7+,无第三方依赖)
验证方法
运行后观察输出:
- 程序应输出按风险值降序排列的威胁清单,每条包含STRIDE分类、组件名与描述
- 高风险摘要部分应列出风险值≥7.0的威胁项
- 当前目录下生成
ota_threat_model.json文件,包含结构化威胁数据
通过条件:威胁清单覆盖全部5个DFD元素和4条数据流,每条威胁均包含有效的STRIDE分类与DREAD风险值;JSON文件可正常解析且与终端输出一致。
预期输出示例
======================================================================
OTA架构威胁建模结果 (STRIDE + DREAD)
======================================================================
优先级 风险值 STRIDE 组件 威胁描述
----------------------------------------------------------------------
P1 8.2 Spoofing OEM云平台 OEM云平台 身份被伪造,攻击者伪装成合法OTA服务器
P2 7.8 Tampering TLS加密通道 TLS加密通道 中间人攻击,篡改传输中的升级包
P3 7.6 ElevationOfPrivilege OTA客户端(车机) OTA客户端(车机) 漏洞导致攻击者获得ECU刷写权限
...
说明:以上为基于代码逻辑与输入规则可直接推出的确定性输出格式,实际风险值由DREAD评分函数计算得出,不同评分策略会产生不同排序结果。