在浏览网页时,你肯定会遇到允许你使用社交媒体账户登录的网站。此功能一般是使用流行的OAuth 2.0框架构建的。在博主的上一篇文章《什么是OAuth 2.0?OAuth 2.0的工作流程是什么?与OAuth 1.0有哪些区别?》中详细介绍了OAuth 的基础知识和工作原理,本文则主要介绍如何识别和利用OAuth 2.0身份验证机制中发现的一些关键漏洞。
1. 漏洞产生原因
-
OAuth身份验证漏洞的出现部分是因为OAuth规范在设计上相对模糊和灵活。尽管每种授权类型的基本功能都需要一些强制性组件,但绝大多数实现都是完全可选的。这包括许多保持用户数据安全所必需的配置设置。 -
OAuth的另一个关键问题是普遍缺乏内置的安全功能。安全性几乎完全依赖于开发人员使用正确的配置选项组合,并在上面实现他们自己的附加安全措施,例如稳健的输入验证。正如您可能已经收集到的,有很多东西需要接受,如果对OAuth缺乏经验,就很容易出错。 -
根据授权类型的不同,高度敏感的数据也会通过浏览器发送,这为攻击者拦截数据提供了各种机会。
2. 如何识别OAuth身份验证
识别应用程序何时使用OAuth身份验证相对简单。如果你看到使用其他网站的账户登录的选项,这强烈表明正在使用OAuth。
识别OAuth身份验证的最可靠方法是通过Burp代理流量,并在使用该登录选项时检查相应的HTTP消息。无论使用哪种OAuth授权类型,流的第一个请求都将始终是对 /authorization
端点的请求,其中包含许多专门用于OAuth的查询参数。特别要注意 client_id
、 redirect_uri
和 response_type
参数。例如,授权请求通常如下所示:
GET /authorization?client_id=12345&redirect_uri=https://client-app.com/callback&response_type=token&scope=openid%20profile&state=ae13d489bd00e3c24 HTTP/1.1
Host: oauth-authorization-server.com
3. 如何利用OAuth身份验证
本章节主要介绍几种常见的身份验证漏洞利用思路,具体完整的利用可以参阅:
-
《OAuth 2.0身份验证漏洞_网络安全学院.pdf》(下载链接:https://url25.ctfile.com/f/1848625-1054213243-ef9e8f?p=6277,访问密码:6277)
3.1. OAuth客户端应用程序中存在漏洞
正如前面已经提到的,OAuth规范的定义相对松散。对于客户端应用程序的实现来说尤其如此。OAuth流中有很多交互流程,每个授予类型中都有许多可选参数和配置设置,这意味着存在大量错误配置的空间。
3.2. 隐式授予类型的实现不正确
由于通过浏览器发送访问令牌会带来危险,因此主要建议单体应用程序使用隐式授予类型。然而,由于其相对简单,它也经常用于经典的客户端-服务器web应用程序。
在这个流中,访问令牌作为URL片段通过用户的浏览器从OAuth服务发送到客户端应用程序。然后,客户端应用程序使用JavaScript访问令牌。问题是,如果应用程序想在用户关闭页面后维护会话,它需要将当前用户数据(通常是用户ID和访问令牌)存储在某个地方。
为了解决这个问题,客户端应用程序通常会在 POST 请求中将这些数据提交给服务器,然后为用户分配一个会话cookie,从而有效地将他们登录。这个请求大致相当于表单提交请求,该请求可能会作为经典的基于密码的登录的一部分发送。然而,在这种情况下,服务器没有任何密码可以与提交的数据进行比较,这意味着它是隐式信任的。
在隐式流中,此 POST 请求通过浏览器暴露给攻击者。因此,如果客户端应用程序没有正确检查访问令牌是否与请求中的其他数据匹配,这种行为可能会导致严重的漏洞。在这种情况下,攻击者可以简单地更改发送到服务器的参数以模拟任何用户。
3.3. CSRF保护有缺陷
尽管OAuth流的许多组件都是可选的,但强烈建议使用其中一些组件,除非有重要原因不使用它们。比如 state
参数。
理想情况下,state
参数应该包含一个不可访问的值,例如在用户会话首次启动OAuth流时绑定到该会话的某个值的哈希。然后,该值作为客户端应用程序的CSRF令牌的形式在客户端应用程序和OAuth服务之间来回传递。因此,如果您注意到授权请求没有发送state
参数,那么从攻击者的角度来看,这是非常有趣的。这可能意味着他们可以在诱骗用户的浏览器完成OAuth流之前自己启动OAuth,类似于传统的CSRF攻击。这可能会产生严重后果,具体取决于客户端应用程序使用OAuth的方式。
考虑一个允许用户使用经典的基于密码的机制登录的网站,或者使用OAuth将其账户链接到社交媒体档案。在这种情况下,如果应用程序未能使用state
参数,攻击者可能会将受害者用户在客户端应用程序上的账户绑定到他们自己的社交媒体账户,从而劫持受害者用户的账户。
请注意,如果站点允许用户以独占方式通过OAuth登录,那么
state
参数可能不那么重要。然而,不使用state
参数仍然可以允许攻击者构建登录CSRF攻击,从而诱使用户登录到攻击者的帐户。
3.4. 泄露授权码和访问令牌
最臭名昭著的基于OAuth的漏洞可能是OAuth服务本身的配置使攻击者能够窃取授权码或访问与其他用户账户相关的令牌。通过窃取有效的代码或令牌,攻击者可能能够访问受害者的数据。
根据授权类型,通过受害者的浏览器将代码或令牌发送到授权请求的 redirect_uri
参数中指定的 /callback
端点。如果OAuth服务未能正确验证此URI,攻击者可能能够构建类似CSRF的攻击,诱使受害者的浏览器启动OAuth流,该流将代码或令牌发送给攻击者控制的站点。
请注意,使用
state
或nonce
保护并不一定能防止这些攻击,因为攻击者可以从自己的浏览器生成新值。
4. 如何防止OAuth身份验证漏洞
为了防止OAuth身份验证漏洞,OAuth提供程序和客户端应用程序都必须对密钥输入(尤其是 redirect_uri
参数)进行稳健的验证。OAuth规范中几乎没有内置的保护,因此由开发人员自己来确保OAuth流尽可能安全。
4.1. 对于OAuth服务提供商
-
要求客户端应用程序注册有效 redirect_uris
的白名单。只要可能,请使用严格的逐字节比较来验证任何传入请求中的URI。只允许完全和精确的匹配,而不是使用模式匹配。这可以防止攻击者访问白名单域上的其他页面。 -
强制使用 state
参数。它的值还应该通过包括一些不可访问的、特定于会话的数据(例如包含会话cookie的哈希)来绑定到用户的会话。这有助于保护用户免受类似CSRF的攻击。这也使攻击者更难使用任何被盗的授权码。 -
资源服务器上,确保验证访问令牌是否已颁发给发出请求的 client_id
。此外,还应该检查请求的作用域,以确保它与最初授予令牌的作用域相匹配。
4.2. 对于OAuth客户端应用程序
-
在实现OAuth之前,请确保已经完全了解其工作原理的细节。许多漏洞都是由于对每个阶段到底发生了什么以及如何利用这些漏洞缺乏了解而导致的。 -
使用 state
参数,即使它不是强制性的。 -
将 redirect_uri
参数不仅发送到/authorization
端点,还发送到/token
端点。 -
在开发移动或本机桌面OAuth客户端应用程序时,通常不可能将 client_secret 保持为私有。在这些情况下, PKCE ( RFC 7636 )
机制可以用于提供针对访问代码拦截或泄漏的额外保护。 -
如果使用 OpenID Connect id_token
,请确保根据JSON Web签名、JSON Web加密和OpenID规范对其进行了正确验证。 -
小心使用授权代码:当加载外部图像、脚本或CSS内容时,它们可能会通过 Referer 标头泄漏。不要将它们包含在动态生成的JavaScript文件中,因为它们可以通过 <script>
标签从外部域执行。
5. 参考链接
-
https://portswigger.net/web-security/oauth -
https://portswigger.net/research/hidden-oauth-attack-vectors -
https://portswigger.net/web-security/oauth/grant-types -
https://portswigger.net/web-security/oauth/preventing
博主简介:10年+ 网络安全领域大厂工作经验,国际注册信息系统安全专家CISSP证书持有者,发表多篇SCI论文及专利,专注于SDL、DevSecOps、安全体系构建、安全工具等网络安全垂直知识分享与交流。
欢迎关注博主,解锁全栈安全知识!
原文始发于微信公众号(全栈安全):「 典型安全漏洞系列 」12.OAuth 2.0身份验证漏洞攻击和防御思路
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论