相关阅读
视频讲解
本期视频我们将讲解Owasp API Top 10中排名第一的BOLA漏洞,也称为失效的对象级授权(Broken Object Level Authorization),其实它与Owasp Top 10中的IDOR(不安全的直接对象引用)在概念上是类似的,之前的视频中我们有分享过。除此之外,我们会重点区分身份验证(Authentication)与授权(Authorization)二者的区别,最后通过CrAPI靶场为大家演示该漏洞是如何挖掘的。
图文讲解
以下内容来自《深入探讨最关键的API漏洞–BOLA(失效的对象级授权)》
简介
在这篇文章中,我将详细介绍失效的对象级授权(BOLA)–根据OWASP API安全项目,这是目前最常见和最严重的API漏洞。
不安全的直接对象引用(IDOR)和BOLA是同一回事。作为项目的一部分,名称从IDOR改为BOLA。
我们每周都会听到一些大公司因为BOLA而被攻破。
最近几个众所周知的例子包括。Uber、Verizon、Facebook、T-Mobile,等等,不胜枚举。
几乎每家公司都有容易受到BOLA攻击的API,目前还没有 “现成的 “解决方案来保护你。
在创建OWASP 10大API的过程中,项目共同负责人Erez Yalon和我正在从不同的来源收集关于API安全的信息,我们发现没有一个资源可以提供关于BOLA的全面信息。这篇文章应该可以填补这一空白。
请记住,你不需要阅读整篇文章来了解BOLA。
本文包含不同的部分,将引导你阅读。
- 对于管理人员–高水平的解释
- 对于工程师–技术解释
- 对于建设者–软件开发人员如何修复BOLA
- 对于破坏者–笔试人员如何利用BOLA
- 为好奇的工程师提供的问答–深入探讨
针对管理人员–如何理解BOLA
与其他漏洞不同,BOLA不是很直观,有些人很难理解它。我找到了一个很好的比喻来向非技术性的观众解释BOLA。欢迎在你的下一个鸡尾酒会上使用这个。
想象一下,你在星期六晚上去旧金山的一家俱乐部。雾气袭来,天气相当寒冷,所以你带了一件温暖的外套。一旦你进了门,你就想甩掉你的夹克,这样它就不会妨碍你交际和享受这个夜晚,所以你就去检查外套。
在大衣检查处,你遇到了詹姆斯,他接过你的外套,递给你一张票,上面有一个数字–26号。然后,詹姆斯拿着你的外套,把它和所有其他俱乐部客人的外套一起挂在衣架上。你走进俱乐部,喝了几杯酒,跳了一晚上的舞。
大约一个小时后,喝了几杯酒,你意识到这不是你的场景,你厌倦了在嘈杂的音乐声中大喊大叫,试图开始交谈。无聊和有点狡猾,你决定用一支笔把你的外套检查票上的号码从26号改成28号。这看起来还算合格。
回到大衣检查处,你把改好的票递给詹姆斯,他目不斜视,伸手到衣架上拿28号外套。你很幸运,28号夹克不是你那件廉价的旧夹克,而是一件高级的香奈儿夹克,而且正好是你的尺寸。
你刚才所做的基本上相当于BOLA的漏洞。
大衣检查室是脆弱的API端点。
詹姆斯是脆弱的代码,他没有实现授权检查。
外套是暴露的对象。
现在你知道了这个技巧,你就可以用1-100的所有数字打印假票,然后偷走每个人的外套。邪恶,对吗?
在最近的Uber漏洞中,阿南德-普拉卡什(Anand Prakash)在Uber的API中发现了一个 “詹姆斯”–一个不执行授权检查的脆弱端点。该端点没有处理验衣单,而是接收用户ID。阿南德((Anand Prakash))要求这个端点提供不属于他的用户信息,而这正是该API所做的。利用这个漏洞,攻击者有可能写一个脚本来列举Uber上所有用户的ID,并获得他们的数据。
今天我们怎样才能减轻BOLA的影响?
有几种方法可以保护你的API并消除这些类型的漏洞。
- 检测 – 脆弱的API端点可以通过代码审查或渗透测试来检测。
- 解决方案规划–对API有深入了解的开发者可以为有漏洞的端点定义具体的授权策略。
- 修复–修复通常只是几行代码,熟悉API的开发者应该能够应用这个修复。
针对工程师–对BOLA的深入研究
现代应用中的资源
现代应用程序处理许多类型的资源,每个资源可能有子资源。
让我们来看看一个骑行共享应用的例子:
- 用户→骑手,司机
- 行程
- 收据
- 司机和骑手之间的文本对话 → 信息
- 车辆→汽车、滑板车、自行车
API端点和资源
在现代REST API中,每一种资源都由一个JSON对象表示,每一种资源通常都有一个API端点,以不同的方式公开它。比如说:
旅行的JSON表示:
{"pick_up_location": "Golden Gate Park", "destination": "Dolores Park"}
与 “旅行 “有关的API端点:
- GET /api/trips/{trip_id} – 获取一个特定的行程
- POST /api/trips/{trip_id}/add_tip_to_trip – 将小费添加到旧行程中
- POST /api/trips – 创建一个新的旅行
- DELETE /admin/api/trips/{trip_id} – 管理功能,删除一个行程。
API端点和对象ID
因为一个用户可以拥有同一资源的多个对象(例如行程),一些API端点需要知道用户愿意访问哪个对象(例如特定的行程)。这就是对象ID出现的地方。客户端基本上会发送用户需要访问的对象ID。
例如,如果用户与司机有一次愉快的旅行,他可以在应用程序的 “旅行历史 “视图中选择具体的旅行,并为该旅行添加小费。然后,移动客户端将触发一个API调用
/api/trips/<trip_id>/add_tip
其中包含所选行程的ID
现代应用程序处理许多资源,并暴露出许多端点来访问它们。因此,现代API暴露了许多对象的ID。这些ID是REST标准和现代应用程序的一个组成部分。
挑战
通过ID暴露一个对象可能是一个很好的软件设计实践,但是一旦客户端可以指定ID,就会为一个非常危险的漏洞打开大门–BOLA。
漏洞
在BOLA中,用户通过操纵ID来访问他不应该访问的对象。
比如说:
攻击者嗅探移动应用程序和API之间的流量,并发现以下API调用。
“/api/trips/7891“,它返回所有关于旅行的细节–包括PII,如骑手的名字和地址。
攻击者写了一个脚本来列举所有的ID。该脚本将发送许多API调用,从。
/api/trips/0001
→
/api/trips/9999
而且,令人惊讶的是,攻击者泄露了应用程序中所有用户的所有行程。
针对建设者–如何建立一个好的授权机制
一个解决BOLA问题的好的授权机制,应该包含以下几个部分。
1:授权决策引擎
该机制的核心是一个授权决策引擎。这个引擎应该有多种功能来回答以下问题。
- 用户#717是否有权限查看收据#11111
- 用户#666是否有权限编辑行程#929
- 管理员#222是否有权限删除用户#555
我不想深入了解底层的实现细节,因为:
- 我不是一个伟大的开发者
- 没有一个通用的方法,因为它完全取决于应用程序的逻辑。
让我们来看看下面的例子:
- #11111收据属于#313行程。这次旅行是一次 “拼车”,由3个不同的用户共享,所以收据也是共享的。所有#313行程的共同乘坐者都应该有机会获得该收据。
- #222管理员是北加州的区域管理员,她应该有权限删除这个区域的所有用户。她想删除#555用户,但她不应该这样做,因为#555用户来自纽约市。
决策引擎应该被非常仔细地规划和构建,以回答这些问题
2:使用决策引擎
即使你建立了最好的授权决策引擎,如果没有人使用它,它也没有任何价值。
让我们想象一下,你是2050年旧金山的市长。你可以建立最智能、最安全的交通灯系统,但如果自动驾驶汽车在行驶前不检查–“灯是绿的吗?”那就毫无价值。
建立一个好的决策引擎,而不使用它,是完全相同的事情。每个处理来自客户端的对象ID的API端点都应该使用决策引擎。
让我们假设一家公司已经实施了一个伟大的决策引擎,可以回答世界上所有的授权问题。
一个新的工程师加入公司并创建了一个新的控制器。
– 易受攻击的代码 –
![图片[1]-失效的对象级授权 (BOLA) 概念解析 | OWASP API TOP 1-FancyPig's blog](https://www.cvv-goods.com/wp-content/uploads/2023/03/20230222020509909.webp)
如果开发人员不使用决策引擎,那么决策引擎有多大也不重要。没有人可以阻止你,作为一个开发者,对数据库进行直接访问请求。在根据客户端的输入访问DB之前,使用决策引擎是你的责任。
一个简单的、天真的调用决策引擎的方法是。
![图片[2]-失效的对象级授权 (BOLA) 概念解析 | OWASP API TOP 1-FancyPig's blog](https://www.cvv-goods.com/wp-content/uploads/2023/03/20230222020525624.webp)
总结一下
第一部分 – 决策引擎是
- 聪明而复杂的
- 集中化的
第二部分 – 使用决策引擎是
- 简单的
- 分散在代码中的许多不同地方
针对攻击者——如何利用 BOLA
免责声明:这是我的舒适区,我真的很高兴开始写 BOLA 有趣的部分——漏洞利用。作为一个渗透测试者,如果你深入了解如何找到和利用 BOLA,你的荣耀是有保证的:)
API 易受 BOLA 攻击,就像 10 年前传统应用程序易受 SQL 注入攻击一样。
这不是针对初学者的指南,而是针对具有一些渗透测试基本经验的人的指南。如果你想从头开始学习 BOLA,Sam Huston 的这份指南是一个很好的资源。
没有一种行之有效的方法来处理 BOLA,但我将分享所需的心态和一些技巧。
如何思考
- 了解应用程序的业务逻辑
在您看到响应中的 PII 之前,不要进行自动驾驶,也不要更改 API 调用中的随机 ID。有一些自动工具可以为您完成这项工作。思考。 - 每次看到从客户端接收对象 ID 的新 API 端点时,请问自己以下问题:
* 该 ID 是否属于私有资源?例如,如果我们谈论一些“新闻”功能,并且 API 端点是“ /api/articles/555 ”,那么很可能所有对象都应该按设计公开,因为文章是公开的。
* 属于我的ID是什么? - 了解资源之间的关系
了解“旅行”和“收据”之间的关系,并且每次旅行都属于特定用户。 - 了解 API 中的角色和组
尝试了解 API 中不同的可能角色是什么。例如——用户、司机、主管、经理。 - 利用 REST API 的可预测性来寻找更多端点
您看到过一些以 RESTy 方式公开资源的端点吗?
例如:GET /api/chats/<chat_id>/message/<message_id>
不要害羞,尝试用另一种HTTP 方法替换 GET 。
如果收到错误,请尝试:
* 添加“Content-length”HTTP 标头
* 更改“Content-type”
如何测试
测试 BOLA 的基本方法是猜测对象的随机 ID,但这并不总是有效。更有效的方法是执行“会话标签交换”:
- 识别会话标签:
会话标签是一个通用术语,用于描述 API 用来识别登录用户的每个字符串。我将其称为会话标签而不是会话 ID 或身份验证令牌的原因是,对于 BOLA 开发而言,这无关紧要! - 记录来自不同用户的两个会话标签:
创建两个不同的用户并记录他们的会话标签。
For example:User 1, Hugo =
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMTEiLCJuYW1lIjoiSHVnbyIsImlhdCI6MTUxNjIzOTAyMn0.JaTvHH5TbKzgRMa5reRDMiPjHEmPKY8axsu5dFMu5Ao
User 2, Bugo =
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMjIiLCJuYW1lIjoiQnVnbyIsImlhdCI6MTUxNjIzOTAyMn0.uXTOzhX1mnYI3TZUSyjWS7qQXfYNn6qw-MehVGAgvpc
将它们保存在一个.txt文件中 - 以用户 #1 身份登录,嗅探流量并找到对从客户端接收对象 ID 的端点的 API 调用。例如:/api/trips/ e6d84adc-b1c7–4adf-a392–35e5b71f068a /details
- 重复并拦截可疑的 API 调用。
- 将用户 #1 的会话标签更改为用户 #2 的会话标签——以便代表用户 #2x 进行呼叫。
- 吸收结果。如果您收到授权错误,则端点可能不易受攻击。
- 如果端点返回对象的详细信息,则比较两个结果并检查它们是否相同。如果它们相同——端点易受攻击。
- 一些端点不返回数据。例如,端点“ DELETE /api/users/<user_id> ”只会返回没有数据的状态代码。
了解它们是否易受攻击可能会有点复杂,但不要忽视它们。
提示与技巧
- URL 中的对象 ID 往往不太容易受到攻击。尝试在 HTTP 标头/主体中的 ID 上投入更多精力。
- GUID 而不是数值?不要放弃!
使用“会话标签交换”技术或查找返回属于其他用户的对象 ID 的端点。 - 始终尝试数字 ID。如果您发现端点收到非数字对象 ID,如 GUID 或电子邮件地址,请试一试并尝试将其替换为数值(例如:将“[email protected]“替换为数字” 100″)
- 收到过一次 403/401?不要放弃!
这不是很常见,但一些奇怪的授权机制只能部分工作。尝试许多不同的 ID。例如:如果端点“ api/v1/trips/666 ”返回 403,则运行脚本以枚举从 0001 到 9999 的 50 个随机 ID。 - 在应用程序中找到最利基的功能
假设您发现了一个奇怪的功能,仅在鳄梨宣传月(顺便说一句,现在是 6 月)期间为您的个人资料创建自定义图片,并且它执行 API 调用 /api/avocado_awarness_month/profile_pics/< avocado_emoji_id >。
开发人员很有可能没有考虑过那里的授权。
如何绕过对象级授权
- 用数组包装 ID。
而不是 {“id”:111} 发送 {“id”:[111]} - 用 JSON 对象包装 ID
而不是 {“id”:111} 发送 {“id”:{“id”:111}} - 尝试执行HTTP 参数污染:
/api/get_profile?user_id=<legit_id>&user_id=<victim’s_id>
或
/api/get_profile?user_id=<victim’s_id>&user_id=<user_id>
这可以在组件的情况下工作执行授权检查和端点本身使用不同的库来解析查询参数。在某些情况下,库 #1 会使用第一次出现的“user_id”,而库 #2 会使用第二个。 - 尝试执行JSON 参数污染
POST api/get_profile
{“user_id”:<legit_id>,”user_id”:<victim’s_id>}
或
POST api/get_profile
{“user_id”:<victim’s_id>,”user_id”:< legit_id>}
这与 HTTP 参数污染非常相似。 - 尝试发送通配符而不是 ID。这种情况很少见,但有时会奏效。
- 查找未启用授权机制的 API 主机。有时,在不同的环境中,由于各种原因,授权机制可能会被禁用。例如:QA 会很脆弱,但生产不会。
- 尝试执行类型杂耍
- 不常见,但是一个很好的例子,说明如何绕过 BOLA 保护
针对热心网友的Q&A
问:什么是对象 ID?
通常对象 ID 是对象在数据库中的实际主键。
例如,这是用户表:
![图片[3]-失效的对象级授权 (BOLA) 概念解析 | OWASP API TOP 1-FancyPig's blog](https://www.cvv-goods.com/wp-content/uploads/2023/03/20230222020923757.webp)
主键将在 API 端点中使用,这些端点将用户资源作为对象 ID 进行访问。
此主键通常是序列号或 GUID。
其他选项
有时我们会看到在常规主键之上分配给每条记录的另一个唯一值。它可以用不同的方法实现,例如:执行转换的一段代码或作为数据库表中的单独列。
在这些情况下,通过 REST API 向客户端公开的对象 ID 可能是:
- 加密值(例如加密对象 ID)
- 电子邮件地址/电话号码(而不是用户 ID)
- 字母数字名称
问:BOLA 有不同类型吗?
是的。BOLA有两种主要类型:
- 基于用户 ID。
API 端点接收用户 ID 并根据此 ID 访问用户对象。例如:
/api/trips/get_all_trips_for_user? user_id =777
通常更容易解决这种类型的 BOLA,因为授权机制很简单——开发人员只需从会话中获取登录用户的 ID(例如:`current_user.id`),并将其与 user_id 进行比较从 GET 参数。
当一个用户被设计为管理其他用户时,事情会变得更加复杂(例如:子用户、区域经理等) - 基于对象 ID。
API 端点接收不是用户对象的对象的 ID。例如:
/api/trips/receipts/download_as_pdf? receipt_id =1111
在很多情况下,这不是一个简单的问题——谁应该有权访问这个对象?
问:为什么它在现代应用程序中如此普遍?
我多次问自己“为什么 BOLA 在 API 中如此普遍?” 经过广泛研究,我认为主要原因有:
原因 1——从客户端发送更多 ID
现代客户端发送的 ID 比以前更多。为什么?
A. 服务器不太了解现代应用程序中的用户状态。
在过去,服务器可能知道用户的状态:他点击了哪些按钮,他正在观看哪个对象,等等……
今天,这项工作主要由客户端完成。在现代应用程序中,服务器不太了解客户端状态。
相反,客户端会向 API 发送更多参数,以按需反映用户状态。
假设您正在使用 Uber 应用程序,并执行以下步骤:
![图片[4]-失效的对象级授权 (BOLA) 概念解析 | OWASP API TOP 1-FancyPig's blog](https://www.cvv-goods.com/wp-content/uploads/2023/03/20230222021004628.webp)
由于您有多个“行程”对象,并且服务器不知道您点击了哪个行程(此状态通常由客户端维护),因此客户端必须在进一步的 API 调用中发送所选行程的 ID。
B. REST 标准中有更多的 ID:
REST 标准鼓励开发人员在 URL 中发送 ID。
原因 2 — 解决 BOLA 的旧技巧不再有效:
由于现代 API 中的新概念,开发人员用于防止 BOLA 的一些旧技术不再有效:
答:临时表不再是一回事
回到过去,后端会为用户呈现一个仅包含属于他的元素的可视化表的情况很常见。ID 是表的临时 ID,服务器将以各种方式维护临时 ID 和内部 ID 之间的关联。
假设我们正在谈论一个传统的应用程序,您可以在其中创建子用户并管理它们。服务器将呈现一个可视化 HTML 页面,其中包含您有权访问的所有用户的表格:
![图片[5]-失效的对象级授权 (BOLA) 概念解析 | OWASP API TOP 1-FancyPig's blog](https://www.cvv-goods.com/wp-content/uploads/2023/03/20230222021008483.webp)
该表还将包含按钮,例如“删除用户”。
如果用户单击此按钮,客户端将触发对删除特定用户的控制器的 HTTP 调用。
因为你有 3 个子用户,你应该提到你要删除哪一个。
在传统的应用程序中,通常看到发送的 ID 是临时 ID(1/2/3)而不是内部 ID。
在现代应用程序中,这种模式真的很少见,主要是因为它不符合 API 的无状态特性。
B:视图状态和类似技术:
视图状态是解决 BOLA 的一种方法,通过存储用户应该有权访问的 ID,然后对视图状态进行签名。
但由于 REST API 的无状态性,这些技术在今天非常罕见。
原因 3——现代授权机制很复杂:
即使你有一个像样的授权决策引擎并且你记得从每个控制器调用它,也可能很难回答像“用户 X 是否有权访问收据 Y”这样的问题,因为旅行可能是在用户之间共享,或者您有一个区域管理员只能访问他所在区域的用户收据。
问:哪些解决方案不能解决问题?
我看到一些安全谈话建议使用并不能真正解决问题的解决方案。
更糟糕的是,我看到了声称可以解决 BOLA 问题的安全解决方案,但事实并非如此。
不能解决 BOLA 的事情:
- GUID 而不是数字 ID
这可能是一个额外的安全层,使攻击者的生活更加艰难,但它绝对不能解决问题。 - 依赖 JWT 令牌中的 ID。
如果您将 JWT 令牌或任何其他类型的身份验证令牌中的 ID 与作为参数发送到端点本身的用户 ID 进行比较,它并不能解决所有 BOLA 事件。
它可能会解决类型 #1,其中易受攻击的 ID 是用户 ID。但它不能解决类型 #2,并且可能会遗漏许多类型 #1 的情况,例如允许用户编辑其他用户的情况。 - 依赖于请求的输入
您可能会将客户端应该有权访问的所有 ID 放入客户端无法操作的存储中,因为它是由服务器签名的(JWT 令牌或某种类型的视图状态),然后您可以将潜在易受攻击的 ID 与此“安全 ID”列表进行 ID 比较。
如果我们忽略它破坏 REST 设计的事实,它是不可行的,因为在现代 API 中,一个用户可能可以访问数百甚至数千个 ID。 - OAuth:与 BOLA 无关。
问:为什么我们将名称从 IDOR 更改为 BOLA?
很好的问题。IDOR 是一个很酷的名字,但它并不准确。
“IDOR——不安全的直接对象引用”这个名字暗示了两件事:
- 问题出在 ID(对象引用)上
- ID不应该是直接的
它们在现代应用程序中都不是真正有效的。
首先,问题不在于对象引用(ID),而是缺乏验证登录用户是否应访问对象的授权机制。
其次,有一些实现“安全间接”机制的想法,该机制包装应用程序并通过用唯一 ID 替换原始 ID 来解决问题。
这个想法说后端需要维护一个表,该表在原始 ID 和随机的、用户特定的 ID 之间进行转换
![图片[6]-失效的对象级授权 (BOLA) 概念解析 | OWASP API TOP 1-FancyPig's blog](https://www.cvv-goods.com/wp-content/uploads/2023/03/20230222021037668.webp)
这是一个很好的概念,但在 API 中实现是完全不可行的,原因如下:
- REST 标准鼓励开发人员从客户端接收许多 ID。由于在现代应用程序中渲染是在客户端而不是服务器中完成的,因此情况变得更糟。因此,每个 API 中都有许多 ID 需要处理。例如:
/api/v2/company/<company_id>/users/<user_id> - 这将非常难以实施——开发人员根本不会这样做
- IDOR 漏洞更通用,包含其他用例并涵盖“文件路径访问控制”等问题。其他用例在现代应用程序和 API 中不太常见,我们认为它们不像 BOLA 那样严重。
暂无评论内容