Pico Org
3398 字
17 分钟
OAuth2攻击面分析

1. 前言#

随着大量开放平台的出现,建立在开放平台之上的各种第三方应用也在大量涌现,出于对安全性和统一标准的要求,诞生了oauth协议。

OAuth 1.0于2007年推出后迅速被广泛使用。

但是在2009年,OAuth 1.0被曝出存在严重安全漏洞Session Fixation Attack,于同年发布修复后版本OAuth 1.0 Revision A

2010年发布OAuth 2.0,是OAuth协议的下一版本,但与OAuth 1.0版本互不兼容。

2013年发布PKCE(Proof Key for Code Exchange by OAuth Public Clients),是OAuth 2.0的一个扩展,用于增强公共客户端的安全性。

2015年发布OAuth 2.0 for Native Apps,是OAuth 2.0的一个扩展,用于增强移动应用的安全性,描述了使用OAuth 2.0的本机和移动应用程序的安全要求和其他建议。包括不允许第三方应用打开嵌入式web视图,以防止钓鱼攻击,以及如何在平台上执行的特定建议。同时还建议使用PKCE扩展进一步保护用户。

2017年发布Security Best Current Practice,是OAuth 2.0的一个扩展,描述了安全要求和其他建议,用于实现OAuth 2.0的客户端和服务器。

2019年发布OAuth 2.0 for Browser-Based Apps,是OAuth 2.0的一个扩展,用于增强浏览器应用的安全性,针对SPA(Single Page Application)建议使用PKCE扩展替代隐式授权流(Implicit flow)。

2021年发布OAuth 2.1,OAuth 2.1总结了后续规范中发布的更改,以简化核心文档。主要区别如下:

  • PKCE是所有使用授权码流的OAuth客户端的必需项
  • 重定向URI必须使用精确字符串匹配进行比较
  • 省略了隐式授权流(response_type = token)的定义
  • 省略了资源所有者密码凭证授予的定义
  • Bearer令牌使用省略了在URI的查询字符串中使用bearer令牌的使用
  • 对于公共客户端,刷新令牌必须是发送者约束的或一次性使用
  • 公共和机密客户端的定义已简化为仅指示客户端是否具有凭据

1.1. OAuth 1.0漏洞(Session Fixation Attack)分析#

801e57d84801b8abf8cde2e8793bf185.png

正常流程为:

  1. 用户访问第三方应用
  2. 用户请求从资源提供者导入资源
  3. 用户携带oauth_token跳转到资源提供者的授权页面
  4. 用户登录到资源提供者系统
  5. 用户授权oauth_token访问资源权限
  6. 用户携带oauth_token跳转到return_url指定的第三方应用
  7. 第三方应用使用oauth_token请求资源

79e8df9b51ab3f86d871bd6002f2dc2c.png

攻击者可以利用的流程在3、4、5、6步骤

  1. 攻击者构造包含oauth_token和无效return_url的URL
  2. 让受害者点击链接访问,登录授权后,跳转到无效return_url
  3. 此时受害者授权流程已经中断,攻击者可以利用受害者的oauth_token访问第三方应用完成授权

漏洞成因可以总结为,授权码生成方式问题。OAuth1.0中,授权码在请求授权过程中可任意生成,导致授权码可能来自于攻击者。同时授权和令牌获取过程是割裂的,导致攻击者可以优先于受害者获取令牌。

2. 什么是OAuth2#

OAuth 2.0是一个业界标准的授权协议,其定义了四种可以适用于各种应用场景的授权交互模式:

  • 授权码模式(Authorization Code)
  • 客户端凭证模式(Client Credentials)
  • 用户凭证模式(Resource Owner Password Credentials)
  • 隐式授权模式(Implicit)

其中,授权码模式被广泛应用于第三方互联网开放平台,通过第三方登录是其最常见应用场景之一,比如使用微信、QQ和淘宝账号进行登录。

有一些设备存在无浏览器或输入受限情况,所以在rfc8628 - OAuth 2.0 Device Authorization Grant引入设备授权(Device code)模式。

为了解决SPA、原生应用等授权安全性问题,基于授权码模式引入PKCE,形成授权码+PKCE模式(Authorization Code with PKCE)。

2.1. 角色#

OAuth 2.0定义了四种角色:

  1. 资源拥有者(Resource Owner):资源拥有者是指可以授权第三方应用访问自己资源的用户,比如微信用户。
  2. 资源服务器(Resource Server):资源服务器是指存储资源的服务器,比如微信服务器。
  3. 客户端(Client):客户端是指第三方应用,比如京东小程序。
  4. 授权服务器(Authorization Server):授权服务器是指用于进行授权的服务器,比如微信开放平台。

2.2. 协议流程#

+--------+                               +---------------+
|        |--(A)- Authorization Request ->|   Resource    |
|        |                               |     Owner     |
|        |<-(B)-- Authorization Grant ---|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(C)-- Authorization Grant -->| Authorization |
| Client |                               |     Server    |
|        |<-(D)----- Access Token -------|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(E)----- Access Token ------>|    Resource   |
|        |                               |     Server    |
|        |<-(F)--- Protected Resource ---|               |
+--------+                               +---------------+
  • A. 客户端向资源拥有者发起授权请求,请求授权服务器授予客户端访问资源服务器的权限。
  • B. 资源拥有者授权客户端访问资源服务器的权限,授权服务器返回授权码给客户端。
  • C. 客户端向授权服务器请求访问令牌。
  • D. 授权服务器验证授权码,返回访问令牌给客户端。
  • E. 客户端向资源服务器请求资源。
  • F. 资源服务器验证访问令牌,返回资源给客户端。

2.3. 授权模式#

仅ABCD流程不同,区分为不同模式。

2.3.1. 授权码模式(Authorization Code)#

997ae2800f9c9f31ee64b386c160e018.png

这种模式广泛用于第三方应用授权登录,比如使用微信、QQ账号进行登录。

2.3.2. 授权码+PKCE模式(Authorization Code with PKCE)#

rfc7636 - Proof Key for Code Exchange by OAuth Public Clients定义了PKCE,用于解决授权码模式存在的安全性问题。

3a1c8a2c4c9483dd97d676d46f7c373a.png

这种模式广泛用于客户端应用授权登录,比如electron应用、移动应用等。

其中:

  • code_verifier:在 [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~" 范围内,生成43-128位的随机字符串。
  • code_challenge:则是对 code_verifier 通过 code_challenge_method 例如 sha256 转换得来的。

Q: PKCE到底防御哪种攻击? A: 在SPA、原生应用(如移动应用)、桌面应用(如electron)中,授权过程中有可能会打开外部浏览器,而浏览器可能会被其他应用劫持,导致授权过程被篡改。PKCE是为了防御这种攻击。

2.3.3. 客户端凭证模式(Client Credentials)#

0ea51598b4ff50260fb5617c783417a8.png

这种模式用于客户端应用存储凭证,自行授权访问资源服务器,比如后端服务使用AK/SK请求操作OSS资源。

2.3.4. 用户凭证模式(Resource Owner Password Credentials) 不安全#

9c140672e8cc8683a074d16fdae83826.png

由于凭证会发送给第三方使用,所以这种模式不安全,不推荐使用。

2.3.5. 隐式授权模式(Implicit) 不安全#

25d2de245c3a6040111a64eb1d91f7f8.png

一般用于无后端应用,前端存储凭证。

由于是跳转到三方应用使用GET请求,且服务器直接回传的是授权凭证,在终端容易被读取,如通过资源文件referer,所以这种模式不安全,不推荐使用。

在某篇博客中曾看到,腾讯存在某个服务使用了隐式授权模式,但是回传Access Token的时候,使用锚点(#),这样锚点之后的数据就不会发送给服务器。但是这种方式也存在安全问题,因为锚点之后的数据是可以被前端获取的,所以这种方式也不安全。

2.3.6. 设备代码模式(Device Code) 极大概率存在Session Fixation Attack漏洞#

rfc8628 - OAuth 2.0 Device Authorization Grant定义了一种新的授权模式,用于设备在无浏览器或输入受限情况下的授权。

+----------+                                +----------------+
|          |>---(A)-- Client Identifier --->|                |
|          |                                |                |
|          |<---(B)-- Device Code,      ---<|                |
|          |          User Code,            |                |
|  Device  |          & Verification URI    |                |
|  Client  |                                |                |
|          |  [polling]                     |                |
|          |>---(E)-- Device Code       --->|                |
|          |          & Client Identifier   |                |
|          |                                |  Authorization |
|          |<---(F)-- Access Token      ---<|     Server     |
+----------+   (& Optional Refresh Token)   |                |
      v                                     |                |
      :                                     |                |
      (C) User Code & Verification URI      |                |
      :                                     |                |
      v                                     |                |
+----------+                                |                |
| End User |                                |                |
|    at    |<---(D)-- End user reviews  --->|                |
|  Browser |          authorization request |                |
+----------+                                +----------------+

e8de63708d5258e6d0d07dc059185078.png

当Device Client为公共客户端,将退化为OAuth1.0认证方式。

2.4. OIDC#

OpenID Connect 1.0 是 OAuth 2.0 协议的一个简单身份层。它允许客户端基于授权服务器执行的身份验证来验证最终用户的身份,以及以可互操作且类似 REST 的方式获取有关最终用户的基本配置文件信息。

简单来说:

  • 授权码模式:使用response_type=code,用授权码换取令牌AccessToken。
  • OIDC:使用scope=openid&response_type=code,用授权码换取用于验证身份的JWT。

3. OAuth2攻击面#

3.1. CSRF导致绑定劫持#

攻击者抓取认证请求构造恶意url,并诱骗已经登录的网用户点击(比如通过邮件或者QQ等方式),认证成功后用户的帐号会同攻击者的帐号绑定到一起。

OAuth 2.0提供了state参数用于防御CSRF,认证服务器在接收到的state参数按原样返回给redirect_uri,客户端收到该参数并验证与之前生成的值是否一致,除此方法外也可使用传统的CSRF防御方案。

3.2. redirect_uri绕过导致授权劫持#

根据OAuth的认证流程,用户授权凭证会由服务器转发到redirect_uri对应的地址。

如果攻击者伪造redirect_uri为自己的地址,然后诱导用户发送该请求,之后获取的凭证就会发送给攻击者伪造的回调地址,攻击者使用该凭证即可登录用户账号,造成授权劫持。

正常情况下,为了防止该情况出现,认证服务器会验证自己的client_id与回调地址是否对应,常见的方法是验证回调地址的主域。

以下几种情况验证配置不当,容易导致授权劫持:

  1. 未验证

    未验证的情况,可以直接跳出外域。案例:土豆网某处认证缺陷可劫持oauth_token

  2. 验证绕过

  3. 子域可控

    对回调地址验证了主域为app.com,但其子域evil.app.com可被任意用户注册使用。案例:新浪微博部分App Oauth2漏洞

  4. 跨域

    1. 利用可信域跳转盗取授权码。
      1. 如果网站存在任意跳转,如https://www.example.com/?return_url=,且未校验跳转后地址。可以构造如下向量https://www.example.com/?return_url=https://www.evil.com
      2. 诱骗用户访问该链接https://www.example.com/oauth/authorize?client_id=xxx&redirect_uri=https://www.example.com/?return_url=https://www.evil.com&response_type=code&state=xxx触发OAuth认证
      3. 用户授权之后,会继续跳转到https://www.evil.com,攻击者可以从referer头获取到授权码。
    2. 利用可信域referer盗取授权码。
      1. 如果跳转后页面可控,比如可以插入自定义图片,或者存在xss漏洞,可以构造向量<img src="https://www.evil.com">,用户授权之后,会向https://www.evil.com请求资源文件,攻击者可以从referer头获取到授权码。

3.3. scope越权访问#

案例:从“黑掉GITHUB”学WEB安全开发展示了scope权限控制不当带来的安全风险,同时将授权劫持的几个方面演绎的淋漓尽致。

4. 名词解释#

  • CAS: Central Authentication Service, 中心认证服务
  • AS: Authorization Server, 授权服务器
  • RS: Resource Server, 资源服务器
  • SPA: Single Page Application, 单页应用
  • SSO: Single Sign On, 单点登录
  • OIDC: OpenID Connect, 开放身份连接

5. 参考资料#

OAuth2攻击面分析
https://picoorg.github.io/posts/oauth2攻击面分析/
作者
Pico Org
发布于
2024-05-07
许可协议
CC BY-NC-SA 4.0