安全测试-02-API鉴权越权与未授权访问怎么测
接口安全测试里,最常见的误判之一是:
- 登录了,说明鉴权没问题
- 页面上按钮看不到,说明普通用户做不了
- 请求里带了 Token,说明接口是安全的
这些判断都太早了。
真正决定接口安全性的,不是“前端看起来限制住了没有”,而是下面这些事情在服务端是否真的成立:
- 当前请求是不是必须有合法身份
- 当前身份是不是有权访问这个资源
- 当前身份是不是有权执行这个动作
- 身份变化后,旧请求还能不能继续生效
所以 API 安全测试里,最先看的通常不是复杂漏洞,而是三件最基础也最高频的事:
- 鉴权
- 越权
- 未授权访问
这篇文章就只讲这三类问题怎么测,重点不是术语,而是怎么在真实业务里更快把问题筛出来。
一、先把三个概念分清楚,不然后面很容易测乱
1. 未授权访问
本质是:
本来应该先登录、先校验身份的接口,没有做这件事。
常见表现:
- 不带 Token 也能查数据
- Cookie 失效后仍能访问关键接口
- 内部接口直接暴露在外部链路上
2. 越权访问
本质是:
虽然登录了,但当前身份不应该访问这个资源或执行这个动作。
常见表现:
- A 用户可以查看 B 用户的数据
- 普通员工可以审批主管任务
- 普通账号可以调管理员接口
3. 鉴权缺陷
这是更大的集合,不只是“有没有登录”。
它包括:
- 身份校验缺失
- Token、Cookie、Session 校验不完整
- 权限模型和资源归属校验不完整
- 敏感动作缺少二次确认
这三个概念如果不先分开,后面很容易把所有问题都笼统记成“权限问题”,最后提单也提不清楚。
二、哪些接口最值得优先测
如果是业务系统,我优先级通常是这样排的:
- 用户详情、订单详情、审批详情、报表详情
- 修改资料、改密码、绑定手机号、修改邮箱
- 审批通过、驳回、删除、退款、封禁、开通权限
- 导出、下载、批量操作
- 管理后台接口
- 内部运维接口、调试接口、回调接口
这些接口值得优先看,不是因为名字敏感,而是因为它们背后通常存在:
- 资源归属
- 角色差异
- 数据边界
- 状态变更
只要这几个约束存在,就必须问一句:
服务端到底有没有重新校验,而不是只信前端。
三、更常用的一套测试顺序
如果时间有限,不适合一开始把所有接口都扫一遍。
更高效的顺序通常是:
1. 先拿到完整业务链路
例如一个报销审批系统,先正常跑通:
- 员工登录
- 创建报销单
- 提交审批
- 主管审批
- 财务打款
这一步最重要的产出不是“功能通过”,而是:
- 找出真正写操作的接口
- 找出业务主键,比如
taskId、orderId、applyId - 找出身份信息从哪里进入系统
2. 再准备最少三类账号
至少要有:
- 普通用户 A
- 普通用户 B
- 管理员或更高权限账号 C
很多越权问题测不出来,不是系统没问题,而是测试只拿了一个账号在反复点。
3. 先测未授权,再测同级越权,再测垂直越权
这是更推荐的顺序:
未授权访问
- 去掉 Token
- 去掉 Cookie
- 用过期 Token
- 用空 Authorization 头
看接口是不是还能继续访问。
同级越权
- 用 A 用户的请求
- 替换成 B 用户的资源 ID
- 看 A 是否能读到、改到、删到 B 的资源
垂直越权
- 用普通用户身份
- 重放管理员或审批人的关键请求
- 看普通用户是否能做高权限动作
这样顺序清楚,问题类型也更容易归类。
四、一套可直接执行的最小验证骨架
如果你要把接口安全测试变成稳定动作,而不是想到才试一下,建议至少固定下面这套骨架。
1. 建一张接口风险表
通常可以先列成这样:
| 接口 | 方法 | 身份要求 | 资源归属要求 | 动作级权限要求 | 首测动作 |
|---|---|---|---|---|---|
/api/order/detail |
GET | 必须登录 | 只能看自己的订单 | 无 | 换 orderId |
/api/order/refund |
POST | 必须登录 | 只能操作自己的订单 | 仅客服/财务可退款 | 换账号重放 |
/api/user/export |
POST | 必须登录 | 仅本部门数据 | 仅管理员可导出 | 换角色重放 |
/api/apply/approve |
POST | 必须登录 | 只能审批分配给自己的任务 | 审批角色 | 普通账号重放 |
这张表会直接决定你后面每个接口怎么测。
2. 固定 4 组基础动作
通常每个关键接口都会至少做这 4 组动作:
- 去鉴权信息
- 换资源 ID
- 换账号身份
- 重放旧请求
如果这 4 组动作都没问题,再考虑更细的签名、时间窗、nonce、流程串改。
3. 固定结果确认方式
不要只看响应码。
至少同时确认:
- 响应内容是否暴露了不该暴露的数据
- 列表页或详情页是否真的变化
- 数据状态是否真实落库
- 审计日志是否记录了错误身份的动作
很多接口表面返回 403,但数据已经提前被改了。
也有些接口返回 200,但实际没有落库,只是文案写得像成功。
五、最常见的 4 类问题
1. 只校验“有没有登录”,不校验“是不是这个人”
这种问题非常常见。
例如:
- 用户详情接口会校验 Token 合法
- 但不会校验
userId是否属于当前登录用户
结果就是:
- 任何登录用户只要改
userId - 都能查到别人的资料
这类问题往往不难测,但很容易漏,因为测试同学习惯只用自己账号看自己数据。
2. 页面按钮有限制,但后端接口没限制
这是管理后台和审批流里最常见的一类。
前端做了:
- 普通用户看不到“删除”
- 普通用户看不到“审批通过”
但后端没做:
- 当前用户角色校验
- 当前用户是否为任务处理人校验
这种问题在 Burp 或 Postman 里重放一下就能出来。
3. 使用旧 Token、旧 Cookie 仍然可访问
常见场景:
- 退出登录后旧请求还能继续生效
- 密码修改后旧会话仍然有效
- 角色变更后旧 Token 权限不变
这类问题尤其适合做回归用例,因为非常容易被后续改动重新带回来。
4. 批量接口只校验了入口,不校验每条资源
例如:
1 | { |
系统可能只校验“当前用户能调用批量删除接口”,却没校验这几个 id 是否都属于当前用户可操作范围。
结果就是批量接口往往比单个接口更容易出越权。
六、测试时很容易踩的几个坑
1. 只测读接口,不测写接口
会先测查询接口越权,但真正业务影响更大的,通常是:
- 修改
- 删除
- 审批
- 导出
- 退款
读越权和写越权要分开看,后者通常风险更高。
2. 只看 HTTP 状态码
200、401、403 只能说明一部分问题。
真正要看的是:
- 数据有没有泄露
- 状态有没有变化
- 动作有没有被执行
3. 忽略缓存和异步处理
有些接口第一次查是旧缓存,看起来像没问题。
但稍后刷新列表、查看操作日志、等异步任务执行完,问题才真正暴露出来。
4. 用错测试数据,导致误判
例如两个用户本来就有相同部门权限,结果换账号后仍能看到同一批数据。
这不一定是越权,而可能是数据本来就共享。
所以测试前一定先把资源归属关系准备干净。
七、真实案例:为什么“只有主管能审批”的系统,普通员工也能审批
场景
一个 OA 审批系统里,员工提交请假单后,只有直属主管可以审批。
功能测试时流程表现正常:
- 员工提交申请
- 主管登录后可以看到审批按钮
- 普通员工页面看不到审批按钮
团队最初认为这条链路没风险。
执行
先用主管账号抓到了审批请求:
1 | POST /api/leave/approve |
然后做了两步:
- 退出主管账号,登录普通员工账号
- 保留请求体不变,只替换成普通员工的
Authorization
现象
接口返回 200,响应内容显示“审批成功”。
刷新申请列表后,这条请假单状态真的变成了“已通过”。
这说明问题不是接口文案不严谨,而是服务端真实执行了审批动作。
排查
继续看代码和日志后,问题链路很清楚:
- 前端通过角色控制隐藏了审批按钮
- 后端接口只校验了用户是否登录
- 后端还校验了
applyId是否存在 - 但没有校验当前用户是否为该申请的审批人
也就是说,系统只做了“身份存在”校验,没有做“动作权限”校验。
修复
最后给出的修复建议有 4 条,不只是“补个 if”:
- 审批接口必须按当前登录用户重新校验审批权限
- 服务端必须校验申请单对应审批链和当前处理人
- 审批日志里记录操作者、原状态、目标状态和审批节点
- 增加自动化回归用例:
- 普通员工重放审批请求
- 预期返回
403 - 申请状态不能变化
- 审计日志不能记录成功审批
这类问题特别典型地说明了一点:
“页面不可见”从来不等于“服务端不可执行”。
八、怎么把这类测试稳定沉淀下来
如果只靠测试同学临场想起来改一下包,这类问题很难持续发现。
更合适的做法是沉淀成两层:
第一层:手工安全检查清单
上线前对高风险模块固定检查:
- 未登录是否还能访问
- 普通用户是否能看别人数据
- 普通用户是否能做高权限动作
- 退出登录后旧请求是否还能生效
- 批量接口是否逐条校验资源权限
第二层:关键回归用例自动化
把最关键的越权场景做成稳定用例,例如:
- 普通用户重放审批请求
- A 用户请求 B 用户订单详情
- 普通账号调用管理员导出接口
- 旧 Token 在角色变更后继续访问接口
这样后面权限模型改动时,问题才不会反复回归。
九、写在最后
API 安全测试里,最值得先做的不是追求覆盖很多漏洞名词,而是把最基本的边界先守住:
- 该登录的,必须登录
- 该隔离的,必须隔离
- 该限制角色的,必须按角色限制
- 该失效的旧会话,必须真的失效
如果这几件事没有做到,再复杂的安全建设都会显得很虚。
而对于测试来说,这类问题也最值得优先去抓,因为它们最接近真实业务风险,发现成本也最低,修复收益通常也最大。