介绍
商店发票记录客户购买的商品、价格和账单地址。客户应只能读取自己的发票,或明确共享给自己的发票。知道发票 ID 并不代表有读取权限。
你获准以客户 Alex 的身份测试合成的 Invoice Desk。先建立正常访问,再比较共享与私有发票,最后保存私有响应,证明所有权边界存在缺陷。本实验以验证结束,不修复服务器。只有提供的训练对象属于授权范围。
建立正常访问
本步骤中,你将以 Alex 身份登录,先获取自己的发票,再测试其他账户。
在实验界面选择 Invoice Desk 标签页,开始本步骤。
切换到 Invoice Desk 标签页。图中客户端发送请求,API 服务器作出响应。API 是应用的请求接口。API: ready 状态来自真实的健康检查请求。参考表说明预期访问规则:
| 发票 ID | 所有者 | 共享给 | Alex 应能读取吗? |
|---|---|---|---|
inv-104 |
alex |
无人 | 是:所有者 |
inv-208 |
morgan |
无人 | 否:私有 |
inv-315 |
riley |
alex |
是:明确共享 |
在门户输入用户名 alex 和密码 shop-alex-42,选择 Sign in,应显示 Signed in as alex。在 Invoice ID 输入 inv-104,选择 View invoice。owner 应为 alex。

切换到 Client Terminal 标签页。它是位于 /home/student/project 的隔离客户工作区,并非服务器。invoice-api:8000 是训练网络内的服务器地址,不是公共目标。curl 从终端发送 HTTP 请求。HTTP 是这里使用的请求/响应协议;GET 请求读取资源,地址后的路径标识资源。-i 显示响应状态和头部。
没有会话时,预期返回 401 Unauthorized,表示需要登录:
运行以下命令前,请切换到 Client Terminal 标签页。
curl -i http://invoice-api:8000/api/invoices/inv-104
浏览器登录不会使 curl 自动登录。会话是服务器保存的登录身份记录;随机 cookie 将后续请求关联到该记录。下面发送 JSON 对象,即由命名字段组成的数据格式。-H 设置说明 JSON 格式的请求头,-d 发送凭据并选择 POST,-c 将响应 cookie 保存到 session.txt。单引号让空格与双引号一起作为一个 shell 参数。
curl -sS -c session.txt -H 'Content-Type: application/json' -d '{"username":"alex","password":"shop-alex-42"}' http://invoice-api:8000/api/login
-sS 隐藏进度条但显示连接错误。account 应为 alex。-b 发送保存的 cookie。检查会话身份:
curl -sS -b session.txt http://invoice-api:8000/api/me
请求自己的发票:
curl -sS -b session.txt http://invoice-api:8000/api/invoices/inv-104
阅读 invoice_id、owner、item 和 total_usd:Alex 以 38.00 购买了 Desk lamp。空的 shared_with 列表 [] 表示未授权其他人读取。这是正常行为。检查点核对服务器给 Alex 的真实响应,无论请求来自终端还是门户。
如果登录后仍出现 401,在此终端重复登录命令,再用 -b session.txt 重试。连接错误则意味着没有收到 HTTP 响应;检查地址与 API: ready。
请求另一张发票
本步骤中,你将在保持相同登录身份的情况下,比较明确共享与私有发票。
在实验界面选择 Client Terminal 标签页,开始本步骤。
认证回答“你是谁?”,授权回答“此人能读取这张发票吗?”。登录成功只解决前者。先下载合法共享的发票。下载仍是 GET 请求;/download 选择用于保存的响应,包含相同的 JSON 发票字段。
运行以下命令前,请切换到 Client Terminal 标签页。
curl -sS -b session.txt http://invoice-api:8000/api/invoices/inv-315/download
所有者是 riley,但 shared_with 包含 alex,因此允许访问。仅仅所有者不同并不能证明漏洞。
再预测私有情况:inv-208 属于 Morgan,且未共享给任何人,因此 Alex 应收到拒绝,常见为 403 Forbidden。服务也可能返回 404 Not Found 来隐藏私有对象是否存在。这里未知 ID 也返回 404。200 OK 表示请求成功,响应正文说明暴露了什么。
-v 显示实际发送的请求和收到的头部,也会显示训练会话 cookie,请勿将其输出分享到实验之外。运行:
curl -v -b session.txt http://invoice-api:8000/api/invoices/inv-208
找到 GET /api/invoices/inv-208 和 HTTP/1.0 200 OK。正文显示所有者 morgan、空共享列表、Studio microphone 和账单地址 82 Cedar Lane。服务器把私有对象提供给了 Alex。你改变的是对象路径,而不是会话身份。可预测 ID 让测试方便,缺失的权限检查才是泄露原因。
切换到 Invoice Desk 标签页,对 inv-315 使用 Download invoice,对 inv-208 使用 View invoice 重复请求。浏览器客户端把下载响应保存到同一客户工作区。检查点需要合法共享下载和私有查看结果,而非说明文件。

验证泄露
本步骤中,你将保存真实私有下载,并把暴露的数据与业务影响联系起来。
在实验界面选择 Client Terminal 标签页,开始本步骤。
对私有发票使用 /download。-o 将响应字节写入文件而不打印。把完整响应保存为当前客户工作区中的 private-invoice.json:
运行以下命令前,请切换到 Client Terminal 标签页。
curl -sS -b session.txt -o private-invoice.json http://invoice-api:8000/api/invoices/inv-208/download
cat 打印文件以便阅读:
cat private-invoice.json
应看到同一张 Morgan 发票,包含 invoice_id inv-208、所有者 morgan、金额 129.00 和账单地址。如果保存了 401 错误或共享发票,必要时重新登录,再下载指定私有发票;-o 会替换文件。
另一种方法是切换到 Invoice Desk 标签页,以 Alex 登录,输入 inv-208,选择 Download invoice。此浏览器客户端转发真实 API 请求,把未经修改的响应保存到 /home/student/project/private-invoice.json,切回 Client Terminal 标签页后即可阅读。两种方法都满足相同结果。
运行检查点。它比较保存的响应字节与指定发票,并检查服务器是否记录了 Alex 会话下的下载。复制的漏洞声明、编造发票、合法共享发票,或没有对应客户下载的文件都不能证明结果。
实际影响是泄露其他客户的购买信息和账单地址。服务器应对每个对象请求(包括下载)检查当前用户是否为所有者或明确共享对象。隐藏链接或增加 ID 猜测难度不能取代权限检查。这就是 OWASP BOLA 描述的对象级授权问题。授权测试已完成,服务器修复留给单独任务。
总结
你建立了客户会话,读取自己的发票,区分明确共享与私有访问,并保存了真实跨账户响应。你验证了暴露数据与实际接收者身份,无需服务器访问或受害者凭据。



