拓冰建站拓冰建站
首页 / 资讯中心 / 正文

API越权漏洞自动化检测实战:crAPI+Hadrian+Vespasian组合

先聊一个我最近实际做过的实验在本地搭了一套 crAPI 靶场把 Hadrian、Vespasian 这两个工具串联起来专门用来跑 API 越权漏洞的自动化检测。整个过程做下来最大的感受是“越权”这种漏洞太适合用自动化去挖了因为它的检测逻辑足够机械只要请求能换对象、换身份、换资源 ID就能比人肉点接口快得多也全得多。这篇文章不是纯翻译官方 README而是我基于实际部署和使用的记录整理了完整的思路、环境和命令。里面会包含 crAPI 的启动方式、Hadrian 做攻击面梳理的流程、Vespasian 生成并执行越权验证请求的玩法以及我在跑通这套流程时踩过的坑。适合刚接触 API 安全测试、想了解自动化越权检测或者想搭一个本地“练手场”的人参考。1. 越权检测为什么要自动化先说清楚一个概念越权漏洞在 OWASP API Security Top 10 里属于对象级授权缺失也就是很多人挂在嘴边的 IDORInsecure Direct Object Reference。它的本质是服务端在处理请求时只拿到了对象 ID却没有校验这个 ID 是否属于当前登录用户结果导致用户 A 能通过改参数访问用户 B 的数据或者普通用户能通过调接口触发管理员才能干的操作。越权分横向和纵向两类。横向越权是两个同级用户之间的数据串位比如我登录后把订单 ID 从 1001 改成 1002就看到了别人的订单。纵向越权是低权限角色使用高权限接口比如普通账号调用管理员的删除接口。这两类漏洞在真实业务里出现频率很高而且危害程度不低但很多团队在测试时容易漏掉原因也很简单接口数量太多参数组合太多一个个手工改写请求再对比响应效率低到没法坚持。自动化检测的思路和手工测试是一致的本质上都是做三件事收集接口和参数替换对象或身份令牌观察响应是否正确。区别在于自动化能把“替换 对比”这个过程循环跑几百上千次而且能把每次请求的响应落在报告里方便复现和整改。这也是我最终选择“靶场 攻击面扫描 验证脚本”组合的原因crAPI 提供目标环境Hadrian 负责把目标环境的接口和资产梳理清楚Vespasian 负责批量构造越权请求并输出结果。很多人可能会担心自动化工具误报率高其实越权类漏洞的误报反而比较好过滤因为它有一个明确的判断标准请求是否使用了另一个用户或权限级的身份却仍然返回了成功或完整数据。只要在自动化流程里加入响应对比和状态码校验误报率能压到一个比较低的水平。2. 这套组合的分工逻辑2.1 crAPI专门给你练手用的脆弱 API 靶场crAPI 是一个故意做脆弱的 Web 应用全称是 Completely Ridiculous API由 OWASP 社区的人维护主要用途就是给安全测试人员做 API 攻击练习。它不像 DVWA 或 WebGoat 那样专注在网页漏洞上而是把漏洞点都放在了 API 接口里从注册登录、找回密码到论坛发帖、车辆追踪各种业务场景都有每个场景背后都藏着不同的 API 缺陷。对越权测试来说crAPI 最大的价值在于接口数量足够多、用户体系足够完整。它可以注册多个用户每个用户有自己独立的车辆、帖子、优惠券和地址信息这就为横向越权提供了天然的测试样本。我只需要注册两个账号就能用账号 A 的令牌去请求账号 B 的资源判断服务端是否做了正确的归属校验。crAPI 本身的业务设计也贴近真实应用不是那种一个接口打天下的 demo所以测出来的结果在真实场景里有参考价值。2.2 Hadrian先把攻击面摸清楚再动手Hadrian 在我这套组合里的角色是“侦察兵”。它主要做攻击面发现也就是从目标域名或 IP 出发去收集相关的子域名、IP 段、开放端口、Web 服务、API 路径等信息。这样做的目的很直接测试越权漏洞之前总得先知道目标有哪些接口、哪些路径是 API 入口、哪些服务暴露在公网不然验证脚本连往哪儿发请求都不知道。用 Hadrian 跑 crAPI 的本地环境时它会先把 8888 端口的 Web 服务和配套的服务域名梳理出来再对响应内容做初步标记区分页面和接口。这个阶段输出的结果相当于给后续的 Vespasian 提供了一份“攻击面清单”让验证脚本不用漫无目的地去爬路径而是拿着清单里的接口逐一做越权测试。比起完全靠手工翻前端代码抓接口效率提升是很明显的。2.3 Vespasian负责把越权请求批量打出去Vespasian 是我用来做请求生成和验证的工具它解决的核心问题是“怎么高效地构造大量越权测试用例”。它的思路和主流 API 模糊测试工具类似但又更聚焦在身份和对象替换上可以复用已经登录的会话并对请求参数做替换变形再根据响应分发结果。由于这个领域工具迭代很快不同仓库的 Vespasian 命令行参数可能不太一样我建议你在本地装完后先看一眼 README确认目标地址、输出路径和并发数这几个常用参数怎么写。它的关键能力是“场景模板化”。我可以定义一条基础请求比如“查询订单详情”然后把其中的订单 ID 标记为变量Vespasian 会基于这个模板批量生成请求把 ID 依次替换为用户 B 的订单号、不存在的订单号、负数、超长数字等等。每一条请求都带着当前用户的令牌发出去然后收集响应码、响应体长度和关键字段最后汇总成一张结果表我再根据表里的差异做人工确认。3. 环境准备把 crAPI 靶场完整跑起来3.1 部署 crAPI 的两种方式crAPI 官方提供了 Docker Compose 的部署方式这也是我最推荐的方式。它把 Web 服务、数据库、消息队列等组件封装到了一套编排文件里只要本机装好了 Docker基本两条命令就能启动全套服务。git clone https://github.com/OWASP/crAPI.git cd crAPI/deploy/docker docker compose --compatibility up -d这里有个小细节--compatibility参数是为了兼容不同版本的 Docker Compose某些旧版本如果不加这个参数会识别不了部分配置项导致服务启动失败。如果你用的是新版 Docker Compose也可以直接docker compose up -d具体看本机报错提示再做调整。crAPI 启动后默认的 Web 入口是http://localhost:8888HTTPS 入口是https://localhost:8443。如果需要在真实浏览器里注册用户和抓请求包建议直接用 8888 这个地址证书相关的坑会少一些。3.2 验证服务是否启动成功启动容器后不能直接就开始测试需要先确认服务已经正常监听端口。下面这几条命令是我每次都会跑的docker ps curl -s http://localhost:8888/api/healthdocker ps用来确认 crAPI 相关容器都处于 Up 状态curl用来验证 API 服务是否返回正常响应。如果健康检查接口返回的 JSON 里包含 “ok” 之类的字段说明服务基本可用。要注意的是crAPI 首次启动时数据库初始化需要一定时间如果在 curl 时出现连接拒绝或超时等 20 到 30 秒再试一次不要急着排障。3.3 容器化部署时常见的启动问题我在第一次部署时遇到过端口冲突因为本机 8888 端口已经被其他服务占用crAPI 的 Web 服务起不来。排查方式很简单先看docker ps -a里容器状态是不是一直在重启再用lsof -i:8888看端口占用情况。解决方法是修改 docker-compose 里的端口映射比如把“8888:80”改成“8899:80”然后重新启动。另一个常见问题出在 Docker Desktop 的网络模式上。部分 Windows 或 macOS 环境下容器里的服务能正常启动但宿主机访问不到端口原因往往是 Docker Desktop 的网络代理设置有问题。处理方式是检查 Docker Desktop 的 Resources 和 Network 配置必要时把代理关掉再重启 Docker。这台靶场本来就应该在本地隔离环境里跑不需要走代理。4. Hadrian 扫描目标环境的完整流程4.1 部署与初始化API Token 的获取方式我用的 Hadrian 版本是官方提供的在线服务式组件这说明它可以作为本地评估步骤也可能通过云集成。它通常会提供一个管理员入口或 API Token 管理界面用来生成访问令牌。测试前所有的目标范围配置和扫描结果查询都要带上这个 Token。具体操作上先在目标管理页面配置扫描范围。对本地靶场把localhost或对应的 IP 加进去如果 crAPI 部署在远程服务器就把服务器的域名或 IP 配置为范围。配置完成后创建一次 API Token并把它放到环境变量里方便后续脚本调用export HADRIAN_API_TOKEN你的token4.2 发起资产发现扫描初始化完成后我用命令行或交互式面板发起了第一轮资产发现扫描。扫描目标直接指向 crAPI 的入口地址因为本地靶场的资产规模不大几分钟就能跑完。扫描完成后Hadrian 会输出一份包含域名、路径、服务类型和端口信息的清单我会重点翻两点API 接口路径列表比如/api/community/posts、/api/forum、/api/identity这些带明显 API 特征的路由。非 Web 服务比如数据库端口或消息队列端口虽然越权测试用不上这些但了解暴露面有助于后续做更完整的风险评估。4.3 从扫描结果里提取测试对象拿到清单之后不是所有接口都适合做越权测试。只有那些带资源 ID、用户 ID、订单编号等参数的接口才可能是越权漏洞的藏身之处。Hadrian 扫描结果里通常会标注请求方法、路径参数和响应码我可以据此快速筛出一批候选接口。筛选原则有三个优先选 GET 请求里带数字 ID 的接口比如/api/coupon/{id}这种最容易出现 IDOR。其次选 POST 请求体里有用户维度字段的接口比如创建订单时传入了用户 ID。最后选 DELETE 或 PUT 这种操作类接口因为越权删除或修改往往危害更大。筛选出的接口会形成一个列表我会把它整理成 Vespasian 的输入文件作为下一阶段的测试范围清单。5. Vespasian 自动化验证越权的实战玩法5.1 设计越权用例不只是改一个 ID越权用例的设计是整个流程里最重要的部分。很多新手做 IDOR 测试时只想着把 ID 改成别人的 ID这是远远不够的。Vespasian 的价值恰恰在于它能系统化地生成各种“越权变形”我一般会覆盖以下几类资源 ID 遍历将 ID 依次替换为其他用户已创建的资源 ID。身份切换同一个请求分别使用普通用户 A 和普通用户 B 的令牌去访问。权限提升用普通用户令牌访问管理端接口或者给请求加一个管理员身份的 Header 字段。参数污染在请求里同时出现两个同类参数时服务端是否取了后面的值比如id1001id1002。特殊取值ID 为 0、负整数、超长整数、字符串型数字等用于探测服务端是否会跳过校验。刚开始跑的时候只做“ID 替换”这一项也能测出很多问题但要想提高覆盖率建议把上面几类都加进去。Vespasian 的优势就是这些用例一旦写成模板后续可以反复复用新接口接入成本很低。5.2 执行批量验证并保存结果当用例设计好后我执行验证时使用了会话管理模块先预置了用户 A 和用户 B 两个账号的登录态稍后发起请求时自动携带对应的 Cookie 或 Authorization Header这样不同角色的隔离就很清晰。具体执行时通常会这样组织一次运行任务vespasian run --target http://localhost:8888/api \ --case idor_order_query.txt \ --user userA.session \ --output ./reports/api_idor_result.json执行任务前我会先跑一次小范围测试确认用例模板没有语法错误。小范围没问题后再全量执行因为批量测试产生的请求量比较大如果目标环境性能较弱并发太高容易把服务打挂也会影响测试结果。官方一般会提供并发参数建议从低到高逐步调别一上来就顶到极限。5.3 用响应对比矩阵来判定越权是否成立判定越权成立不能只看响应码是不是 200。我采用的方法是构造一个响应对比矩阵把每次请求的状态码、响应体长度、响应时间、关键字段值放在一起比较请求场景响应码响应体长度是否包含目标用户关键字段判定用户A查询自己资源2001024是基线用户A查询用户B资源2001024是存在横向越权用户A查询不存在ID404128否正常用户A调用管理员删除20032是存在纵向越权基线请求是用户 A 访问自己的正常资源后续请求都要和基线做对比。如果用户 A 访问用户 B 的资源时响应码和响应体长度都和基线一致基本可以判定服务端没有做资源归属校验越权漏洞成立。如果返回的是 403 或响应体很小的一段错误信息说明服务端做了权限校验这个用例就不算漏洞。判定逻辑背后有一个很实用的原则所有越权验证都应先用“存在性”验证作为基础再辅以业务语义的确认。比如我看到用户 B 的资源 ID 被用户 A 成功读取这只是存在性我再进一步确认响应体里的数据确实属于用户 B这就完成了业务语义的确认漏洞报告也更有说服力。6. 扫描结果的分析、修复与复测6.1 误报过滤的“三查”法自动化测试跑完第一时间要做的是过滤误报。我不会立刻把 Vespasian 标红的报告丢给开发而是按“三查”流程走一遍查身份确认请求时确实使用了低权限或不同用户的身份没有误用管理员令牌。查结果确认响应体确实是目标数据而不是一个泛化的提示信息比如“查询成功”但没有数据。查逻辑确认这个接口的业务逻辑里该用户本来就不应该能访问目标资源。有些接口虽然是公开查询接口但返回的数据本身不敏感这类不算严重越权。这个流程看着简单但能省很多沟通成本。漏报的多误报的多了更烦。开发同学一看到报告里一堆假的“越权”后续再提漏洞配合度就会下降。6.2 crAPI 里的越权接口修复示例以 crAPI 里一个典型的越权场景为例某个查询车辆信息的接口请求参数包含车辆 ID但服务端只根据车辆 ID 查询并返回信息没有校验当前用户是否绑定了这辆车。修复方案很明确在服务端代码中先根据令牌获取当前用户信息再校验车辆 ID 是否属于该用户校验不通过就返回 403。伪代码大概是这个样子def get_vehicle_info(request): user get_current_user(request.token) vehicle_id request.query.get(vehicle_id) vehicle db.query(Vehicle, idvehicle_id) if vehicle.user_id ! user.id: return 403, 无权访问该车辆 return 200, vehicle这里的关键是“先鉴权后返回”。很多开发在修复时会顺手把 ID 改成不可逆的 UUID这能增加猜测难度但并不能从根上解决问题。只要服务端不校验资源归属UUID 照样可以被同一用户通过前端泄露的接口路径发现。修复的核心永远是“用户是否能访问这个资源”而不是“这个 ID 是否容易被猜到”。6.3 修复完成后的回归验证修复完成后的回归验证很多人会忽略但这步特别重要。我会重新跑一遍 Vespasian 任务确认之前上报的接口不再返回目标数据同时也会顺手确认正常的访问没有被影响比如用户 A 仍然能访问自己的车辆信息。回归测试最好把之前的整个用例集都跑一遍而不是只跑报漏洞的那几条。因为修复代码有时会引入新的问题比如在所有接口里统一加了权限校验结果把一些本应公开的接口也拦住了。全量回归能及早发现这种问题避免上线后出事故。7. 常见问题与排查技巧实录我下面按实际遇到频率整理了问题速查表基本上照着这个顺序排查能解决大部分部署和使用中的卡壳问题。问题现象可能原因解决办法crAPI 容器一直重启端口被占用或数据库初始化失败先docker compose logs查看日志再调整端口映射访问 8888 端口超时Docker 网络模式问题或启动时间不足等待 30 秒后重试检查 Docker Desktop 网络设置Hadrian 扫描不到任何资产Token 未生效或扫描范围配置错误确认 Token 已写入环境变量检查地址是否包含 http/httpsVespasian 请求全部 403会话过期或用例里没带令牌重新登录并刷新 session 文件检查请求头加载逻辑越权用例全部判定为正常用例里替换的参数是公共资源换一个带明确归属关系的资源再试比如订单、消息、私密文件批量请求把靶场打挂了并发数设置过高降低并发数分批执行用例除了表格里的问题还有几个心得值得单独说。第一做越权自动化之前先把目标环境的网络隔离做好别有外网暴露测试接口又不是生产系统没必要挂在公网上。第二每次跑任务前清空上一次的报告目录不然新旧结果混在一起时间对不上复盘时很痛苦。第三多用“保存请求”的思路Vespasian 或 Burp Suite 里把关键请求保存下来后续写用例模板时直接改参数就行比重录一遍省事太多。这套自动化方案跑通之后最大的收益不是我测出了多少漏洞而是把整个测试流程沉淀成了一套可复用的脚本和用例集。只要 crAPI 里新增了业务模块或者换了新的靶场应用我只要更新一下目标地址和接口清单就能在十几分钟内完成一轮越权检测。这个模式从“人工点接口”升级到“批量验证”补上了手工测试最大的短板——覆盖率。如果你是做 API 安全测试、搞代码审计或者正在为内部上线前安全检查发愁可以考虑把这套流程在你的本地环境里复现一遍磨顺之后再往实际项目上迁移。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门