第四章:水平越权测试:基于ID的参数遍历、批量分配漏洞、UUID可预测性分析
好,咱们进入第四章。水平越权,说白了就是「你能看到隔壁老王的数据」。这在API测试里太常见了。我做过那么多渗透项目,十个里面至少有六七个存在这类问题。今天咱们就把这块彻底讲透。
4.1 水平越权的本质
先理清概念。垂直越权是「普通用户干管理员的事」,水平越权是「用户A看用户B的数据」。两者都危险,但水平越权更隐蔽,也更难防御。
为什么会这样?因为很多开发人员觉得「只要用户登录了,就安全了」。他们忘了——登录只能证明你是谁,不能证明你该看什么。
我举个例子。一个电商API:
GET /api/orders/1001
Authorization: Bearer user_token_123
如果后端只校验token是否有效,没校验这个订单是否属于当前用户,那我把1001改成1002,就能看到别人的订单了。就这么简单。
4.2 基于ID的参数遍历
这是最基础,也是最常见的攻击方式。API里到处都是ID:用户ID、订单ID、商品ID、文章ID……只要这些ID是数字且递增,就存在遍历风险。
4.2.1 数字ID遍历
我在项目中遇到过这样一个案例。一个医疗平台的API:
GET /api/v1/patient/records/23456
返回了患者的病历信息。我试着把23456改成23457,居然也能访问。再改成23458,还是能访问。好家伙,整个数据库的病历全暴露了。
测试方法很简单:
- 先正常请求,拿到自己的资源ID
- 把ID加1或减1,看能不能访问
- 批量遍历,比如从1到10000
- 观察响应状态码和数据内容
用Burp Suite的Intruder模块,几秒钟就能跑完。但要注意——别跑太快,小心把人家服务搞挂了。
4.2.2 复合ID遍历
有些API用了复合ID,比如:
GET /api/orders/2024/03/1001
这种看起来复杂,其实一样。日期部分可以遍历,订单号部分也可以遍历。我见过一个系统,日期是用户注册日期,订单号是自增的。结果呢?攻击者只要知道目标用户的注册日期,就能遍历他的所有订单。
4.3 批量分配漏洞
这个有意思。批量分配漏洞(Mass Assignment),也叫「自动绑定漏洞」。它跟参数遍历不太一样,但同样危险。
4.3.1 原理
很多框架(比如Spring、Django、Laravel)支持自动将请求参数绑定到对象属性。如果开发人员没做限制,攻击者就能通过额外参数修改不该改的字段。
举个例子。用户注册API:
POST /api/register
{
"username": "test",
"password": "123456",
"email": "test@test.com"
}
如果后端直接绑定到User对象,我加个参数试试:
POST /api/register
{
"username": "test",
"password": "123456",
"email": "test@test.com",
"role": "admin"
}
你猜怎么着?有些系统真的会把这个用户创建成管理员。我在一次测试中就遇到过,直接注册了个管理员账号,然后……嗯,后面的你懂的。
4.3.2 测试方法
测试批量分配漏洞,我一般这么干:
- 先看API文档或抓包,了解所有参数
- 猜测可能的隐藏字段:role、is_admin、is_verified、balance、credit
- 在请求里加上这些字段,看响应有没有变化
- 重点关注创建和更新接口
4.4 UUID可预测性分析
很多人觉得「用了UUID就安全了」。嗯,这话对了一半。UUID确实比自增ID安全,但前提是——你得用对版本。
4.4.1 UUID版本
UUID有5个版本,咱们重点看前三个:
| 版本 | 生成方式 | 可预测性 |
|---|---|---|
| v1 | 基于时间戳+MAC地址 | 高 |
| v4 | 随机数 | 低 |
| v5 | 基于命名空间+哈希 | 中 |
v1 UUID的问题在于——它包含时间戳。如果你拿到一个v1 UUID,就能推算出生成时间。如果再拿到几个,就能推测出生成规律。
我曾经遇到一个系统,用的就是v1 UUID。我收集了100个UUID,解析出时间戳,发现它们之间的间隔很规律——每10毫秒生成一个。然后我就能预测下一个UUID大概是什么时候生成,再结合一些其他信息,就能猜出具体的UUID值。
4.4.2 测试方法
测试UUID可预测性,我一般分三步:
- 识别版本:看UUID的格式。v1 UUID的第13位是1,v4 UUID的第13位是4
- 收集样本:至少收集50-100个UUID,记录生成顺序和时间
- 分析规律:用工具(比如uuid-analyzer)分析时间戳分布
4.4.3 实战案例
说个真实的。一个金融平台的交易记录API:
GET /api/transactions/{uuid}
UUID看起来是随机字符串。但我抓了几个包,发现UUID的第13位是1——v1版本。我写了个脚本,解析出时间戳,发现这些交易记录是按秒生成的。然后我根据当前时间,往前推了24小时,生成了所有可能的UUID。结果呢?我拿到了当天所有的交易记录,包括别人的。
4.5 综合防御建议
讲了这么多攻击方法,咱们也得说说怎么防。我个人的经验是:
- 参数遍历:用UUID v4替代自增ID,或者加权限校验
- 批量分配:用白名单机制,只允许修改指定字段
- UUID可预测性:用v4版本,别用v1
但说实话,最根本的防御就一条——每次访问资源时,都校验当前用户是否有权限。别偷懒,别相信客户端传来的任何数据。
嗯,这一章内容不少。水平越权测试看起来简单,但真正做好不容易。我建议你多动手,多抓包,多分析。下一章咱们聊垂直越权,那个更刺激。