WebGoat越权靶场实战:从访问控制失效到IDOR与垂直越权
发布时间:2026/10/19 6:12:25 锦皓数字建站

刚把WebGoat 2023里的Broken Access Control模块完整走了一遍从最开始对着页面发呆到后面闭着眼也能猜到它要考什么。这个模块是我见过最适合用来理解“越权”概念的靶场之一它把隐藏字段、对象直接引用、缺失功能级访问控制、多步骤流程绕过这类问题拆成了一节节小课每一节都能亲手复现一个真实漏洞场景。如果你正准备入门Web安全或者已经刷过一些靶场但总觉得对“权限校验”理解不透这篇东西应该能帮你省不少时间。文章按我实际通关的顺序来写不跳步每关会给出思路、请求样例和判定条件最后附了一堆我自己踩过的坑。整篇面向的是手上有一个可用靶场、想搞清楚Broken Access Control到底考什么的读者你不需要有很深的安全基础能看懂简单的HTTP请求就够。1. 环境准备与工具清单1.1 启动靶场几行命令跑起来WebGoat是一个Java写的Web漏洞训练靶场我这边用的2023版本拿到的是一个可执行的jar包。启动之前先确认本机装了JDK版本建议用11以上实测在JDK 17上跑得很顺。启动命令很直接java -jar webgoat-2023.x.jar --server.port8080看到日志里出现Started WebGoat in xx seconds就说明起来了。浏览器访问http://localhost:8080/WebGoat会自动跳到登录/注册页面。这里有个很容易忽略的细节如果8080端口被别的程序占了启动会直接报错。我第一跑的时候就是本地一个服务占了8080导致白等了一分钟才反应过来。换端口再启动就行比如--server.port8888后面所有请求路径里也要跟着改端口。也有人喜欢用容器方式起靶场一条命令就能拉起来本质是一样的关键是容器里端口要映射到宿主机。无论哪种方式只要浏览器能打开登录页环境就算准备完毕。1.2 不可缺少的抓包工具练Broken Access Control浏览器开发者工具只能算辅助真正的主力是HTTP拦截代理。简单说这类工具站在浏览器和服务器中间可以看到浏览器发出去的每一个请求也可以手动改完再放行。没有它后面一半以上的关卡都玩不了。代理端口尽量不要也选8080和靶场端口撞了会很混乱。我常用的是把代理监听端口设为8888然后在浏览器代理设置里填上127.0.0.1:8888。这里有一个真实的坑不少浏览器默认忽略本机代理地址需要在浏览器设置里手动把“回环流量走代理”打开否则抓不到包。如果靶场访问地址是HTTPS还需要额外安装代理工具生成的CA证书到浏览器受信任列表。好在WebGoat默认走HTTP的多这个坑遇到的人不多。但是提前把证书这事搞清楚后面自己玩别的HTTPS靶场会少走很多弯路。1.3 账号准备与角色概念进入WebGoat后先注册一个用户很多同学直接用自己的邮箱随便注册一个这在前面课程没问题但到了Broken Access Control后半段尤其是垂直越权和水平越权相关关卡系统要求你以特定身份登录比如guest、alice、tom、admin这一类预置账号。我不止一次因为当前登录账号不对怎么做都判定失败后来才意识到是自己用错身份了。我的做法是把预置账号当成通关凭证每进入一个新的子课程先看一眼页面提示里要求用谁的身份。不要嫌麻烦登出、清理Cookie、再登录这几步在后面的关卡几乎成了标准动作。有些浏览器开多个标签页共享会话登出操作只在一个标签页生效另一个标签页还是旧会话排查问题时要格外留意这一点。2. 访问控制漏洞的底层原理2.1 访问控制失效到底是什么Broken Access Control翻译过来是损毁的访问控制更常见的叫法是越权。它指的不是密码被爆破、也不是提交框里有恶意脚本而是服务器对“当前用户能不能做这件事”或者“当前用户能不能看这个数据”的校验做漏了。比如一个普通用户能访问管理员页面或者登录A账号能看到B账号的订单都属于访问控制失效。很多新手容易混淆认证和授权这两个概念。认证解决的是“你是谁”通常是登录、写入Session授权解决的是“你能干什么”也就是对每个请求判断角色和资源归属。WebGoat这里的靶场题目绝大多数不是要你绕登录而是要你绕过“授权”这一步。你去看很多现实漏洞报告会发现越权漏洞的危害被严重低估。水平越权能扒出大批同级别用户的个人资料垂直越权直接就是一个普通用户变管理员最严重的能拿到系统底层权限。所以这个模块被放在安全风险榜非常靠前的位置一点不冤。2.2 水平越权、垂直越权与IDOR的关系访问控制漏洞常被分成三类这在后面通关时是选路线的关键。水平越权指相同权限级别的用户之间互相访问数据经典场景是学生A修改请求里的学号看到了学生B的成绩单。垂直越权指低权限用户拿到高权限能力比如访客角色直接调用“删除用户”接口。还有一类很隐蔽但出现频率极高的IDOR全称是Insecure Direct Object Reference意思是“不安全的直接对象引用”。IDOR的本质是服务器把数据库里的主键、文件ID这一类对象标识直接暴露在URL或请求参数里并且没有校验当前用户是否拥有这个对象。它可能造成水平越权也可能配合角色漏洞变成垂直越权。在WebGoat里IDOR单独占了一课后续的水平越权/垂直越权关卡也建立在相同思路上。记住一句话看到请求里出现用户ID、订单号、文件名这类参数第一反应应该是“能不能改成别人的”。2.3 客户端信任边界的误区接触这套靶场之后最大的认知转变是永远不要相信从浏览器发过来的东西。隐藏字段、下拉框选项、按钮权限显示这些都只存在于客户端用户改起来只需要一个抓包工具。前端隐藏一个菜单不等于后端没有这个接口JS提示你无权限不等于服务器会拒绝你页面把价格字段设成readonly不等于提交的时候不能改。WebGoat有不少关卡故意在前端放一个障眼法比如一个靠前端判断角色才显示的按钮目的就是让你体会“前端限制根本不是限制”。真正的权限边界只应该在服务端画出来。所有敏感操作、敏感数据接口服务端在收到请求后都应该重新鉴权而不是相信请求里带的角色字段或者某个隐藏参数。3. 通关实战隐藏字段与IDOR3.1 Hidden Fields改一次隐藏参数就能过去进入Broken Access Control最开始两课相对温和其中Hidden Fields这节课很有代表性。页面看起来像一个商品购买表单里面有商品名称、数量还有个不出现在页面上的字段。用抓包工具继续往下点请求里会看到形如price199quantity1的参数而price并不是页面上明显可编辑的输入只是藏在HTML表单里的input typehidden。做法不复杂抓包拦截这个提交请求把price改成0或者一个很小的数放行后看响应。如果服务端没有再次校验就会按你提交的价格处理通关提示随即弹出。这个关卡之所以经典是因为它完美演示了“客户端提交的数据直接被信任”的典型问题。在这个关卡里还要注意一个细节有些题改价格前服务器会先查一次数据库里的价格然后和你提交的一起判断。如果你的请求里既有id又有price那可以把眼光放到id上改成别的商品ID再组合提交多试试总有一个参数是信任链上的突破口。版本不同参数名可能不同可能是price、total、amount、role但思路一致在关键业务参数上做文章观察服务端反应。3.2 IDOR对象引用直接暴露在URL里Insecure Direct Object References这节课比Hidden Fields多绕几个弯完整版通常分两到三个子任务。第一个子任务是查看某个指定用户的资料。进入课程后页面上会有一个类似“View Profile”的按钮点一下会在当前页展示一份用户信息同时浏览器的地址栏里能看到一个很关键的URL片段/WebGoat/IDOR/profile/2342444最后那串数字是数据库里的用户主键。在这个场景里它就是“直接对象引用”。如果你是按正常操作点的看到的当然是有权限访问的那个用户。接下来的操作就是用抓包工具或者直接在浏览器地址栏改这个ID把它换成附近的整数比如2342443、2342384、2342389刷新页面看返回内容。我习惯用抓包工具的Repeater功能来枚举比在地址栏一下一下改高效得多。把请求发到Repeater每次只改末尾的ID段发几次之后就能看到另一个用户的信息出现在响应体里。这时两个用户的信息对比一下你会发现哪些字段是这个人独有的题目要求找的“目标用户标志信息”基本就在里面。这一关成功地让你理解服务端只查了WHERE id ?却没加AND owner 当前用户。这里有一个实际操作心得不要一上来就猜一个巨大的随机ID先看看当前ID是几位数然后在它附近前后各枚举几十个。WebGoat的虚拟员工ID往往就在一个很窄的区间内盲目爆破只会让日志刷屏并增加出问题概率。3.3 IDOR删除案例接口直接暴露的越权IDOR这一课的第二个经典子任务是让你以普通用户身份删除其他用户。页面上虽然提供删除功能但正常操作只会删除自己能删的记录这样并不会通关。真正的考点是请求里的ID参数能不能指向别人。在页面抓包会看到一个删除请求指向类似地址DELETE /WebGoat/IDOR/delete?id2342444这里id是你的用户ID。把这个ID改成其他用户的ID再发送如果响应显示删除成功或者返回了对方用户的信息就说明服务端对删除操作也没有做归属校验。这种漏洞在真实系统中非常致命因为删除是破坏性操作一旦接口被越权调用数据恢复都是大问题。操作时有一个细节删除请求可能要求特定的HTTP方法比如必须是DELETE如果你用GET去试有时候会被405拦下来。我的建议是把抓包工具里的请求方法改成跟原请求一致只改参数。如果服务器对方法校验不严那么POST、GET、DELETE都可以试一遍这种尝试本身也是垂直越权关卡里的常见考点。4. 通关实战接口级与业务流越权4.1 Missing Function Level Access Control直接调管理接口Missing Function Level Access Control翻译过来是“缺失功能级访问控制”表现出来的问题更像是一张门禁卡没设置权限谁捡起来都能刷开管理员办公室。这一课配了一个用户管理界面页面上提示你当前是普通用户系统没有给你放管理菜单的入口。普通用户在主界面里确实找不到“用户管理”相关的按钮但管理功能肯定是一个真实存在的接口。用抓包工具观察页面加载时的所有请求或者直接看前端源码里有没有注释掉的链接你会发现一个类似这样的地址GET /WebGoat/access-control/users拿当前普通用户的Cookie直接访问这个URL如果返回的是用户列表JSON那就说明服务端没有校验当前角色任何登录用户都能访问用户管理功能。这一关后面的子任务大同小异要求你以普通用户身份去创建一个新用户、修改用户角色。本质上就是对着这个接口发POST、PUT请求。我用抓包工具构造了一个添加用户的请求POST /WebGoat/access-control/users HTTP/1.1 Host: localhost:8080 Cookie: JSESSIONID当前会话 Content-Type: application/json {username:pwnuser,password:pwn123456,role:admin}发送后如果服务器返回“用户新增成功”或者页面上出现了你创建的用户就代表垂直越权链路已经打通了。这一课给我的启发很大功能在前端被藏起来并不代表后端接口不存在。很多系统只做了菜单权限却没在真正处理业务的Controller上做角色注解导致前端看不到、后端不设防。4.2 Multi-Step Process多步骤流程绕过Multi-Step Process这节课玩的是业务流程上的漏洞。它模拟了一个包含多个步骤的场景选商品、填信息、确认、提交。页面一步步带你走但后端并没有把整个流程的状态锁在服务器上而是隐含地信任前端传过来的步骤编号和汇总字段。实际操作中我先把整个流程完整走一遍同时用抓包工具记录每一步的请求。重点观察两个地方有没有随请求一起提交的累计金额、折扣、数量之类的字段有没有类似step1、step2这样的步骤标识。常见做法是在第一步请求里就把最终步骤该提交的参数一并带上比如直接在第一步提交step4的参数集合看服务器会不会跳过错觉校验直接进入完成状态。更常见的变形是把折扣字段改成负数。靶场里曾经出现过的场景是系统根据商品数量自动计算总价前端把“总价”和“优惠比例”当隐藏参数传给后端。你把优惠比例改成-100总价就变成了负数系统不但不校验还会按负数入账。负“付款”这种反直觉结果恰好暴露了服务端对计算参数的绝对信任。这一关的系统判定往往需要看到最终的“购买成功”页面才算通过所以要仔细看加载了哪个成功回调。我踩过的坑是改完参数后只看到了HTTP 200就以为OK但页面没有真正跳转通关标记也没亮。处理方法是除了看响应码还要在前端显示层面确认流程已经走完。4.3 垂直越权与水平越权扩展练习模块后半段的垂直越权和水平越权课程其实是把前面IDOR、Missing Function Level的知识合并成更接近实战的场景。垂直越权关卡里系统给了你一个低权限账号又暗示存在一个只有管理员能做的操作。找接口的过程和4.1差不多但多了一道限制即使你找到了管理员接口直接发送请求可能被拦。这时候就要做HTTP层面的绕过尝试。我当时的顺序是先用原请求原样发送看服务器返回什么如果返回403 Forbidden就把请求方法从GET换成POST、从POST换成PUT、甚至试试HEAD如果还不行就检查是不是存在Origin、Referer这类来源校验把请求里的这些头删除再放行。WebGoat这类靶场里经常藏着某个方法在鉴权逻辑中漏掉的情况多试几种组合通关条件很快会出现。水平越权关卡则更像前面IDOR的加强版。登录用户A后用抓包工具找到查看个人信息的请求请求参数里必然有一个用户标识字段。把它改成用户B的标识如果响应里带出了B的数据就说明水平校验缺失。要注意的是这类关卡经常要求你在同一个角色层级内操作如果改错成管理员ID可能因权限过高反而被限本质上还是先确认一下目标ID属于哪个用户组。在这里我形成了一个习惯凡是遇到越权关卡先画一条线——当前用户、目标用户、接口URL、参数位置。把四个要素列出来再开始改包思路会清晰很多。5. 实战问题排查与避坑指南5.1 通关状态不刷新/不判定的排查通关最令人崩溃的情况是操作明明生效了页面却显示未完成。我遇到的第一个原因是登录身份不对。WebGoat每个课程都有独立完成状态不假但很多题目是在“特定用户”的前提下设计的。你用注册的新用户完成了操作系统却期望你是内置角色自然不给你通关。第二个原因是缓存。浏览器对某些请求做了本地缓存你改包发送了新的请求但页面展示的仍是旧的响应。解决办法是打开开发者工具的“Disable cache”选项并且每次操作后硬刷新页面。第三个原因是步骤遗漏。有些课程有好几个子页面通关条件是在最后一个子页面出现的。你只完成了前半部分右侧菜单的勾自然不会亮。我的建议是每做完一步就刷新一下左侧课程列表看勾选状态有没有变化及时定位还没完成的子步骤。5.2 抓包过程最常见的三类问题第一类是代理端口和靶场端口冲突导致页面打不开。解决方案很简单让靶场端口和代理端口保持不同浏览器代理设置里确认无误即可。第二类是只抓到页面加载请求没抓到具体的操作请求。很多新手开了拦截却发现点击按钮后什么都没发生。这通常是因为浏览器对按钮的POST请求走了异步JavaScript需要确认抓包工具里没有过滤掉某些域名或文件类型。我一般把过滤器清空先抓全量请求再逐步缩小范围。第三类是修改请求后服务器返回异常比如500、参数解析失败。这种情况大概率是改了字段但没改对应的Content-Type或者JSON格式少了个引号。发送前先检查请求体语法尤其注意双引号和花括号的闭合。5.3 版本差异与信息收集方法WebGoat 2023与旧版相比课程名称和请求路径会有细微差别。比如旧版把某些课放在“Access Control”里新版可能直接叫“Broken Access Control”菜单有些旧版关卡里的参数叫userId新版变成了id。如果照着网上的老文章操作发现请求路径404了不要慌通常是路径结构变了。我的信息收集方法是登录进靶场后先打开浏览器开发者工具的Network面板把课程页面的所有请求都扫一遍。很多隐藏接口在页面初始化时会自动请求一次即使前端不显示网络面板里也会暴露路径。这个技巧能解决80%“找不到接口”的问题。另外右键查看页面源代码搜索hidden、access-control、admin这些关键词也经常能翻出线索。把这些线索汇总起来比端着老教程盲改要好很多。6. 从通关到落地的安全修复思路6.1 服务端授权是唯一信任边界通关越多越能体会一个结论所有涉及权限判断的逻辑都必须写在后端。前端那些根据角色隐藏菜单、置灰按钮的方案只有体验价值没有安全价值。开发接口时每一个敏感操作前都应有一个“我是谁”的身份识别和角色判定步骤。我自己看代码时有个习惯从路由层往Controller层走一遍找到每个操作入口确认有没有加统一的鉴权拦截。如果某个接口只靠前端URL隐藏来保护那这个漏洞在这套靶场里一定走不过两关。在真实项目里这几乎等于给攻击者送分。6.2 对象级权限校验模板IDOR类问题的最佳解法是对象级权限校验。核心原则是查询数据时在SQL或查询逻辑里带上当前用户的归属条件。举个例子如果有一个接口根据文件ID返回文件内容正常逻辑应该是“先找到文件再判断文件owner是否等于Session里的userId”。很多开发者喜欢先查文件再判断结果在查询阶段就泄露了文件内容。正确顺序是先确定当前用户允许访问哪些文件再执行查询。代码上可以抽象成一个方法专门做“资源归属校验”所有涉及业务对象ID的接口统一调用能省掉一大半越权风险。对于垂直越权则要在服务端给接口和角色做矩阵映射明确哪些角色能访问哪些方法和路径。Web框架里的拦截器、过滤器、注解都可以实现关键是覆盖全别只给管理页面加了限制而忘了背后的接口。6.3 后续进阶方向这套靶场通关只是起点后面可以做三件事巩固第一拿一个模拟项目X做一次权限遍历测试把所有带用户ID、订单号、文件ID的接口列出来逐个尝试越权。第二结合代码审计工具查一下项目里有没有未统一鉴权的接口这个在真实工作中很重要。第三把眼光从Web接口扩展到文件下载、对象存储这些场景IDOR不止存在于数据库主键还常见于文件名、路径、云存储对象键。我还建议把通关过程中修改过的请求保存成一份清单包括原始请求、修改后的请求、响应结果。日后复盘时这份清单比通关截图有价值得多。它记录的是你从“看到参数”到“想到越权”的完整链路而这种链路思维才是这套靶场真正想训练的东西。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。