|
越权漏洞的越权测试,核心就一句话:用A用户的漏洞身份,去干B用户才能干的测试事,看系统拦不拦。越权拦住了,漏洞安全;没拦住,测试漏洞坐实。越权听起来简单,漏洞但真到测试的测试时候,坑比想象的越权多。 先拿最常见的漏洞水平越权开刀。假设你注册了两个账号,测试账号A和账号B。越权登录A,漏洞抓一个查询订单的测试请求,比如 GET /api/order/detail?orderId=1001。这个1001是A自己的订单,返回正常。现在把orderId改成1002——如果1002是B的订单,而系统直接把B的订单信息吐给了A,水平越权就成立了。测试的关键在于:你得确认1002确实属于B,而不是一个不存在的编号。很多人改完参数看到返回数据就兴奋,结果那数据其实是自己的,白高兴一场。 垂直越权稍微麻烦点。普通用户去调管理员接口,比如 POST /admin/user/delete。用普通账号的Cookie直接发这个请求,如果系统只在前端藏了按钮、后端没做角色校验,那删除操作照样执行。我见过一个后台,普通用户登录后菜单里看不到“用户管理”,但直接访问 /admin/users 页面,整个用户列表连密码哈希都渲染出来了。前端隐藏不等于后端拦截,这是两码事。 还有一种容易被忽略的:参数污染导致的越权。比如修改用户资料时,请求体是 { "userId": 123, "nickname": "test"}。你试着把userId改成别人的,或者干脆加一个 { "userId": 123, "targetUserId": 456, "nickname": "hacked"}。有些框架会自动绑定参数,后端如果从 targetUserId 取值而没校验归属,就直接改掉了别人的昵称。这种漏洞在Spring MVC的 @ModelAttribute 场景里出过不少。 测试时得注意HTTP方法。同一个URL,GET被拦了,POST不一定。比如 /api/user/update 用GET请求返回403,换成POST可能就200。还有PUT、DELETE、PATCH,挨个试。有些中间件只对特定方法做鉴权,漏掉其他方法。另外,记得测JSON和表单两种Content-Type,后端解析逻辑可能不同,校验也可能不同。 ID的形态也影响测试策略。自增数字最好猜,遍历就行。UUID看着随机,但如果接口返回了其他用户的UUID——比如评论列表里带了用户ID——照样能拿来越权。更隐蔽的是哈希ID,比如 orderId=md5(1001),如果你能拿到自己的哈希和别人的哈希,对比一下说不定能反推出规律。曾经有个电商站,订单ID是 base64(订单号+用户ID),解码后改用户ID再编码,直接越权查看他人订单。 批量测试工具能省力,但别全信。Burp Suite的Authz插件可以配两个Cookie自动替换重放,但有些接口依赖CSRF Token或时间戳,自动重放会失败。手动测虽然慢,但能观察到响应差异:状态码、响应体长度、错误信息。比如越权成功时返回200和完整数据,失败时返回403但body是 { "code": 403, "msg": "无权访问"},长度差很多,一眼就能分辨。 最后说个真实案例。某次测一个SaaS后台,普通用户能通过 GET /api/company/{ companyId}/members 拉取公司成员列表。我把companyId改成另一家公司的ID,接口返回了对方所有成员的姓名、邮箱和手机号。更离谱的是,这个接口还支持 ?role=admin 过滤,直接筛出对方的管理员账号。开发后来解释:他们以为companyId是前端传的,后端只校验了用户是否登录,没校验用户是否属于这个company。这种“信任前端参数”的思维,就是越权漏洞的温床。 测越权,本质是测信任边界。系统信任了哪些不该信任的输入——Cookie、Header、URL参数、请求体——哪里就可能出问题。别只盯着ID,多想想角色、归属、层级关系。一个请求发出去,先问自己:这个操作,当前用户真的有权限吗?如果答案模糊,那就值得一试。 |