授权 Web API 渗透测试教程:从攻击面梳理到越权验证与整改复测

枫少@KillBoy
枫少@KillBoy
枫少@KillBoy
管理员
287
文章
0
粉丝
渗透测试321,295字数 4067阅读13分33秒阅读模式
AI智能摘要
AI 生成的文章内容摘要

Web API 渗透测试的价值,不在于证明“某个请求能够返回数据”,而在于证明该请求违反了明确的身份、对象或功能权限规则,并且结果能够由开发、运维和复测人员独立复核。本文仅适用于获得书面授权的测试环境,使用占位域名、测试账号和脱敏数据,重点介绍如何以最小化请求验证对象级授权、功能级授权、认证状态和敏感数据暴露问题。

授权 Web API 安全评估流程示意图

一、先确认授权边界和停止条件

测试开始前,应将授权内容整理成可执行的测试规则,而不是只保留一封笼统的“允许测试”邮件。至少确认以下事项:

  • 目标范围:域名、IP、API 网关、环境名称、版本或租户范围。
  • 测试时间窗:开始和结束时间,是否避开批处理、发布、结算等高风险时段。
  • 允许的方法:是否允许身份与权限测试、错误配置检查、限速观察,以及是否禁止上传、删除、支付和管理操作。
  • 测试账号:普通用户、受限用户、管理员或租户管理员等角色,账号应为专门创建的测试账号。
  • 数据限制:只能访问授权测试数据;发现真实个人信息、令牌、密钥或生产数据时应立即停止扩大验证。
  • 影响阈值:请求速率、并发数、单次返回量、失败次数和资源消耗上限。
  • 停止条件:出现服务异常、数据写入、跨租户数据、敏感凭据、告警升级或无法判断影响时,暂停请求并联系授权方。
  • 清理方式:测试产生的数据、会话、临时对象和配置变更由谁清理,如何确认清理完成。

OWASP Web Security Testing Guide 将 API 侦察视为独立测试环节,强调先了解目标和 API 结构,再开展后续验证。可以将 OWASP WSTG 的 API 侦察章节 作为方法参考,但具体测试仍应服从项目授权范围。

二、建立资产和接口清单

API 测试的第一个实际产物应是接口清单,而不是扫描器报告。清单用于回答“测试了什么”和“还有什么没有测试”。

可以从以下资料来源建立清单:

  1. OpenAPI、Swagger、GraphQL Schema 或内部接口文档;
  2. 前端 JavaScript、移动端测试包和业务流程中的请求记录;
  3. API 网关路由、反向代理配置和服务注册信息;
  4. 测试环境访问日志、调用方清单和版本发布记录;
  5. 授权范围内的被动流量观察结果。

建议为每个接口记录:

字段示例
接口标识GET /api/v1/orders/{order_id}
环境staging-api.example.test
认证方式Bearer 测试令牌
预期角色普通用户
对象范围当前用户所属租户
操作类型读取
数据敏感度订单基础信息
是否产生副作用否
测试状态未开始、通过、异常、需复核
证据位置请求编号、响应摘要、日志编号

清单中的目标应使用占位域名,例如 https://api.example.test,不要在报告或示例中泄露真实生产域名、内部主机名和令牌。对于文档中存在但实际不可用的接口,应记录“未验证”及原因,不能直接标记为安全。

三、先写出身份与权限假设

越权验证的核心不是随意替换参数,而是先定义服务端应该执行的授权规则。没有预期规则,就无法判断响应差异究竟是漏洞、业务设计还是测试误判。

1. 对象级授权假设

对象级授权关注“当前身份能否访问这个具体对象”。例如:

  • 用户甲只能读取自己创建的订单;
  • 租户甲的成员不能读取租户乙的项目;
  • 普通用户只能修改自己名下的地址;
  • 归档对象只能由具备特定职责的角色查看。

测试前准备两个同权限、不同对象范围的账号,例如 user_a 和 user_b,并在测试环境中准备各自独立的对象:

  • order_a 属于 user_a;
  • order_b 属于 user_b;
  • 两个对象状态和字段结构尽量相似。

验证目标不是“把 ID 改大或改小”,而是确认服务端是否根据当前会话重新判断对象归属。对象标识可以是数字、UUID、路径片段、查询参数或请求体字段,均不应被客户端输入自动视为授权依据。

2. 功能级授权假设

功能级授权关注“当前角色能否执行这个动作”。例如:

  • 普通用户可以查看自己的订单,但不能导出全租户订单;
  • 项目成员可以读取项目,但不能修改成员权限;
  • 运维角色可以查看运行状态,但不能变更业务数据;
  • 管理功能不能仅凭隐藏按钮或前端路由限制。

功能级测试应覆盖同一接口在不同角色下的行为,并区分:

  • 未登录;
  • 已登录的普通用户;
  • 已登录的受限角色;
  • 具备管理权限的测试账号。

不要仅以 HTTP 状态码判断结果。200、201、204、403、404 和 401 都需要结合响应体、业务状态、审计日志和服务端实际变化解释。

四、采用最小化请求进行验证

低影响验证的原则是:一次只验证一个假设,优先使用只读接口,控制请求频率,不主动扩大数据量。

1. 建立基准请求

先使用账号 A 对其自身对象发起正常请求,保存以下信息:

  • 请求方法和路径;
  • 脱敏后的请求头;
  • 必要的查询参数或请求体;
  • 状态码、响应长度和关键字段;
  • 请求时间、响应时间和追踪 ID。

示例使用占位目标和环境变量,不包含真实令牌:

export API_BASE="https://api.example.test"
export TOKEN_A="REDACTED_TEST_TOKEN_A"

curl --silent --show-error 
  --request GET "$API_BASE/api/v1/orders/order_a" 
  --header "Authorization: Bearer $TOKEN_A" 
  --header "Accept: application/json"

该请求的作用是建立“合法基线”,不是扫描接口。若基线请求本身失败,应先确认账号状态、接口版本、测试数据和环境配置,不要直接把失败结果解释为访问控制有效。

2. 进行单变量对照

在保持方法、请求头和其他参数不变的情况下,仅将对象替换为 order_b,并使用账号 B 做同样请求。对照表可以这样记录:

对照项账号 A 访问 order_a账号 A 访问 order_b
预期结果允许拒绝或返回统一不存在
实际状态码200待记录
响应是否含对象字段是待记录
服务端数据是否变化否待记录
是否产生审计日志是待记录

如果账号 A 能读取或修改 order_b,应先确认 order_b 是否确实属于不同用户或租户,是否存在共享、委托、团队协作或客服代办等业务规则。只有在业务规则明确禁止访问时,才能将其作为对象级授权问题提交。

3. 处理响应差异

有价值的证据不只是“返回 200”。应比较:

  • 状态码;
  • 响应正文中的对象标识、用户标识、租户标识;
  • 返回字段数量和敏感字段;
  • 分页总数、错误码和错误信息;
  • 响应时间是否出现异常差异;
  • 服务端审计日志中的主体、对象和决策结果。

对于未授权对象,服务端可能返回 403,也可能为避免对象枚举而返回统一的 404。这两种设计都可能合理,关键是未授权请求不能泄露对象内容,也不能产生未授权的状态变化。

五、重点检查认证状态和敏感数据暴露

认证状态

至少验证以下状态:

  1. 完全不带认证头;
  2. 使用格式错误或过期的测试令牌;
  3. 使用账号 A 的令牌访问账号 B 的对象;
  4. 令牌被撤销或退出登录后再次访问;
  5. 不同 API 版本或网关路径是否使用一致的认证策略。

应检查认证是否仅由前端控制、是否存在某个版本路径遗漏认证、是否将用户标识从请求参数直接作为可信身份。测试中不要尝试猜测真实令牌,也不要收集非测试用户的会话信息。

敏感数据暴露

即使对象级授权正确,也可能存在对象属性级问题。检查响应是否返回业务不需要的字段,例如:

  • 密码哈希、访问令牌、刷新令牌;
  • 内部服务地址、调试堆栈和数据库标识;
  • 身份证件、支付信息或完整联系方式;
  • 未脱敏的日志、密钥或第三方凭据;
  • 不同角色不应看到的管理字段。

验证时只需确认字段是否出现、是否可由低权限账号获取,不应下载大量记录或进一步使用暴露的凭据。发现真实敏感数据后,应停止扩大读取范围,保留最小必要证据,并按约定通知授权方。

不同权限账号进行 API 对象级授权对照验证

六、控制请求影响和测试节奏

API 测试不应把并发压测、批量枚举和破坏性操作混入普通权限验证。建议采取以下控制:

  • 优先使用 GET、HEAD 或明确无副作用的接口;
  • 每次只发送一个或少量对照请求,并设置合理间隔;
  • 不使用大范围 ID 枚举来证明问题;
  • 不测试删除、支付、发邮件、改密和批量导出等动作,除非授权明确允许;
  • 需要验证写操作时,使用专门测试对象,并提前确认回滚方法;
  • 遇到速率限制、错误率升高、队列堆积或响应时间明显上升时立即暂停;
  • 记录测试工具的并发、超时、重试和代理配置,避免工具默认行为扩大影响。

如果需要确认写操作是否受权限控制,应优先在隔离环境中使用无业务价值的测试对象,并将请求体中的内容限制为无害标记。例如,先验证服务端是否返回拒绝,再由授权方通过日志或数据库审计确认没有发生变更。

七、形成可复核的漏洞证据

一条合格的发现应让不了解现场的开发人员能够复现和判断。报告至少包含以下字段:

  • 标题:例如“普通用户可读取其他租户订单对象”;
  • 资产与接口:环境、方法、路径和版本;
  • 前置条件:测试账号角色、对象归属和必要配置;
  • 预期授权规则:当前身份本应能做什么;
  • 复现步骤:控制在最少请求数,使用脱敏参数;
  • 实际结果:状态码、关键响应字段和是否产生状态变化;
  • 对照结果:合法账号、拒绝场景或修复前后的差异;
  • 影响范围:可能暴露的数据类型、受影响角色和租户边界;
  • 证据:请求编号、响应摘要、网关日志或审计日志编号;
  • 风险判断:机密性、完整性、可用性和业务影响;
  • 修复建议:服务端授权位置、字段控制和测试要求;
  • 清理结果:创建对象、会话、配置和临时数据是否已清除。

请求示例应脱敏:

GET /api/v1/orders/order_b HTTP/1.1
Host: api.example.test
Authorization: Bearer <TOKEN_A_REDACTED>
Accept: application/json
X-Test-Case: BOLA-001

响应可以只保留用于证明结论的字段:

{
  "status": "success",
  "order_id": "order_b",
  "tenant_id": "tenant_b",
  "customer_name": "<REDACTED>"
}

不要在报告中保留完整令牌、Cookie、个人信息、支付数据或可直接使用的密钥。截图也应进行遮罩,并说明截图时间、账号角色和环境。

八、风险判断不能只看状态码

越权问题的严重程度取决于对象和动作,而不是单一的 200 或 403。可以从以下维度判断:

  • 是否跨用户、跨团队或跨租户;
  • 读取的是普通业务信息还是身份、财务、凭据等敏感数据;
  • 仅能读取,还是能够新增、修改、删除或授权;
  • 是否需要已认证账号,还是完全未认证即可访问;
  • 是否存在稳定、可重复的权限绕过;
  • 是否可能影响大量对象,但不应通过批量请求进行实际验证;
  • 是否已有审计日志和告警,能否追溯异常访问。

风险描述应区分“已证明的影响”和“合理推断的影响”。例如,单个测试对象被读取可以证明对象级授权失效;但不能据此断言整个数据库已被读取,除非有授权范围内的独立证据。

九、修复建议应落到服务端控制点

常见修复方向包括:

  1. 在服务端根据认证主体重新加载对象,并执行租户、用户和角色授权检查;
  2. 将授权逻辑放在业务服务或统一策略层,而不是只依赖前端隐藏按钮;
  3. 对读取、创建、更新、删除和导出分别定义权限;
  4. 使用字段白名单和角色化响应模型,避免直接序列化内部对象;
  5. 对管理接口、调试接口和旧版本 API 采用一致的认证与授权策略;
  6. 对失败访问记录主体、对象、动作、来源和结果,同时避免日志泄露令牌;
  7. 对高敏感操作增加重新认证、审批或二次确认;
  8. 根据业务需要设置分页上限、速率限制和资源消耗控制。

随机化对象标识只能降低枚举便利性,不能替代服务端授权。隐藏路径、修改前端路由或依赖网关规则,也不能替代每个业务接口自身的权限判断。

十、整改复测要证明“问题已关闭”

复测应复用原始测试条件,并保留修复前后的对照:

  1. 使用原账号 A 访问原对象 order_b;
  2. 确认服务端拒绝访问或返回统一的无对象结果;
  3. 使用合法账号访问自身对象,确认正常业务没有被误伤;
  4. 检查读取、更新、删除、导出等相关动作是否同时修复;
  5. 检查不同 API 版本、网关路径和缓存层是否仍有差异;
  6. 检查响应中是否仍暴露不必要字段;
  7. 通过审计日志确认拒绝决策和主体信息正确;
  8. 清除复测产生的测试对象、令牌和临时配置。

复测结论可分为:

  • 已修复:越权请求被拒绝,合法请求正常,日志和字段控制符合预期;
  • 部分修复:某个方法或版本已修复,但仍有相关入口可访问;
  • 未修复:原始条件下仍可重复;
  • 无法验证:环境、账号、数据或日志条件不足,应明确列出缺失项。

最终,Web API 渗透测试应形成一条完整证据链:授权范围定义了可以测试什么,接口清单说明测试覆盖了什么,权限假设说明为什么该访问应被允许或拒绝,对照请求证明实际差异,日志和响应确认影响,整改复测则证明修复没有只停留在前端或单一路径。以这条证据链为主线,越权验证才会真实、可复核,也更值得开发和运维团队投入修复资源。

 
枫少@KillBoy
评论  32  访客  31  作者  1
    • 回家的路灯
      回家的路灯 1

      先把授权边界写清楚,确实省很多麻烦

      • 嚣张的猫
        嚣张的猫 1

        越权测试最怕把业务规则和漏洞混为一谈

        • 小狐火
          小狐火 1

          只读接口优先,这个测试节奏比较稳妥

          • 月光喵咪
            月光喵咪 0

            复测时能复用原始条件就更有说服力

            • 杨门女将
              杨门女将 0

              想问下多租户场景通常怎么准备测试数据

              • 琴瑟在御
                琴瑟在御 1

                状态码相同也不能说明权限判断真的一致

                  • 坚定磐石
                    坚定磐石 1

                    @ 琴瑟在御 对,响应体、审计日志和实际变化都得一起看。

                  • 蓝莓酱
                    蓝莓酱 1

                    对象权限过了,字段白名单也不能省

                      • 星尘飘散
                        星尘飘散 1

                        @ 蓝莓酱 没错,能访问对象不等于能看全字段,敏感字段还得靠服务端白名单单独卡住。

                      • Eagle翔
                        Eagle翔 1

                        测试前先写清停止条件,真出异常时能少走很多弯路

                        • 囚牛鸣涧
                          囚牛鸣涧 1

                          脱敏证据这点很关键,报告不能留下新风险

                          • 吴倩
                            吴倩 1

                            复测时别忘了把旧版本接口也过一遍

                              • 枫少@KillBoy
                                枫少@KillBoy

                                @ 吴倩 这个提醒很关键,旧版本接口也要纳入清单,确认是否仍可访问以及权限控制是否一致。

                              • 嚣张獠牙
                                嚣张獠牙 1

                                前端隐藏按钮确实不能代替服务端鉴权

                                  • 夫诸角
                                    夫诸角 2

                                    @ 嚣张獠牙 尤其是管理接口,前端限制撤掉后就不能算控制了。

                                  • 四面楚歌
                                    四面楚歌 1

                                    接口清单比单纯丢一份扫描报告实用

                                      • KomorebiShade
                                        KomorebiShade 0

                                        @ 四面楚歌 接口清单还能标出未验证项,后续复测不容易漏。

                                      • 草莓小浣熊
                                        草莓小浣熊 0

                                        写操作测试还是得提前确认回滚方案

                                        • 考拉梦
                                          考拉梦 1

                                          元宝,别被状态码带偏了,日志和实际数据变化才是硬证据

                                            • yuanbao
                                              yuanbao 6

                                              @ 考拉梦 对,状态码只是表象,得结合日志和实际数据变化一起看,不然容易误判。

                                            • 坚韧的竹子
                                              坚韧的竹子 1

                                              撤销令牌后的访问状态也值得单独留证。

                                              • ChillChimera
                                                ChillChimera 0

                                                跨版本接口保持一致,常常比想象中难。

                                                • 四维空间裁缝
                                                  四维空间裁缝 1

                                                  字段级权限很容易被对象级权限遮住。

                                                  • 国粹传承
                                                    国粹传承 2

                                                    多租户数据最好让对象归属足够清晰。

                                                    • 嚣张的咸鱼
                                                      嚣张的咸鱼 1

                                                      基线请求失败时,确实不能急着下结论。

                                                      • 土载物
                                                        土载物 1

                                                        统一返回不存在有助于减少对象枚举。

                                                        • 花艺设计师
                                                          花艺设计师 0

                                                          审计日志能不能看懂,也是证据链的一环。

                                                          • 嚣张如我
                                                            嚣张如我 1

                                                            风险判断还是要区分已验证和推测影响。

                                                            • 快乐小分队
                                                              快乐小分队 0

                                                              测试数据清理完成后最好再核对一次。

                                                              • 坚韧小骆驼
                                                                坚韧小骆驼 1

                                                                无害标记适合用来验证写操作权限。

                                                                • 远途独行
                                                                  远途独行 1

                                                                  前端藏得再深,服务端也得重新验权限

                                                                  • 土陶
                                                                    土陶 2

                                                                    响应字段白名单比直接返回对象稳妥。

                                                                  匿名

                                                                  发表评论

                                                                  匿名网友

                                                                  拖动滑块以完成验证