2. 目标应用建模

DAST 的扫描质量,首先取决于我们是否把“被测系统”建模正确。很多团队把 DAST 简单理解为“输入一个 URL 然后点开始”,结果扫描器只爬到了首页和几个静态链接,真正的业务接口、单页应用路由、微服务网关后的服务全部漏掉。目标应用建模要解决的核心问题是:把用户能触达的每一个入口点、每一类参数、每一条业务流,转成扫描器可识别、可覆盖、可验证的对象清单。

一、从真实对象出发识别入口点

入口点(Entry Point)是外部输入进入应用的通道。建模时不要从“页面”出发,而要从“输入如何进入系统”出发。常见的真实对象包括:

  • URL 路径与查询串:如 /product/detail?id=1024&from=search,路径段和查询参数都是注入、越权、SSRF 的候选点。
  • HTML 表单:登录、注册、搜索、下单、上传,字段类型决定测试载荷(文本、文件、隐藏域、CSRF token)。
  • REST/GraphQL API:路径参数、查询参数、JSON body、Header(Authorization、X-Forwarded-For)、Cookie。
  • 单页应用(SPA)路由:#/order/123 或 history 模式下的 /order/123,爬虫往往看不到,需要从 JS 中提取路由表。
  • 微服务网关:网关暴露的聚合接口与后端服务接口可能不一致,网关层做鉴权、限流、路由重写,是攻击面收敛与放大的关键位置。

把这些对象整理成入口点清单时,建议至少记录:入口标识、协议方法、参数位置、参数类型、是否需要认证、所属业务域。下面这张图展示了从真实对象到攻击面清单的建模关系,以及各类入口在网关前后的分布。

目标应用建模:真实对象 → 入口点 → 攻击面清单 真实对象 URL / 查询串 /detail?id=1024 HTML 表单 登录 / 搜索 / 上传 REST / GraphQL API JSON body / Header SPA 前端路由 #/order/123 微服务网关 /api/v1/* 聚合 WebSocket / SSE 实时消息通道 入口点分类 路径 / 查询参数 注入 · 越权 · SSRF 请求体 / 表单字段 XSS · 命令注入 Header / Cookie 鉴权绕过 · 会话固定 文件上传 / 下载 路径穿越 · 恶意文件 实时通道消息 消息伪造 · 越权订阅 攻击面清单(可扫描对象) 入口标识 GET /api/v1/orders/{id} POST /api/v1/login 参数位置与类型 path: id (int) · query: from (str) body: username, password 认证与角色 需登录 · 普通用户 / 管理员 Token 位置:Authorization 业务域与优先级 订单 · 支付 · 用户中心 高价值接口优先扫描 业务流关联 登录 → 下单 → 支付 → 查询 建模目标:让扫描器知道“有哪些入口、每个入口带什么参数、需要什么身份、属于哪条业务流”

二、入口点分类与参数建模

入口点分类不是学术分类,而是为了决定“用什么载荷、以什么身份、按什么顺序”去测。一个实用的分类维度是参数位置与数据语义的组合:

参数位置典型示例优先测试方向
路径段/user/1001/profile越权访问、ID 遍历、路径穿越
查询串?q=test&page=1反射型 XSS、SQL 注入、SSRF
JSON Body{"role":"user"}参数篡改、批量赋值、类型混淆
HeaderX-Forwarded-ForIP 伪造、鉴权绕过、缓存投毒
Cookiesessionid=abc会话固定、JWT 篡改
文件字段avatar.png恶意文件上传、内容类型绕过

建模时还要标注参数的“可控性”和“回显性”。可控但无回显的参数适合盲注类测试;可控且有回显的参数适合 XSS 和模板注入。对于 SPA,需要从打包后的 JS 中提取路由表,例如在 app.js 中搜索 path:、component: 等关键字,把 /order/:id 这类动态路由还原成可访问的具体 URL。

三、业务流建模:把接口串成有状态的路径

单个接口测试通过,不代表业务流安全。业务流建模要回答:用户完成一个业务目标,需要按什么顺序调用哪些接口,携带什么状态。以电商下单为例,一条最小业务流是:

POST /api/v1/login          → 获取 token
GET  /api/v1/cart           → 读取购物车
POST /api/v1/orders         → 创建订单,返回 orderId
POST /api/v1/pay/{orderId}  → 发起支付
GET  /api/v1/orders/{id}    → 查询订单状态

建模时记录每一步的输入、输出和状态依赖:orderId 来自上一步响应,token 来自登录。DAST 工具需要按这个顺序执行,才能覆盖“越权查看他人订单”“支付金额篡改”“订单状态跳变”等只有在有状态上下文中才暴露的问题。如果只对每个接口单独发请求,很多业务逻辑漏洞会被漏掉。

建模小技巧:用浏览器开发者工具的 Network 面板录制一次完整业务操作,导出 HAR 文件,再从中提取请求序列、参数和依赖关系。这比手工翻代码快得多,也更接近真实用户行为。

四、微服务网关下的攻击面收敛

在微服务架构中,网关是外部流量的统一入口,也是攻击面建模的关键节点。网关通常做三件事:路由转发、鉴权校验、限流熔断。建模时要区分两类接口:

  • 网关暴露接口:如 /api/v1/orders,外部可直接访问,是 DAST 的主要目标。
  • 内部服务接口:如 /order-service/internal/query,通常不对外暴露,但如果网关路由配置过宽(如 /api/** 全部转发),就可能被外部触达。

因此,建模阶段要拿到网关的路由配置(如 Spring Cloud Gateway 的 routes、Nginx 的 location、Kong 的 service/route),逐条核对“哪些前缀被转发到了哪个服务”。对于 GraphQL 网关,还要提取 schema 中的 Query 和 Mutation 字段,因为单个 /graphql 端点背后可能对应几十个可调用的操作。

常见遗漏:只扫描网关暴露的 REST 接口,忽略 WebSocket 和 SSE 通道;只扫描主域名,忽略移动端 API 子域名和旧版本 /api/v0/ 接口。这些往往是攻击面清单中最容易被遗漏、也最容易出问题的地方。

五、攻击面清单的交付形态

建模的最终交付物是一份可被扫描器消费的攻击面清单。它不需要很复杂,但字段要完整、可执行。一个最小可用的清单条目应包含:入口 URL、HTTP 方法、参数名与位置、是否需要认证、所需角色、所属业务流、优先级。下面是一个示例条目:

{
  "entry": "GET /api/v1/orders/{id}",
  "params": [
    {"name": "id", "in": "path", "type": "integer"},
    {"name": "fields", "in": "query", "type": "string"}
  ],
  "auth": true,
  "role": "user",
  "flow": "order-query",
  "priority": "high"
}