写点什么

OAuth:每次授权暗中保护你的那个“MAN”

发布于: 2021 年 02 月 18 日

摘要:OAuth 是一种授权协议,允许用户在不将账号口令泄露给第三方应用的前提下,使第三方应用可以获得用户在某个 web 服务上存放资源的访问权限。


背景


在传统模式下,用户的客户端在访问某个 web 服务提供的具有一定访问限制的资源时,需要提供用于进行身份认证的凭证(credential),例如密码,accesskey 等。如果存在第三方的应用需要该 web 服务上用户的资源,用户必须将自己的凭证共享给第三方应用,这种实践带来了一些问题:


  1. 第三方应用需要存放用户的凭证,且必须拿到明文(例如使用用户名和密码远程调用 web 服务的 API),如果第三方应用被攻击,用户的凭证可能被泄露。

  2. 无法限制第三方应用的权限。第三方应用拿到用户凭证明文后,等于拿到了用户的所有权限,且用户无法对第三方应用在什么时间访问哪些资源进行限制,可能被越权。

  3. 用户无法回收对某个第三方应用的授权,除非更改密码。更改密码可能导致依赖该密码的其他第三方应用无法访问。

  4. 用户资源的安全性取决于安全性最弱的第三方应用(木桶理论),任何一个第三方应用被攻击,都可能导致用户的身份凭证泄露,以及存放在 web 服务上的资源被攻击。


基本原理


OAuth 是一种授权协议,允许用户在不将账号口令泄露给第三方应用的前提下,使第三方应用可以获得用户在某个 web 服务上存放资源的访问权限。


例如下图,通过华为账号登录腾讯新闻应用时,并不需要将账号口令提供给腾讯新闻应用,用户只要拥有华为账号,只需要轻轻点击一下授权就可以无缝访问,在保证安全和隐私的同时带来体验上质的飞跃,体验提升的持续追求使得 OAuth 协议在互联网得到了非常广泛的应用。



OAuth 通过引入 authorization server 的概念,并对授权访问过程中的几个参与方进行重新定义和角色解耦。



上面是一个非常非常抽象的流程图,仅仅为了厘清 OAuth 交互过程中存在哪些角色及承担的职责,实际上具体应用过程中的差异非常大。从上图大概可以看出,OAuth 协议交互过程中存在四种角色:


  • resource owner


需要访问资源的主体,可以是人,也可以是物,指代人的时候就是我们通常说的 end-user。


  • resource server


存放受保护资源的 web 服务,接收资源的访问请求并响应,resource server 对请求进行鉴权。例如用户存放照片的华为终端云服务。


  • client


用来代理 resource owner 请求资源的应用程序,client 访问资源需要得到 resource owner 的授权。例如照片美图 APP,需要拉取用户存放在云服务上的照片。


  • authorization server


对 resource owner 进行身份认证和鉴权,并颁发访问凭证。例如华为账号认证服务。


其他说明


  1. OAuth 协议当前已经发展到 0 版本。1.0 版本已经废弃,且 OAuth2.0 并不能后向兼容 1.0。

  2. OAuth 协议常用于 web 访问,基于 HTTP 协议。实际上,OAuth 只是定义了一种流程,以及该流程中各方的角色定义和功能职责,并不限于 HTTP 这一种传输通道。

  3. 上面的流程图中并没有介绍 resource server 和 authorization server 之间的交互,它们可能承载在同一个 web 服务中,也可能由不同的独立 web 服务承载。当 resource server 和 authorization server 各自独立时,正是因为 OAuth 协议没有定义其交互过程,导致 OAuth 协议在产品标准化和工程化中出现困难,后面会慢慢介绍。


OAuth:授权流程


接下来我们探讨一下,获取授权和获取 token 的几种模式,应用场景,交互过程以及 API 的定义。


分类



准备工作


在开始 OAuth2.0 的授权流程前,应用的开发者需要将应用的信息注册到 authorization server,例如华为账号服务、百度开发者中心这些知名的开放平台,注册成功后得到最重要的两个参数:client_id 和 client_secret,这两个参数在后面介绍的几乎每种授权流程都会频繁使用。


如下图华为终端开发者联盟管理中心注册界面:



开发者进行应用注册时,一般需要提交应用类型。应用类型常见的几大类:



对于 web application,开发者还需要提交 redirect URI,即 web application 接收 grant code 的地址,authorization server 在认证完成后重定向到此地址。


授权码流程


授权码流程是 oauth2.0 最常见的交互流程,甚至很多开放平台仅支持这一种流程。授权码流程示意见下图:



该流程主要适用于 web 应用,基于浏览器的重定向能力实现整个交互过程。


错误返回


当 resource-owner 拒绝 client 的访问请求,或者授权请求错误,authorization server 将错误信息通过 redirect_uri 返回给 client 应用,除非 redirect_uri 本身就不正确。


参数



说明,所有参数需经过“application/x-www-form-urlencoded”编码。


隐式授权(Implicit Grant)


如上面介绍,隐式授权适用于代码运行在客户端上的应用,例如网页应用,利用浏览器的重定向能力得到 resource-owner 的授权。不同于授权码流程,隐式授权流程的授权请求可以直接得到 access token,没有 authorization code 的中间过程。隐式授权过程发生在 resource owner 的设备上,必须有 resource owner 在场,且 client 代码不能包含 client 的凭证(client_secret),另外 access_token 返回给 client 时,存在暴露到同一个设备(user-agent)上其他应用的风险。


身份信息透传授权(Resource Owner Password Credentials Grant)


如果 resource owner 非常信任这个应用,可以将身份凭证(口令,密钥等)通过应用传递到 authorization server。一般不推荐这种方式,应用可以截留用户的身份凭证明文,风险较高,RFC 协议也仅建议用于存量的应用迁移到 OAuth 协议。个人认为,如果 client 本身就是 authorization server,其身份验证过程这样做也是可行的,相当于 authorization server 的内部实现。



客户端凭证直接授权(Client Credentials Grant)


应用拿着 client_id 和 client_secret 直接从 authorization server 获取 access token,这种流程仅用于访问应用本身的与 resource owner 无关的数据,不需要 resource owner 授权的场景,可以使用这种授权,一般都是机机接口调用。


扩展应用


不同厂商的开放平台可以扩展授权流程,以满足不能场景的需求,例如手机、平板等端侧设备应用,或者电视、游戏手柄等娱乐设备应用。


移动端和 PC 桌面的应用授权


对于运行在手机、平台和 PC 上的应用程序,也可以通过 OAuth 协议得到用户的授权来安全的访问用户的数据。这种场景的授权流程和 web server 应用非常类似,也是 authorization grant 模式,主要区别是此类应用需要提供本地 web server 或者支持应用间跳转,并提供系统内置的“browser”(例如 android 的 intent)实现与 authorization server 之间的交互。


这种授权方式的交互过程和接口和上文介绍得 authorization grant 模式一样,唯独授权请求的 redirect_uri 参数有差异:



电视或输入受限设备的应用授权


当我们在使用智能电视、游戏手柄或者带液晶屏的打印机需要访问用户的数据,例如放在网盘上的照片、文档等,需要得到用户的授权,而这类设备的输入能力有限,没有浏览器进行重定向,也不方便输入账号口令等认证凭证。


此类场景的应用授权大致步骤如下:



Step1: 获取 device_code


-


Java 代码


1POST /device/code2Content-Type: application/x-www-form-urlencoded34client_id=client_id&response_type=device_code&scope=email%20profile 
复制代码


Step2: 处理 authorization 响应


-


Java 代码


{    "device_code": "4/4-GMMhhdfkdkfgdgegkfkfkeegjgjgj",    "user_code": "GQVQ-JKEC",    "verification_url": "https://www.google.com/device","qrcode_url": "http://www.google.com/device/qrcode\ddggheghehhhdddddddddddddddhgerhh",   //二维码    "expires_in": 1800    // code有效期    "interval": 5   // poll的间隔
复制代码


Step3: 显示 user_code


可以屏幕显示 verification_url 和 user_code,甚至如果支持的话可以显示二维码。


Step4:poll 用户授权结果


APP 根据第 2 步授权响应的 interval 间隔,向 authorization server 拉取用户的授权结果。


-


Javascript 代码


POST /tokenContent-Type: application/x-www-form-urlencoded client_id={client_id}&client_secret={client_secret}&code={device_code}&grant_type=device_code
复制代码


Step5: 用户打开浏览器输入 verification_url 和 user_code,或者通过手机扫码完成登录和授权。


Step6: 处理 poll 响应


Javascript 代码


{    "access_token": "1/ffffdgdg",      "expires_in": 3920,    "scope": "openid profile email",    "token_type": "Bearer",    "refresh_token": "dgegegegedgegeg"
}
复制代码


OAuth:API 定义和扩展


在上一篇中介绍了不同场景下的应用获得租户授权的交互流程。本文主要介绍 OAuth2.0 协议的授权和 token API 定义及常见的扩展方案。OAuth2.0 的所有参数都通过"urlencoded"编码,在请求头部需要增加“application/x-www-form-urlencoded”。


1. code 授权请求 API


适用于 authorization code grant 模式,应用通过浏览器将授权请求重定向给 authorization server,除了通过重定向外,我认为也可以通过 FORM 表单提交。


1.1 参数



1.2 示例


GET /oauth2/authorize?response_type=code&


client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb


1.3 扩展


看了 Google 的 OAuth2.0 接口定义,选取几个实践中比较有意义的扩展参数:



1.4 响应


authorization server 完成用户身份认证并得到用户授权后,将 code 作为参数重定向给 redirect_uri。



2. 隐式授权请求 API


适用于 implicit grant 模式,浏览器 JS 直接向 authorization server 发送授权请求。


2.1 参数



2.2 示例


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


2.3 响应


认证服务器在完成用户身份认证并得到用户的授权后,将回跳到 redirect_uri,并携带 access_token 参数。



API 定义和扩展


OAuth2.0 的所有参数都通过"urlencoded"编码,在请求头部需要增加“application/x-www-form-urlencoded”。


1. code 授权请求 API


适用于 authorization code grant 模式,应用通过浏览器将授权请求重定向给 authorization server,除了通过重定向外,我认为也可以通过 FORM 表单提交。


1.1 参数



1.2 示例


GET /oauth2/authorize?response_type=code&


client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb


1.3 扩展


看了 Google 的 OAuth2.0 接口定义,选取几个实践中比较有意义的扩展参数:



1.4 响应


authorization server 完成用户身份认证并得到用户授权后,将 code 作为参数重定向给 redirect_uri。



2. 隐式授权请求 API


适用于 implicit grant 模式,浏览器 JS 直接向 authorization server 发送授权请求。


2.1 参数



2.2 示例


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


2.3 响应


认证服务器在完成用户身份认证并得到用户的授权后,将回跳到 redirect_uri,并携带 access_token 参数。



本文分享自华为云社区《【系列集合篇】浅谈 OAuth 二三事》,原文作者:APTX-486977。


点击关注,第一时间了解华为云新鲜技术~


发布于: 2021 年 02 月 18 日阅读数: 123
用户头像

提供全面深入的云计算技术干货 2020.07.14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
OAuth:每次授权暗中保护你的那个“MAN”