4. 数据流图与系统建模
威胁建模不是凭空猜测攻击者会做什么,而是先要把系统“画清楚”。数据流图(Data Flow Diagram,DFD)正是这项工作的核心载体:它用少量固定元素描述数据从哪里来、经过哪些处理、在哪里停留、最终流向何处。相比架构图强调部署与技术栈,DFD更关注数据的移动路径与信任关系,因此天然适合用来发现“数据在哪个环节脱离了受控范围”。
一、DFD的四个基本元素
标准DFD只有四类元素,威胁建模中通常再叠加一条“信任边界”。理解它们的语义边界,比记住图形符号更重要。
- 外部实体(External Entity):系统边界之外、与系统交互的人、组织或外部系统,例如“用户浏览器”“支付网关”“运维人员”。它是数据的起点或终点,本身不受本系统控制,因此默认不可信。
- 进程(Process):对数据执行变换的逻辑单元,例如“登录校验”“订单创建”“报表生成”。进程是威胁建模中最需要关注的对象,因为绝大多数漏洞(注入、越权、逻辑缺陷)都发生在进程内部。
- 数据存储(Data Store):数据静止存放的位置,例如“用户表”“对象存储桶”“Redis会话缓存”。它关注的是“数据停在哪里”,对应静态数据保护与访问控制。
- 数据流(Data Flow):数据在实体、进程、存储之间的移动,例如“登录请求”“数据库查询结果”。数据流关注的是“数据怎么走”,对应传输加密与完整性。
绘制时建议统一约定:外部实体用矩形,进程用圆角矩形或圆形,数据存储用开口矩形(或双横线),数据流用带箭头的有向线。箭头方向必须与真实数据流向一致,不能为了排版美观而反向。
二、层级划分:从上下文图到Level 1
一张DFD不可能同时容纳整个企业系统,因此需要分层。常用做法是:
- Level 0(上下文图):把整个系统视为一个进程,只画它与外部实体的交互。它回答“系统边界在哪里、和谁交换数据”。
- Level 1:把Level 0中的系统进程拆成若干主要子进程,并引入主要数据存储。它回答“系统内部大致分成哪几块、数据在块之间怎么流”。
- Level 2及更深:对高风险或复杂子进程继续分解,直到每个进程的职责足够单一、可以逐条分析威胁为止。
分解要遵守“平衡原则”:父图中某个进程的输入输出数据流,必须与子图中该进程的边界数据流一致,不能凭空多出或少掉。否则说明分解过程中遗漏或臆造了数据路径,后续威胁分析会失真。
三、跨信任边界标注方法
信任边界是DFD在安全领域的灵魂。它表示“数据从一侧进入另一侧时,信任级别发生变化”。常见边界包括:互联网与企业内网之间、应用服务器与数据库之间、普通用户区与管理后台之间、本系统与第三方服务之间。
标注方法建议采用“虚线 + 标签”的形式:用虚线穿过被跨越的数据流,并在旁边标注边界名称与信任方向,例如“Internet→DMZ”“App→DB 内网”。关键原则有三点:
- 每条跨越边界的数据流都必须被识别,因为它是输入校验、认证、加密和审计的必设点。
- 边界两侧的信任假设要写清楚,例如“DMZ不可信,所有请求需重新校验”。
- 数据存储若位于边界一侧,要明确其归属,避免出现“数据库既在内网又被公网直连”的模糊画法。
四、绘制规范与常见错误
为了让DFD真正可用于评审和威胁建模,建议遵循以下规范:
- 每个进程至少有一个输入和一个输出,避免“黑洞进程”和“奇迹进程”。
- 数据流命名使用“名词+动词”或明确的数据对象,如“登录凭据”“订单详情”,不要写“数据”“请求”这类无信息量的词。
- 外部实体之间不直接连数据流,必须经过进程或明确说明是系统外行为。
- 数据存储不主动发起数据流,它只被进程读写。
- 同一层级内不重复出现同一进程的多个副本,除非确实存在多实例且信任关系不同。
常见错误包括:把网络设备(如防火墙)画成进程、把信任边界画成实线导致与数据流混淆、层级之间数据流不平衡、以及把“用户点击按钮”这类交互动作当成数据流。这些都会削弱DFD的分析价值。
五、一个可参考的绘制示例
假设一个简化的电商下单场景:用户通过浏览器提交订单,Web应用校验后写入订单库,同时调用支付网关完成扣款。其Level 1 DFD可包含外部实体“用户”“支付网关”,进程“订单服务”“支付服务”,数据存储“订单库”“支付流水”,以及跨越“Internet→DMZ”“DMZ→内网”两条信任边界的数据流。绘制时应重点标出:用户提交的订单参数在进入订单服务前是否经过校验、支付回调是否验证签名、订单库是否只允许内网访问。
这张图的价值不在于“画得好看”,而在于它把“用户请求进入DMZ”“订单服务访问内网数据库”“支付服务与外部网关交互”这三类高风险跨越点显式暴露出来。接下来做威胁建模时,就可以针对每条跨边界数据流逐一提问:是否做了身份认证?输入是否校验?传输是否加密?失败是否可审计?
掌握DFD元素语义、层级平衡规则和信任边界标注方法后,后续的STRIDE威胁识别、攻击树分析和安全控制设计才有稳定的分析对象。建议在实际项目中先完成Level 0和Level 1,再针对高风险进程做局部细化,避免一开始就陷入过度分解。