理解 OAuth 2.0

2021-08-28 20:41:18 浏览数 (1)

前言

OAuth 2.0 是一个用于授权的标准协议。OAuth 2.0 聚焦于客户端开发者提供简化的授权流程,包括 Web 应用、桌面应用、智能手机应用以及物联生活设备(例如电视)。其说明文档和扩展在这里有说明。

上面一段话是 OAuth 2.0 官网的一段描述。其中有些关键字:授权、标准、简化以及各种场景。

首先我们来看下授权,英文为 Authorization,容易混淆的一个词为鉴权,英文为 Authentication。对于这两个概念,在这里有比较。笔者总结下文章里说的内容:

鉴权是为了确认用户确实就是那个自己,而授权是给予用户访问资源的权限,鉴权方式当前包括密码、一次性口令、鉴权应用和生物凭证;授权例子包括对服务器上特定文件访问许可、对应用的管理权限使用;当然在很多情况下授权实际上与鉴权关联比较紧密,例如一个开发者拥有腾讯云的一个子账号,通过密码登录(鉴权)之后,可以操作主账号(授权)的一些CVM(允许),但不能访问主账号的COS资源(拒绝)。

所以 OAuth 2.0 是授权不是鉴权。

四种模式

关于 OAuth 2.0 一般都会提到其四种模式,

  • Authorization Code
  • Client Credentials
  • Implicit Flow
  • Password Grant

关于上面四种模式笔者在这里不做介绍,因为网络上已经有大量文章做了这方面介绍,在这里笔者只是对这里的内容做些补充。

Authorization Code 是最为推荐的流程,没有特殊限制都应该使用这一模式。

Client Credentials 后端使用,没有让步。

Implicit Flow 由于一些安全性问题而不建议使用了,类似于这种纯Web端应用可以使用到这种模式,不过当前有新的方案。

Password Grant 模式由于密码托管方不可控,更不建议使用,甚至可以说是禁止使用。

PKCE

关于无后台应用移动端应用(又称原生应用或者公共应用)需要使用 PKCE(Proof Key for Code Exchange)模式,是基于 Authorization Code 模式做了扩展,因为原生应用无法确保 client_secret 的机密性,或者没有 client_secret 可言,那么只要劫持到 Authorization Code 恶意应用就能拿到 Access Token,rfc7636描述的劫持流程如下,

代码语言:javascript复制
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
| End Device (e.g., Smartphone)  |
|                                |
|  -------------     ----------  | (6) Access Token   ---------- 
| |Legitimate   |   | Malicious|<--------------------|          |
| |OAuth 2.0 App|   | App      |-------------------->|          |
|  -------------     ----------  | (5) Authorization |          |
|        |    ^          ^       |        Grant      |          |
|        |              |       |                   |          |
|        |         (4)  |       |                   |          |
|    (1) |         Authz|       |                   |          |
|   Authz|         Code |       |                   |  Authz   |
| Request|              |       |                   |  Server  |
|        |              |       |                   |          |
|        |              |       |                   |          |
|        v              |       |                   |          |
|  ----------------------------  |                   |          |
| |                            | | (3) Authz Code    |          |
| |     Operating System/      |<--------------------|          |
| |         Browser            |-------------------->|          |
| |                            | | (2) Authz Request |          |
|  ----------------------------  |                    ---------- 
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

劫持过程在第(4)步,具体解释可以参见rfc7636或者这里或者这里。在有后端的场景下,我们一般认为 Authorization Code 模式已经足够安全了,但是在客户端存在 Authorization Code 被劫持的风险场景下,PKCE 是一个必选项。

为什么需要 Authorization Code(授权码)

标准 Authorization Code 模式流程如下,

代码语言:javascript复制
 --------                                 --------------- 
|        |--(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 流程都是后端流程,前端流程可以认为安全性弱与后端,而前端的便利交互的便利程度又优于后端,所以通过前端拿 Authorization Code 更方便,而通过后端拿 Access Token 更安全。

为什么需要 OpenID Connect

OpenID Connect 的主页在这里。首先明确 OpenID Connect 基于 OAuth 2.0,是简单的身份认证层,允许客户端校验终端用户身份信息。这里描述了获取终端用户身份信息的协议标准,例如 Authorization Code 模式下,Authorization Request 中 scope 中必须带 openid。在 Access Token 应答中会返回 id_token 字段,这里有 ID Token 的说明,同时标准规定了远端校验接口 tokeninfo,这附加信息获取接口 userinfo。所以,在没有 OpenID Connect 的情况如果需要认证用户的信息,身份提供方都需要提供非标准的接口通过 Access Token 进行获取。

state 与 nonce

这里对这两者的作用进行探讨。总结下来就是 state 用于授权请求,让客户端可以校验应答是否来源于原始授权服务器,即授权应答的跨站检查;而 nonce 出现在 OpeID Connect 说明中,如果客户端使用了,那么它会出现在 id_token 中,所以也可以用来检查 id_token 是否来源于原始授权服务器,即 id_token 的跨站检查;

小结

在梳理 OAuth 2.0 的内容时,笔者发现在之前有过广泛应用或者出现的标准,在现在都已变得不推荐甚至是弃用,而且在曾经认为是标准流程规范,也不得不因为安全问题对其进行增强。另外 OAuth 2.0 解决的虽然是授权,但是应用的场景众多,而且会与时俱进,如 OAuth 2.1 已经提出,尝试对 OAuth 2.0 进行简化。所以,一项标准紧紧跟随应用场景和技术发展才更有生命力。

0 人点赞