OAuth2 协议解析(安全视角)

目录


Refinition

OAuth2 是在WEB基础上发展出来的一个授权框架(Authorization Framework),也可以认为它是一套协议,一套能解决第三方授权问题的解决方案,优势在于它允许第三方应用在不获取用户密码的情况下,获得访问用户资源(用户的ID信息等)的有限权限。

它是如何做到的?下面来解析一下这个协议。

搞懂这个协议,需要理解下面几个部分:

四个核心角色

OAuth2 流程中有四个关键角色:

  • 资源所有者 (Resource Owner)

    用户(一般指使用客户端的人),他拥有受保护资源(一般指他的账号信息);

  • 客户端 (Client)

    一个前端UI应用,方便用户操作的面板。一般来说客户端和授权服务器是前后端关系。

  • 授权服务器 (Authorization Server)

    验证用户身份并颁发令牌的 绝对控制者。

  • 资源服务器 (Resource Server)

    一般指可以提供给用户使用的服务器,能给用户提供专属服务,比如网盘服务、点外卖服务,这种也叫第三方应用。

    资源服务器一般需要用户信息,才能提供服务。

    获得用户信息,可以让用户注册,但是APP太多了,很多用户不愿意注册了。就发展出第三方应用去授权服务器拿取用户ID的免注册模式。

四类常见授权模式

OAuth2 定义了多种授权方式,适应不同场景,下面看4个常见:

  • 授权码模式 (Authorization Code) - 最常用、较安全(本文讨论这个模式)
  • 密码模式 (Resource Owner Password Credentials) - 需要信任客户端
  • 客户端凭证模式 (Client Credentials) - 应用访问自己的资源
  • 隐式模式 (Implicit) - 较不安全,已不推荐

授权模式中的术语

  • 令牌 (Tokens)

    • 访问令牌 (Access Token):相当于"临时门禁卡",用于访问资源
    • 刷新令牌 (Refresh Token):用于获取新的访问令牌,避免用户频繁重新登录
  • ......


OAuth2 协议流程解析

在看时序图之前,必须先清楚各个角色的作用,不然就会混乱。

时序图,简版流程:
sequenceDiagram actor User as 用户 participant Client as 客户端应用 participant AuthServer as 授权服务器 participant ResourceServer as 资源服务器 Note over User, Client: 1. 启动授权流程 User->>Client: 访问应用 Client->>User: 重定向到授权服务器 Note over User, AuthServer: 2. 用户认证与授权 User->>AuthServer: 在授权页面登录并授权 AuthServer->>User: 重定向回应用并携带授权码 Note over Client, AuthServer: 3. 交换令牌(后端通信) Client->>AuthServer: 发送授权码 + 客户端凭证 AuthServer->>Client: 返回访问令牌 Note over Client, ResourceServer: 4. 访问资源 Client->>ResourceServer: 使用访问令牌请求资源 ResourceServer->>Client: 返回受保护资源 Client->>User: 显示用户请求的内容


更接近实际的流程,以企微授权一个工作台应用案例为例子:
sequenceDiagram actor 用户 participant 客户端 as 企业微信客户端<br>(浏览器/WebView) participant 应用 as 企微工作台应用<br>(Your Server) participant 授权服务器 as 企业微信<br>授权服务器 participant 资源服务器 as 企业微信<br>资源服务器 用户->>客户端: 1. 点击工作台应用图标 客户端->>应用: 2. 访问应用首页 (GET /) Note over 应用, 授权服务器: 认证与授权阶段 应用->>客户端: 3. 重定向到企微授权页<br>?response_type=code&redirect_uri=... 客户端->>授权服务器: 4. 跳转到授权页面 授权服务器->>用户: 5. (可选) 向用户显示授权同意页面 用户->>授权服务器: 6. 点击同意授权 授权服务器->>客户端: 7. 重定向到 redirect_uri 并携带 code 客户端->>应用: 8. 请求 Callback URL (GET /callback?code=...) Note over 应用, 资源服务器: 获取访问令牌与用户信息 应用->>授权服务器: 9. 用 code 换取 access_token<br>(POST /token) + secret 授权服务器->>应用: 10. 返回 access_token 应用->>资源服务器: 11. 使用 access_token 获取用户信息<br>(GET /userinfo?access_token=...) 资源服务器->>应用: 12. 返回用户信息 (e.g., UserId) Note over 应用, 用户: 正常业务访问 应用->>应用: 13. 根据UserId处理业务逻辑<br>(e.g., 查询数据库) 应用->>客户端: 14. 返回个性化应用页面 客户端->>用户: 15. 显示应用内容

以上都是以一个用户视角看的流程,其实后端之间还做了很多事情,才能保障整个流程的安全,不过下面的流程图需要以一个开发者的角度看待,下面继续解构。


后端之间的交互流程-包含安全方案设计

下面以企业微信OAuth2授权码流程,以开发者(应用服务器/资源服务器)的视角,看待应用如何与企微授权服务器建立联系,包括如何获取安全凭证(如Secret)、验证的流程。

企业微信OAuth2授权码流程中,开发者需要先在企微管理后台创建应用,获取应用的安全凭证(corp_id, secret等),然后在应用服务器中使用这些凭证。

整体流程分为两个主要部分:

  • 应用注册与安全凭证发放(静态配置)
  • OAuth2授权码流程(动态交互)

理解几个密码学上关键的工具包:

  • AgentId
  • Secret
  • 随机数
  • 签名-HMAC
  • ......

应用注册与安全凭证发放

这一步是确保整体安全的关键流程,Secret参数作为一个关键密钥(可以申请更换),它也是标识身份,防抵赖性作用。

一个AgentId 对应 一把Secret密钥。
Secret必须安全地存储在应用服务器内,只做打签名用。不可以暴露,否则有被冒充安全风险!
sequenceDiagram participant 开发者 participant 企微管理后台 participant 应用服务器 开发者->>企微管理后台: 1. 登录管理后台 开发者->>企微管理后台: 2. 创建应用(设置应用名称、logo等) 企微管理后台->>开发者: 3. 返回应用凭证:AgentId、Secret等 开发者->>应用服务器: 4. 配置AgentId和Secret


OAuth2授权码流程

State:

客户端生成 State 流程:

  1. 收集数据:随机数 + 时间戳 + 会话ID + 业务参数
  2. 构建结构:
  3. 计算签名:HMAC-SHA256(排序后的数据字符串, client_secret)
  4. 添加签名:
  5. Base64编码:生成最终的state参数

客户端/服务端验证 State 流程:

  1. Base64解码state,得到原始数据结构
  2. 提取签名值,从数据结构中移除签名字段
  3. 重新计算签名:HMAC-SHA256(相同的排序数据, client_secret)
  4. 对比签名:恒定时间比较计算签名与提取签名
  5. 如果一致 → 数据未被篡改,验证通过
  6. 如果不一致 → 可能被篡改,拒绝请求

graph TB A[客户端生成state] --> B[使用client_secret签名] C[客户端验证state] --> D[使用client_secret验签] B --> E[确保数据完整性] D --> E


再次看OAuth2授权码流程
sequenceDiagram participant User as 用户 participant Client as 客户端应用 participant Browser as 浏览器 participant AuthServer as 授权服务器 participant TokenStore as 令牌存储 Note over Client, AuthServer: State 生成与签名阶段 User->>Client: 1. 访问应用 Client->>Client: 2. 生成 State 参数 Note right of Client: - 收集会话ID<br/>- 生成随机数<br/>- 记录时间戳<br/>- 添加业务上下文 Client->>Client: 3. State 签名 Note right of Client: - 排序数据字段<br/>- 计算HMAC签名<br/>- Base64编码 Client->>Browser: 4. 存储State到Session Client->>Browser: 5. 重定向到授权页(带state) Note over Browser, AuthServer: 用户认证与授权阶段 Browser->>AuthServer: 6. 请求授权页面 AuthServer->>User: 7. 显示登录页面 User->>AuthServer: 8. 输入凭证并授权 AuthServer->>AuthServer: 9. 验证用户凭证 Note over AuthServer, TokenStore: Code 生成阶段 AuthServer->>AuthServer: 10. 生成授权码(Code) Note right of AuthServer: - 关联用户ID<br/>- 绑定客户端ID<br/>- 设置权限范围<br/>- 添加时间戳 AuthServer->>TokenStore: 11. 存储Code元数据 Note right of TokenStore: - code值<br/>- 用户信息<br/>- 客户端信息<br/>- 过期时间 AuthServer->>Browser: 12. 重定向回客户端(带code+state) Note over Client, TokenStore: State 校验与 Code 验证阶段 Browser->>Client: 13. 请求回调URL Client->>Client: 14. 提取并验证State Note right of Client: - Base64解码<br/>- 验证签名<br/>- 检查时效性<br/>- 会话匹配 Client->>Client: 15. 清理已用State Client->>AuthServer: 16. 用Code交换Token AuthServer->>TokenStore: 17. 验证Code有效性 TokenStore->>AuthServer: 18. 返回Code关联信息 AuthServer->>AuthServer: 19. Code使用标记 AuthServer->>Client: 20. 返回访问令牌 TokenStore->>TokenStore: 21. 清理已用Code Client->>User: 22. 完成授权流程


为什么用code不直接返回token?

授权码(code)的安全作用介绍:

授权码(code)是OAuth2授权码流程中的核心凭证,它通过前端信道传递(浏览器重定向),然后由客户端应用在后端信道中与授权服务器交换访问令牌。授权码的安全作用主要包括:

  • 避免访问令牌通过前端信道传输,降低令牌泄露风险。
  • 授权码是短暂的,一次性使用的,降低被窃取后的风险。
  • 授权码与客户端身份绑定,防止被其他客户端使用。

假设code被截取:

  • 即使授权码被窃取,攻击窗口很短
  • 自动清理过期的授权码,减少存储负担

所以code也不能保证绝对安全,但是相对安全,在防CSRF类攻击时,它是有效的。

相关推荐
曲幽1 天前
FastAPI + SQLite:从基础CRUD到安全并发的实战指南
python·sqlite·fastapi·web·jwt·form·sqlalchemy·oauth2
Tancenter2 天前
OAuth2协议
oauth2·授权行式
IT 行者17 天前
Spring Security 6.x 迁移到 7.0 的完整步骤
java·spring·oauth2
IT界的奇葩22 天前
OAuth2 单点登录流程图
java·流程图·oauth2·单点登录·sso
泽济天下1 个月前
【经验分享】基于Spring Boot 4.0快速实现最简版的OAuth2 Server和Client
spring boot·springboot·oauth2
佛祖让我来巡山1 个月前
小明网站双登录系统实现——微信授权登录+用户名密码登录完整指南
oauth2·springsecurity·微信授权登录
佛祖让我来巡山1 个月前
小明网站微信登录改造记——OAuth2完整指南(含续期逻辑)
oauth2·微信授权登录
不会吃萝卜的兔子2 个月前
spring - 微服务授权 2 实战
spring·oauth2·authorization
陈果然DeepVersion2 个月前
Java大厂面试真题:从Spring Boot到AI微服务的三轮技术拷问(一)
java·spring boot·redis·微服务·kafka·面试题·oauth2
asom222 个月前
互联网大厂Java求职面试实战:Spring Boot到Kubernetes的技术问答
java·spring boot·kubernetes·oauth2·电商·microservices·面试技巧