3. 常见越权类型详解:水平越权与垂直越权
这一章我们直面权限系统的两大“天坑”——水平越权和垂直越权。我在做代码审计时,十次越权漏洞里有八次就栽在这俩兄弟手上。说白了,它们就像一对双胞胎:一个偷偷横向跨账户,一个垂直爬楼层。但它们的本质完全不同,应对策略也天差地别。咱们一个一个掰开揉碎了讲。
3.1 什么是水平越权?
水平越权(Horizontal Privilege Escalation, 也称横向越权)是指攻击者以自身权限等级,访问了同等级下其他用户的资源。比如你登录了自己的银行账户,却能修改张三的转账地址。权限等级没变,但操作的“业务主体”错了。
我记得早期给一个SaaS平台做安全评估时,发现用户A通过修改URL中的数字参数就能看到用户B的订单详情。那感觉就像你走进一间开放式办公室,顺手拉开了隔壁同事的抽屉——明明大家都是普通员工,但你却看到了别人的工资单。
3.1.1 水平越权的常见场景
- 用户ID可枚举的API接口:GET /api/order/1001 改成 /1002,返回别人的订单。
- 无用户身份绑定的查询:后端只检查了登录状态,没检查“这个资源属于谁”。
- 批量操作遗漏验证:批量删除功能只验证了一次,却没逐条校验归属。
- 共享资源的ID暴露:内部ID(如employee_id、file_id)直接作为参数传递。
3.1.2 一个典型的水平越权代码
这段代码我改了个简化版,但结构几乎和我当年看到的一模一样——可怕的是它跑在生产环境里很久了。
@GetMapping("/order/{orderId}")
public Order getOrder(@PathVariable Long orderId) {
// 只检查了是否登录,没检查orderId是否属于当前用户
return orderRepository.findById(orderId);
}
问题在哪里?orderId没有与当前用户ID做关联。任何登录用户只要猜到或遍历orderId,就能拿到别人的订单。这种代码我们内部叫“裸奔接口”,除了登录墙什么都没做。
3.2 什么是垂直越权?
垂直越权(Vertical Privilege Escalation, 也称纵向越权)是另一个方向——攻击者以低权限角色,执行了高权限角色才能做的事情。比如普通用户调用管理员接口,或者游客绕过登录直接访问后台。
我处理过一个比较刺激的案例:某个后台管理系统,前端隐藏了"删除用户"按钮,但后台API根本没有角色鉴权。只要用浏览器开发者工具找到这个API路径,普通用户直接POST就能删管理员账号。嗯,那次甲方经理的脸都绿了。
3.2.1 垂直越权的两种常见形态
| 类型 | 描述 | 典型例子 |
|---|---|---|
| 未授权访问 | 接口未做任何权限校验,任何角色均可调用 | GET /admin/users 返回全部用户列表,但未校验角色 |
| 权限绕过 | 低权限用户通过参数篡改或接口枚举,获取高权限 | 普通用户加参数 role=admin,后端就赋予管理员能力 |
3.2.2 一个典型的垂直越权代码
@PostMapping("/admin/deleteUser")
public String deleteUser(@RequestParam Long userId) {
// 没有任何角色检查,任何人都可以调用
userService.deleteById(userId);
return "deleted";
}
看到没?@RequestMapping路径里写了/admin,但Spring不会自动按路径做鉴权。前端隐藏了按钮,后台却毫无防备。这就像把大门锁了但把窗户开着——你只是没告诉别人窗户在哪,不代表别人找不到。
3.3 水平越权 vs 垂直越权:核心区别
这两种越权经常被混在一起说,但咱们得从根源上分清楚。我个人习惯用一张表格来对比,看完你会一目了然。
| 对比维度 | 水平越权 | 垂直越权 |
|---|---|---|
| 权限级别 | 同级权限 | 跨级权限 |
| 攻击方向 | 横向,同角色间 | 纵向,低角色→高角色 |
| 根源漏洞 | 资源属主校验缺失 | 角色或功能鉴权缺失 |
| 典型参数 | user_id, order_id, file_id | role, admin接口路径, 特殊header |
| 攻击难度 | 较低(需要枚举ID) | 较低(前端隐藏≠安全) |
| 防御重点 | 数据层面做属主绑定 | 接口层面做角色/权限校验 |
⚠ 我曾经踩过的坑:有一次我查水平越权,发现后端已经做了属主校验——但校验逻辑是写在业务Service层的,Controller层没做。结果攻击者绕过Service直接调DAO层接口……越权依然存在。所以校验不止要写对位置,还要写在正确的层级。
3.4 一张图理清越权分类体系
下面这张SVG图把水平越权和垂直越权的结构关系画出来了。你顺着箭头看,就能明白它们各自的位置和攻击入口。
3.5 实战中如何快速区分?
你在审计API时,拿到一个越权报告,怎么判断它是水平还是垂直?我给自己定了一个“两步定位法”分享给你:
- 看权限等级是否变化:如果攻击者使用的仍然是普通用户,那他大概率是水平越权。如果用了普通用户的调了管理员接口,就是垂直越权。
- 看操作的资源是否属主:假如权限没变,只改了资源ID就能看别人数据 → 水平越权。假如角色变了或访问了角色专属路径 → 垂直越权。
💡 避坑指南:我曾经遇到一个系统,它的水平越权是通过修改"用户角色"字段来实现的——一个普通用户把自己的role改成"admin"后,看到了所有订单。严格来说这是垂直越权,但数据层面又像水平越权。你判断时要以“最终访问的资源是否超出了该角色应有的数据范围”为准。别被参数名字带偏了。
3.6 两种越权的审计关注点
我在做审计时,会分别列出检查清单。下面这个表格是从我的个人笔记里扒出来的,你写审计方案时可以直接参考。
| 审计方面 | 水平越权检查点 | 垂直越权检查点 |
|---|---|---|
| 参数 | 所有业务ID(订单、文件、用户ID)是否进行了属主校验 | 所有角色相关的参数、路径、header是否经过了授权拦截 |
| 接口 | 查询/修改/删除类接口,尤其是批量操作 | 管理类接口、配置类接口、用户管理接口 |
| 数据 | 接口返回数据是否携带了多个用户的敏感信息 | 低角色是否能调用高角色专属的数据导出、日志查询等 |
| 工具 | Burp Suite修改ID参数、遍历枚举 | Burp修改Cookie/Role、添加admin路径前缀 |
📌 老工程师给个提示:做审计时别只顾着看代码。你可以在测试环境登录两个不同用户的账号,用A的访问B的资源——能访问就是水平越权。再用普通用户访问管理接口——能访问就是垂直越权。嗯,这个“两步法”帮我抓了至少十几个线上的漏洞。
好了,水平越权和垂直越权的基本概念、区别和审计要点我们过了一遍。接下来你可以直接从代码层面入手,看看怎么给这些接口加上正确的鉴权逻辑——不过那是其他章节的事情了。这一章你只要记住:水平越权防的是左顾右盼,垂直越权防的是上下乱窜。