news 2026/9/15 13:10:59

API越权漏洞自动化检测:Hadrian+Vespasian+crAPI本地部署实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
API越权漏洞自动化检测:Hadrian+Vespasian+crAPI本地部署实战

API 越权漏洞自动化检测是我最近反复折腾的一个方向。越权漏洞说起来简单,但真要在几十个接口里找出“哪个接口能看别人数据、哪个接口能调管理员功能”,手工点一天也未必能覆盖完整。我最后搭了一套本地组合:Hadrian 负责扫描编排,Vespasian 负责异步执行,crAPI 当靶场,总算把整个流程跑顺了。这篇东西就是把当时的部署过程、配置思路和踩坑记录整理出来,给同样在做 API 安全测试、或者想学习越权漏洞的工程师一个参考。整套环境建议在本地或者授权的测试环境里玩,不要拿去做未授权测试。

1. 为什么用 Hadrian + Vespasian + crAPI 这一套

1.1 API 越权漏洞的本质与测试难点

越权漏洞在 API 里通常分两类:一类是对象级越权,也就是常说的 BOLA(Broken Object Level Authorization),比如订单详情接口写死了/order/123,普通用户把 123 改成 124,就能看到别人的订单;另一类是功能级越权,也就是 BFLA(Broken Function Level Authorization),比如普通用户直接请求管理员删除用户的接口,服务器没有校验角色权限。

这两类漏洞的共同点是:接口本身是正常的,参数和请求格式也都正确,纯粹是“授权逻辑”缺失。所以传统的漏洞扫描器非常难扫出来,因为扫描器只能判断“请求是否报错”“页面是否异常”,没法判断“这个用户有没有权限看这条数据”。手工测倒是能测,但接口一多就非常痛苦,要反复注册账号、切换 token、对比两个用户看到的数据差异,而且越权往往藏在业务逻辑层,黑盒测试很容易漏。

我在 crAPI(一个故意设计成存在大量 API 漏洞的靶场)上试过最土的办法:注册两个账号,手工写脚本逐个接口对比响应。结果发现接口数量超过 30 个之后,脚本里到处是硬编码的 ID、Token、请求头,维护成本极高,换一个接口就要改一次。后来才决定引入专门的自动化检测链路。

1.2 三个工具的分工

这套组合里,三个工具的角色非常清晰:

  • crAPI 不是扫描器,它是“猎物”。它是一个模拟真实业务的 API 靶场,有注册登录、车辆管理、社区、优惠券等模块,里面埋了各种越权漏洞。把它当作扫描目标,既安全又可控。
  • Hadrian 是“大脑”。它负责定义扫描策略、解析 API 文档、生成越权测试任务。比如它会从 OpenAPI / Swagger 里抽取出所有接口,标记哪些接口带路径参数,哪些接口需要认证,然后决定用什么方式做对象级越权和功能级越权检测。
  • Vespasian 是“手脚”。它从队列里拉取 Hadrian 生成的任务,真正去发 HTTP 请求,把响应结果写回存储。把“扫描编排”和“请求执行”拆开,好处是任务可以并行、可以重试、可以横向扩展,扫描一批接口时不会因为单个请求超时卡死整个流程。

实际跑起来就是:Hadrian 先分析目标,把“用 A 用户请求 /user/123,再用 B 用户请求 /user/123,对比响应”这类任务丢到队列里,Vespasian 的 worker 拿到任务后开始请求,最后所有结果汇总回 Hadrian 的报告模块。整个过程不需要写一堆手工脚本,策略变更也只改配置。

1.3 为什么不直接用商业扫描器

可能会有朋友问,市面上商业 API 安全扫描器也不少,为什么折腾这一套?我自己的体验是:商业扫描器在“已知漏洞指纹”上很强,但越权测试需要知道业务上的“资源从属关系”,它很难理解。比如两个接口都不是标准漏洞特征,但响应体里一个返回了用户手机号,一个返回了“无权限”,这种业务语义差异,商业扫描器基本只能靠规则碰运气。

另一个原因是二次开发能力。Hadrian 和 Vespasian 都是开源项目,策略代码在手里,扫描规则可以自己加。比如我想自定义一个“批量赋值”检测规则,直接在 Hadrian 的检测模块里加一个插件就行。这点在内部测试平台里非常关键,因为每个公司的 API 风格和权限模型都不一样,能改代码的扫描器才真正好用。

2. 部署前需要准备的环境

2.1 本地环境与资源建议

我建议准备一台至少 8GB 内存的机器。整套环境要跑 crAPI 的几个后端服务、数据库、消息队列、Hadrian 和 Vespasian 的执行器,全部加起来内存占用非常可观。我自己在 16GB 内存的笔记本上跑是流畅的,但有一次在 4GB 的小机器上硬跑,Vespasian 的 worker 频繁被系统杀掉,日志里全是 OOM。

操作系统方面,Windows、macOS、Linux 都能跑,前提是 Docker 环境正常。如果是在 Linux 服务器上部署,建议用 Docker Engine 配合 Docker Compose 插件;如果在 macOS 或 Windows 上用 Docker Desktop,注意给 Docker 分配足够的内存,不要用默认的 2GB。这里多说一句,如果机器资源紧张,可以先只启动 crAPI 和 Vespasian,Hadrian 先不启动,等需要扫描时再拉起来。

磁盘方面预留 20GB 以上空间,因为要拉取的镜像里包含了各种运行时和数据存储,单个镜像几百 MB 很正常。

2.2 Docker 与 Docker Compose 安装验证

部署之前需要确认 Docker 环境可用。在终端里执行:

docker --version docker compose version

如果docker compose没有找到,说明 Compose 插件还没装。现在新版的 Docker Engine 通常自带 Compose v2 插件,旧环境需要单独安装。装完之后先跑一个测试容器:

docker run --rm hello-world

看到 “Hello from Docker!” 说明 Docker 本身没问题。要注意一点,如果之前装过旧版 Docker Toolbox 或者一直用老旧的 docker-compose,建议统一升级到 Compose v2,命令是docker compose(中间有空格)而不是docker-compose。新的 compose 文件在解析变量、指定网络、健康检查上都更靠谱,后面部署这套东西会少很多麻烦。

2.3 拉取项目与镜像

三个工具的代码仓库都不一样,建议统一放在同一个工作目录下。我用的是:

mkdir -p ~/api-security-lab cd ~/api-security-lab git clone <crAPI仓库地址> git clone <Hadrian仓库地址> git clone <Vespasian仓库地址>

这里我没有写具体仓库地址,因为项目更新比较快,直接去对应项目的 GitHub 首页复制地址最稳妥。拉代码的时候要用 git clone,不要手动下载 zip,后面要切换分支或者拉更新会非常麻烦。

拉完代码之后,先别急着docker compose up。花两分钟看一下每个项目根目录下的 README 和.env.example,确认当前版本需要的环境变量。很多部署问题不是工具本身有 bug,而是版本变了,环境变量名字变了,配置还按旧文档写,结果启动直接报错。我的习惯是先把.env.example复制成.env,再逐个改里面的端口、密码、Token 密钥。

3. crAPI 靶场部署

3.1 启动 crAPI 服务

crAPI 的启动方式基本是一个命令:

cd crAPI cp .env.example .env docker compose up -d

第一次启动会拉取一串镜像,时间取决于网速,耐心等就行。启动完成后用docker compose ps看一下容器状态,正常状态应该是所有服务都是Up,没有反复重启的迹象。

crAPI 本身由多个服务组成:API 网关、业务后端、身份认证服务、数据库、邮件服务等。启动后默认 Web 访问端口在8888(具体以当前版本 README 为准),邮件服务可能在另一个端口。如果本地端口有冲突,可以修改 compose 文件里的端口映射,比如把"8888:8888"改成"8889:8888",左边是宿主机端口,右边是容器内端口。这个细节很容易踩坑,改了端口之后,后面 Hadrian 配目标地址也要跟着改。

启动之后浏览器访问http://localhost:8888,能看到注册登录页面就说明 crAPI 起来了。

3.2 注册账号与获取基础配置

crAPI 的注册逻辑和真实业务很接近,要求填邮箱、密码、手机号等。邮箱填入一个看起来真实但不存在的地址就行。注册完之后,crAPI 不会真的发外部邮件,而是把邮件内容显示在它自带的邮件服务里,入口一般在网页右上角或者专门的/mail路径。从这个邮件服务里可以拿到激活链接或者客户端 ID 之类的信息。

越权测试通常需要两个或多个账号,所以至少要注册两个。为了方便识别,我习惯用user1@test.comuser2@test.com这样的邮箱,手机号也填不同的。之后为了避免密码记混,统一用一个测试密码。

这里有个小技巧:注册时把“账号拥有者”和“被越权目标”的数据差异化。比如 user1 的车牌号填 AB-12345,user2 的车牌号填 CD-67890。后面扫描器判断越权时,如果 user1 请求 user2 的资源却返回了 CD-67890,那基本可以确定为对象级越权,而不是因为数据恰好一样导致的误判。

3.3 crAPI 里值得关注的越权场景

crAPI 虽然是靶场,但它设计的接口节奏非常接近真实商业 API。我梳理过的几类典型场景:

  • 用户信息接口带主键 ID,修改 ID 可能返回他人资料。
  • 车辆控制接口只校验是否登录,不校验车辆归属,A 用户能操作 B 用户的车辆。
  • 优惠券、订单、社区帖子等资源接口存在对象级越权。
  • 部分管理员接口只做了隐藏,没有做权限校验,普通用户直接请求也能访问。

这些场景非常适合验证 Hadrian 和 Vespasian 的检测能力。我们在本地把这套流程跑通之后,再拿到有授权的真实测试环境里,替换掉目标地址和认证配置,逻辑是一样的。毕竟越权检测的关键不是“用什么工具”,而是“工具能不能理解资源归属关系”。

4. Hadrian 与 Vespasian 部署与配置

4.1 Hadrian 配置解析

Hadrian 启动前需要改配置文件,一般是 YAML 格式。下面这个是我在本地用的配置片段,核心思路是:让 Hadrian 先解析 crAPI 的 OpenAPI 文档,再用两个账号的 Token 做对比测试。

target: base_url: "http://crapi:8888" openapi_path: "/openapi.json" auth: mode: "bearer" login_endpoint: "/auth/login" credential: user1: email: "user1@test.com" password: "Test@123" user2: email: "user2@test.com" password: "Test@123" token_field: "access_token" rotate_user: true scan: concurrency: 10 timeout: 10 checks: - bola - bfla - mass_assignment

逐个说下关键项。

target.base_url要特别注意,这里是http://crapi:8888而不是http://localhost:8888。因为 Hadrian 和 crAPI 都在 Docker 网络里,用容器名crapi访问才能走内部网络;如果写 localhost,从 Hadrian 容器里访问的是它自己,会连接拒绝。

auth.rotate_user是越权检测的灵魂。打开之后,Hadrian 会交替使用两个账号的 Token 去请求同一个资源接口,然后对比响应。如果关闭,扫描器就只会用 user1 一个身份,很多越权场景根本测不出来。

scan.concurrency控制并发请求数。第一次跑不要调太高,10 就够。并发太高,crAPI 这种小靶场可能直接拒绝服务,返回一堆 429 或者 500,反而干扰结果判断。

4.2 Vespasian 执行器配置

Vespasian 的配置重点在队列和 worker 数量。它默认需要连一个消息队列,可以是 Redis。如果和 Hadrian 一起部署,确保 Redis 的地址和密码在两边配置成一样的,不然 Hadrian 往队列里写任务,Vespasian 读不到。

Vespasian 的 worker 配置大概长这样:

queue: type: redis host: redis port: 6379 password: "" worker: concurrency: 16 retry_on_failure: true max_retries: 3 timeout: 30

worker.concurrency代表同时处理多少个任务。这个值不是越大越好,它受到 CPU、内存、目标接口响应速度的综合影响。在 crAPI 这种本地靶场上,16 足够;如果扫描外部授权目标,可以从 4 开始试探着往上调。

有个细节值得提:timeoutmax_retries一定要配。越权检测里经常遇到某个接口响应特别慢,或者偶尔 500,如果没有超时控制,一个任务会一直占着 worker,直到整条队列积压。设置 30 秒超时和 3 次重试,能明显提高扫描稳定性。

4.3 启动并验证服务健康状态

配置改完就可以启动了。我这里假设 Hadrian 和 Vespasian 各自在同一个 compose 文件里,或者被同一个 external 网络管理:

cd hadrian docker compose up -d cd ../vespasian docker compose up -d

启动后分别看日志:

docker compose logs -f hadrian docker compose logs -f vespasian-worker

健康的日志里应该能看到服务成功连接 Redis、等待任务之类的信息。如果 Vespasian 连不上 Redis,日志里会直接甩出 connection refused,这时候先检查.env里 Redis 的密码和 host 是否跟实际一致。

我这里强烈建议先把 crAPI 和这套扫描链路放到同一个 Docker 网络里。最简单的方式是启动 crAPI 时记住网络名,然后在 Hadrian 和 Vespasian 的 compose 文件里用 external 网络指过去。很多朋友部署完发现 Hadrian 能启动,但扫描时全部连接失败,最后排查下来就是网络隔离问题,容器之间根本 ping 不同。

5. 自动化越权检测的实际操作流程

5.1 配置扫描目标与认证信息

Hadrian 一般都提供 UI 或 REST API 来配置扫描任务。以 UI 为例,进入管理页面后找到 “Targets” 或 “New Scan”,添加目标时填写:

  • 目标名称:给这次扫描起个名字,比如crAPI-local
  • 目标地址:http://crapi:8888
  • API 文档地址:http://crapi:8888/openapi.json

认证信息这里有两种做法。一种是在配置里写死账号密码,让扫描器自动去登录获取 Token;另一种是先把两个 Token 手动在页面里填入,扫描器直接使用。我推荐第一种,因为 crAPI 的 Token 有效期有限,自动登录能保证扫描期间 Token 都是新的。不过要注意,登录接口的返回字段要填对,token_field要匹配 crAPI 实际返回 JSON 里的字段名,我见过最典型的问题就是字段名填错了,导致扫描器拿到一个空 Token,所有请求全部 401。

5.2 开始一次扫描

配置完成后,选择要执行的检测项,我只勾选了 BOLA、BFLA 和批量赋值,然后点击启动。Hadrian 会先做一次接口梳理:从 OpenAPI 文档里提取所有 path,标记带路径参数的接口,比如/identity/{user_id}这种,然后把它们作为对象级越权的重点检测对象。

整个扫描过程不需要人盯着。Vespasian 会不断从队列里取任务执行,我这边观察到的典型日志类似:

task user2_request_with_user1_token: /identity/2 task: compare_response_body_by_source task result: high_confidence_bola

看到high_confidence_bola这种结果,基本说明发现了一个高置信度的对象级越权漏洞。扫描结束之后,页面会生成一份报告,列出所有检测过的接口,以及每个接口的检测结果。

5.3 报告里的字段与真伪判断

报告里常见的字段包括:

  • 请求地址和方法
  • 使用的账号身份
  • 被访问的具体资源 ID
  • 两个账号请求同一资源时的响应状态码
  • 响应体长度差异
  • 响应体关键字段是否包含不属于当前账号的数据
  • 置信度和漏洞类型

看报告时不要只盯着状态码。很多越权不是靠状态码暴露的,比如返回码都是 200,但 user1 的响应体里返回了手机号、真实姓名、车辆 VIN 码,这就是越权。相反,如果两个用户的响应体只有创建时间不同,而业务字段都是空的,那可能是正常数据,不一定算越权。

一个很实用的验证方法:报告里发现可疑接口后,手动用 curl 重放一遍。我从 crAPI 上发现过/identity/user/2越权时,重放命令类似这样:

curl -H "Authorization: Bearer $TOKEN_USER1" http://localhost:8888/identity/user/2 curl -H "Authorization: Bearer $TOKEN_USER2" http://localhost:8888/identity/user/2

user1 请求 user2 对应的资源 ID,如果返回的数据里带的是 user2 的邮箱或手机号,基本就能确认问题。这一步不可省,自动化工具的价值在于缩小范围,最终确认还是要靠人。

6. 常见问题与排查实录

6.1 Docker 网络通信问题

我自己遇到最多的问题就是容器之间访问不了。典型现象是 Hadrian 日志里全是dial tcp: lookup crapi: no such host,但 crAPI 明明在运行。

原因通常有两个。第一,Hadrian 和 crAPI 不在同一个 Docker 网络里。解决办法是让两个容器加入同一个网络:

docker network create api-scan-net docker network connect api-scan-net crapi docker network connect api-scan-net hadrian

第二,配置文件里写了localhost。容器里的 localhost 指的是容器自己,一定要用服务名或容器名。这个坑我踩了不止一次,现在写配置前都会先确认目标服务在 compose 里的 service name。

6.2 Token 或认证信息不生效

扫描刚开始,所有请求都返回 401,排查思路按顺序来:

  1. 登录接口地址对不对,crAPI 的登录路径可能是/auth/login,也可能是/identity/auth/login,要以 OpenAPI 文档为准。
  2. 返回字段名对不对,crAPI 返回的是access_token还是data.token?填错了照样 401。
  3. Token 是否过期,如果扫描时间很长,可以在 Hadrian 里配置自动 refresh,或者改用 Vespasian worker 里的 token 刷新逻辑。

这里有个特殊情况:有些越权漏洞本身就是“不校验 Token”,扫描器如果发现某个接口无论带什么 Token 都返回同样的数据,报告里可能会标记成“认证失效”而不是越权。这两种漏洞要分开上报,因为修复方案不一样,前者是加认证校验,后者是加权限校验。

6.3 误报与漏报的处理策略

自动化工具免不了误报。以 crAPI 为例,有些接口会给未登录用户返回“欢迎页数据”,给已登录用户返回“用户面板数据”,响应体长度差异很大,扫描器可能误以为是越权。

我的经验是调整 Hadrian 的“响应对比策略”。不要只看长度,要设置一个字段黑名单,把timestamprequest_idsession_id这类动态字段排除掉,聚焦在业务数据字段上。然后在报告里按置信度排序,优先人工复核高置信度的结果。漏报的问题更棘手,通常要靠增加测试账号和丰富数据差异来解决。我一开始只注册两个账号,很多越权场景测不到;后来注册了四个不同角色账号,扫描覆盖率明显提升。

6.4 排查速查表

症状可能原因处理方式
hadrian 报 no such host容器不在同一网络 / 用错 target 地址配置使用服务名,connect 到同一 docker network
vespasian worker 连不上 redisRedis host/密码不一致检查 compose env,确认 host 和密码
所有请求 401登录接口或 token_field 配置错误 / token 过期检查 OpenAPI,修正 auth 配置,开启自动登录
扫描任务积压不执行队列没有 worker / worker 挂掉docker compose ps 检查 worker 状态,看日志
报告大量误报动态字段导致响应对比失真配置字段黑名单,调整置信度阈值
容器频繁重启内存不足调整 Docker memory 限制,关闭不用的容器
端口被占用宿主机端口冲突修改 compose 端口映射,注意同步修改 target URL

这条速查表是我这次部署过程中最常用的东西。很多时候不是工具坏了,而是环境和配置的问题,按这个顺序排查,基本能解决 90% 的问题。

7. 一点个人使用体会

整套组合跑通之后,我把 crAPI 上的越权接口基本上都扫出来了,比自己手工写脚本效率高不少。不过我也得说句实话,自动化检测再怎么方便,也不能完全替代人工分析。工具只能告诉你“这两个响应不一样”,但“为什么不一样、是不是越权、影响范围多大”,还是得人去判断。我现在的习惯是,每周在本地靶场跑一次这套流程,把新增的漏洞场景更新到 crAPI 或者自己的测试应用里,再反过来验证扫描器的能力。另一个实用的小技巧是:正式扫描之前先导入两套业务差异足够大的测试数据,比如一个账号有订单,一个账号没有订单,这样扫描器对不同响应会更加敏感。后续如果想扩展,可以在 Vespasian 里增加埋点,把每次越权请求都记录下来,形成自己的自动化回归用例集,这样以后 API 版本更新时可以直接重放验证。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 13:10:53

Kettle增量同步实战:从时间戳到CDC的完整方案与避坑指南

做了这些年数据工作&#xff0c;Kettle一直是我处理日常数据同步的首选工具之一。最近好几个项目都在聊“增量同步”&#xff0c;不少同事和朋友问我&#xff1a;用Kettle怎么做增量&#xff0c;而不是每天傻乎乎地全量拉一遍。这确实是很多团队都会遇到的现实痛点——数据量越…

作者头像 李华
网站建设 2026/9/15 13:09:15

网盘文件直链怎么在浏览器里拿到?这个开源油猴脚本支持九大网盘

网盘文件直链怎么在浏览器里拿到&#xff1f;这个开源油猴脚本支持九大网盘 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云…

作者头像 李华
网站建设 2026/9/15 13:07:14

kubeadm init报错unknown flag --network-plugin的完整排查与修复指南

如果你执行kubeadm init时卡在 kubelet 启动环节&#xff0c;等一会儿终端里冒出一行error execution phase kubelet-start&#xff0c;下面跟着command failed" err"failed to parse kubelet flag: unknown flag: --network-plugin&#xff0c;那你遇到的和我是同一…

作者头像 李华
网站建设 2026/9/15 13:07:01

Unity后处理实战:从PostProcessing配置到性能优化全指南

搞Unity有一阵子的朋友&#xff0c;迟早会碰到一个绕不开的需求——画面太平了。明明模型、材质、灯光都摆得挺齐整&#xff0c;可渲染出来就是一股“素颜”味。这时候就该PostProcessing登场了。这篇文章从一个实际项目的落地视角&#xff0c;聊透Unity里后处理怎么装、怎么配…

作者头像 李华
网站建设 2026/9/15 13:06:10

行测图形推理完整指南:程序员按题型拆解的规律速记与考场策略

行测图形推理完整指南&#xff1a;程序员按题型拆解的规律速记与考场策略 【免费下载链接】developer2gwy 公务员从入门到上岸&#xff0c;最佳程序员公考实践教程 项目地址: https://gitcode.com/GitHub_Trending/de/developer2gwy 行测卷面里&#xff0c;图形推理通常…

作者头像 李华
网站建设 2026/9/15 13:05:45

PyQt5 + PaddleOCR 桌面OCR标注工具实战解析

简介&#xff1a;一份基于PyQt5与PaddleOCR实现文字识别的Python项目源码&#xff0c;定位为毕业设计、课程大作业或项目初期立项演示的优质范例&#xff0c;主要面向计算机、人工智能、物联网等专业的在校学生和开发者&#xff0c;帮助解决图形界面下快速完成图片文字提取与编…

作者头像 李华