安全问题 | 安全弱点 | 影响 | 如何预防 |
---|---|---|---|
对象级别授权漏洞(BOLA) | 访问控制机制失效 | 数据泄露、账户接管 | 实施适当的授权机制,使用随机值作为 ID |
认证漏洞 | 认证机制脆弱 | 账户控制权丧失 | 使用标准库,实施多因素认证和反暴力破解机制 |
对象属性级别授权漏洞 | 敏感属性暴露 | 数据泄露、权限提升 | 仅暴露必要的属性,避免批量赋值 |
不受限制的资源消耗 | 资源限制不当 | 拒绝服务、成本增加 | 限制请求频率和资源使用,配置消费限额 |
函数级别授权漏洞(BFLA) | 功能授权检查缺失 | 未授权访问管理功能 | 默认拒绝访问,明确授权特定角色 |
不受限制地接触敏感的业务流程 | 业务流程过度访问 | 业务损害 | 确定敏感流程,实施访问限制 |
服务端请求伪造(SSRF) | 未验证 URI | 内部服务暴露 | 使用白名单,禁用重定向,过滤输入 |
安全配置错误 | 配置不当 | 系统泄露或失守 | 加固 API 堆栈,审查配置,使用加密通信 |
库存管理不当 | 存在旧版本 API | 数据泄露、服务控制 | 清单管理,文档记录,风险评估 |
不安全的API使用 | 第三方 API 交互不安全 | 敏感信息泄露 | 验证第三方 API 安全性,使用安全的通信渠道 |
威胁媒介/攻击媒介 | 安全弱点 | 影响 |
---|---|---|
API特定:易受攻击,利用难度低 | 普遍存在:检测难度低 | 中等技术问腿:特定于业务 |
攻击者可以通过篡改请求中发送的ID,来利用缺乏适当访问控制的 API 端点。对象 ID 可以是顺序整数、UUID 或通用字符串。无论数据类型如何,它们都很容易在请求目标(路径或查询字符串参数)、请求头甚至请求 Payload 中识别出来。 | 这个问题在基于 API 的应用程序中极为常见,因为服务器组件通常不会完全跟踪客户端的状态,而是更多地依赖客户端发送的对象 ID 等参数来决定访问哪些对象。服务器的响应通常足以了解请求是否成功。 | 未经授权访问其他用户的对象可能导致数据泄露给未经授权的第三方、数据丢失或数据被篡改。在某些情况下,未经授权访问对象还可能导致整个账户被接管。 |
对象级别的授权是一种访问控制机制,通常在代码级别实现,验证用户只能访问他们应该有权访问的对象。
每个接收对象 ID 并对该对象执行任何操作的 API 端点都应实施对象级授权检查。这些检查应验证登录用户是否有权限对所请求的对象执行所请求的操作。
这一机制的失效通常会导致未经授权的信息泄露、修改或销毁所有数据
将当前会话的用户 ID(例如从 JWT 令牌中提取)与易受攻击的 ID 参数进行比较并不足以解决对象级授权(BOLA)失效问题。这种方法只能解决一小部分情况。
在 BOLA 的情况下,用户按照业务设计来说是有权限访问某个易受攻击的 API 端点/功能的,但安全问题出现在他们能够通过改变 ID 来访问到他们不应该能访问的特定数据对象。
如果攻击者成功访问了他们本不应有权访问的 API 端点/功能,这属于功能级别授权漏洞(BFLA),而不是 BOLA。
场景一
一个为在线商店提供平台的电子商务网站提供了带有收入图表的列表页面,用于显示其托管的商店。通过检查浏览器请求,攻击者可以识别出用作这些图表数据源的 API 端点及其 schema: /shops/{shopName}/revenue_data.json
。使用另一个 API 端点,攻击者可以获取所有托管商店名称的列表。通过编写一个简单的脚本来操作列表中的名称,替换 URL 中的 {shopName}
,攻击者可以访问数千家电子商务商店的销售数据。
场景二
一家汽车制造商通过移动 API 启用了车辆的远程控制,以便与驾驶员的手机进行通信。该 API 允许驾驶员远程启动和停止发动机,以及锁定和解锁车门。作为此流程的一部分,用户将车辆识别号(VIN)发送到 API。由于 API 未能验证 VIN 是否代表属于登录用户的车辆,因此会导致 BOLA 漏洞。攻击者可以访问不属于他的车辆。
场景三
在线文档存储服务允许用户查看、编辑、存储和删除他们的文档。当用户文档被删除时,会向 API 发送一个带有文档 ID 的 GraphQL 请求。由于没有进行任何进一步的权限检查就删除了给定 ID 的文档,因此用户可能能够删除另一个用户的文档。
POST /graphql
{
"operationName":"deleteReports",
"variables":{
"reportKeys":["<DOCUMENT_ID>"]
},
"query":"mutation deleteReports($siteId: ID!, $reportKeys: [String]!) {
{
deleteReports(reportKeys: $reportKeys)
}
}"
}