3. 简化模式与密码模式
本章深入分析 OAuth2.0 中两种经典但风险特征截然不同的授权模式:简化模式(Implicit Grant)与密码模式(Password Credentials Grant)。理解它们的流程差异、安全缺陷与适用场景,是构建安全 OAuth 集成的关键基础。
3.1 简化模式(Implicit Grant)
简化模式专为纯前端应用(如浏览器单页应用 SPA、移动端 WebView)设计,其核心特征是不经过授权码交换步骤,授权服务器直接通过 URL 片段(Fragment)向前端返回 Access Token。
3.1.1 核心流程
- 用户代理发起授权请求:前端应用将用户重定向至授权服务器的
/authorize端点,请求参数包含response_type=token。 - 用户认证与授权:用户在授权服务器上登录并确认授权范围。
- 返回 Token(URL 片段):授权服务器将 Access Token 附加在重定向 URL 的
#片段中,直接返回给用户代理。 - 前端提取 Token:用户代理(浏览器)解析 URL 片段,提取 Access Token,并可通过 JavaScript 传递给应用。
- 访问资源:前端应用使用该 Token 直接请求受保护的资源服务器。
关键特征:整个流程中,没有后端服务器参与 Token 的接收与存储,所有敏感信息均暴露在浏览器端。
3.1.2 主要风险
| 风险类别 | 描述 | 影响等级 |
|---|---|---|
| Token 泄露 | Access Token 出现在浏览器 URL 历史、书签、Referer 头中,易被窃取。 | 高 |
| 中间人攻击 | 若未强制 HTTPS,Token 在传输过程中可被截获。 | 高 |
| 无法使用 Refresh Token | 由于没有后端安全存储,Refresh Token 无法安全下发,导致 Token 续期困难。 | 中 |
| 浏览器扩展/恶意脚本 | 浏览器环境中的恶意代码可直接读取 URL 片段中的 Token。 | 高 |
行业趋势:OAuth 2.0 Security BCP(Best Current Practice)已不推荐使用简化模式。对于 SPA 应用,建议改用授权码模式 + PKCE 作为替代方案。
3.2 密码模式(Password Credentials Grant)
密码模式允许用户直接将其用户名和密码交给客户端应用,由客户端代表用户向授权服务器换取 Access Token。这种模式对用户凭证的信任要求极高。
3.2.1 核心流程
- 用户提供凭证:用户在客户端应用(如移动 App、第一方后端服务)中输入用户名和密码。
- 客户端发送凭证:客户端将用户凭证与自身
client_id、client_secret一起,直接发送至授权服务器的/token端点,请求参数包含grant_type=password。 - 授权服务器验证:授权服务器验证客户端身份和用户凭证的有效性。
- 返回 Token:验证通过后,授权服务器返回 Access Token(可选 Refresh Token)给客户端。
- 访问资源:客户端使用 Access Token 请求资源服务器。
适用前提:密码模式要求客户端应用是高度可信的(通常是第一方应用),且授权服务器与客户端属于同一安全域或具有强信任关系。
3.2.2 适用场景与限制
| 场景 | 说明 | 推荐度 |
|---|---|---|
| 第一方原生应用 | 如官方 iOS/Android App,用户信任度高,且应用与授权服务器同属一个组织。 | 中(需配合额外安全措施) |
| 遗留系统迁移 | 旧系统使用 HTTP Basic Auth 或表单登录,逐步向 OAuth2.0 过渡时的临时方案。 | 低(仅限过渡期) |
| 高度信任的内部服务 | 企业内部工具或管理后台,用户与客户端之间具有强信任关系。 | 中 |
| 第三方应用 | 任何非第一方应用使用密码模式。 | 禁止 |
3.3 两种模式对比总结
| 维度 | 简化模式(Implicit) | 密码模式(Password) |
|---|---|---|
| Token 获取方式 | 通过 URL 片段直接返回给前端 | 通过后端 API 返回给客户端 |
| 是否需要客户端密钥 | 否 | 是(client_secret) |
| 用户凭证暴露面 | 仅授权服务器处理密码 | 客户端应用直接接触明文密码 |
| Refresh Token 支持 | 不支持 | 支持(但需安全存储) |
| 主要风险 | Token 泄露、中间人攻击 | 凭证泄露、客户端被攻破 |
| 当前推荐度 | 不推荐(已被 PKCE 取代) | 仅限高度信任的第一方场景 |
架构决策建议:在 Go 项目实践中,应优先选择授权码模式 + PKCE 作为默认方案。若必须使用密码模式,务必确保客户端与授权服务器之间的通信使用 mTLS 或至少 TLS 1.3,并在客户端侧对用户凭证进行零持久化处理——即使用完毕后立即从内存中清除,不写入日志、数据库或缓存。