【系列集合篇】浅谈OAuth二三事

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

OAuth系列一】OAuth协议简介

背景

    在传统模式下,用户的客户端在访问某个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 serverauthorization server之间的交互,它们可能承载在同一个web服务中,也可能由不同的独立web服务承载。当resource serverauthorization server各自独立时,正是因为OAuth协议没有定义其交互过程,导致OAuth协议在产品标准化和工程化中出现困难,后面会慢慢介绍。

 

【OAuth系列二】授权流程

在上一篇中介绍了协议的基本流程:获取授权->获取token->访问资源。本文主要探讨获取授权和获取token的几种模式,应用场景,交互过程以及API的定义。

分类

 Grant Type

 应用场景

 Authorization Code Grant

 适用于具有web server的应用,web server能够安全的保存应用的凭证,并通过user-agent的重定向能力完成授权过程。

 Implicit Grant

 适用于client-side的应用,此类应用的代码暴露运行在不安全的环境,不应该保存应用的凭证。例如运行在浏览器里的JavaScript应用,常见的SPA(单页面应用 )。此类应用也是通过user-agent的重定向能力完成授权过程。

 Resource Owner Password Credentials Grant

 适用于高度可信的环境,例如操作系统或高权限应用,resource owner向此类应用直接传递账号口令,一般仅用于兼容存量的业务系统。

 Client Credential Grant

 适用于访问与resource owner无关的资源,例如应用自身的图标,配置等。

 Extension Grant

 自定义类型,由厂商的Authorization Server自定义,下游应用来配套,例如Google面向电视和设备应用提供的urn:ietf:params:oauth:grant-type:device_code

 

准备工作

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

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

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

 client type

 说明

 web application

 运行在服务端的可信的web应用,用户通过浏览器访问web应用。authorization server给应用颁发的client密钥和access token都存放在服务端,不会暴露给最终用户。

 user-agent-based application

 代码运行在客户端的应用程序,例如浏览器上的单页面应用。此类应用运行在非信任域,不能保存敏感的client密钥。此类应用的优势是可以充分利用客户端的能力和authorization server交互达到无缝的访问体验。

 native application

 运行在用户设备上的应用程序,例如手机APP,此类应用运行在非信任域,不能保存长期凭证,但可以使用临时凭证。

 

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

 

授权码流程

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


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

 

错误返回

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

 

参数

 参数名

 可选/必选

 说明

error

必选 

错误标记,用于程序处理:
1. invalid_request
:无效参数
2. unauthorized_client
client不允许以此方法请求授权
3. access_denied
resource owner拒绝授权
4. unsupported_response_type
:不支持的response_type
5. invalid_scope
:无效的授权范围
6. server_error
authorization server500错误
7. temporarily_unavailable
authorization server503错误

error_description

 可选

 错误描述,可读

error_uri

 可选

 错误信息页面,可读

state

 必选

 如果授权请求携带state,则必选,且原文返回

说明,所有参数需经过“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_idclient_secret直接从authorization server获取access token,这种流程仅用于访问应用本身的与resource owner无关的数据,不需要resource owner授权的场景,可以使用这种授权,一般都是机机接口调用。


扩展应用

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

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

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

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

 redirect_uri类型

 格式

 示例

 说明

 Custom URI scheme

 com.example.app:redirect_uri_path

 com.googleusercontent.apps.123:/oauth2redirect

 APPscheme

 Loopback IP address

 http://127.0.0.1:port or http://[::1]:port

 

 APP监听的本地web server



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

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

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


 

    Step1: 获取device_code

-

Java 代码

1

POST /device/code

2

Content-Type: application/x-www-form-urlencoded

 

3

 

4

client_id=client_id&response_type=device_code&scope=email%20profile

    Step2: 处理authorization响应

-

Java 代码

1

{

2

    "device_code": "4/4-GMMhhdfkdkfgdgegkfkfkeegjgjgj",

 

3

    "user_code": "GQVQ-JKEC",

4

    "verification_url": "https://www.google.com/device",

 

5

    "qrcode_url": "http://www.google.com/device/qrcode\ddggheghehhhdddddddddddddddhgerhh",   //二维码

6

    "expires_in": 1800    // code有效期

 

7

    "interval": 5   // poll的间隔

     Step3: 显示user_code

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

 

    Step4: poll用户授权结果

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

-

Javascript 代码

1

POST /token

2

Content-Type: application/x-www-form-urlencoded

 

3

 

4

client_id={client_id}&

 

5

client_secret={client_secret}&

6

code={device_code}&

 

7

grant_type=device_code

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

    Step6: 处理poll 响应

-

Javascript 代码

1

{

2

    "access_token": "1/ffffdgdg",  

 

3

    "expires_in": 3920,

4

    "scope": "openid profile email",

 

5

    "token_type": "Bearer",

6

    "refresh_token": "dgegegegedgegeg"

 

7

}

 

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 参数

参数名

 可选/必选

说明 

 response_type

 必选

必须传参为"code"

 client_id

必选 

 开放认证平台为应用分配的唯一标识。

 redirect_uri

 可选

 应用接收认证服务端返回code的回跳地址,必须为绝对路径,且不能包含fragment,即不能有#

 scope

 可选

 请求的授权范围,由authorization server定义,例如id, profile, email等。多值通过空格分割,例如id%20profile。大小写敏感。如果不传,authorization server需提供默认值。

 state

 可选

 推荐,防止CSFR攻击,stateauthorization server透明,必须原文返回,应用通过对比state防止CSRF

 

1.2 示例

GET /oauth2/authorize?response_type=code&

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

 

1.3 扩展

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

 参数名

 可选/必选

 说明

 access_type

 可选

 推荐,取值"online""offline",标识应用是否需要用户不在线的情况下刷新access token,如果是"offline",通过code换回token时将返回refresh_token参数,用于在用户不在线且access token过期时轮换新的access token

 login_hint

 可选 

 可以传user-id快速填充登录页面,也可用于多会话情况下选择合适的会话。

 prompt

 可选

 consent: 提示用户进行授权
 select_account:
提示用户选择一个账号授权
 none:
不提示

 

1.4 响应

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

 参数名

 可选/必选

说明 

 code

 必选

 authorization server生成,有效期非常短且一次性使用,建议有效期不超过10分钟。code内容对于应用是透明的,且不能假设code的长度。

 state

 可选

 如果request携带state参数,则必须原文返回。

 

2. 隐式授权请求API

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

2.1 参数

 

 参数名

 可选/必选

 说明

 response_type

 必选 

 必须传参为"token"

 client_id

 必选

 开放认证平台为应用分配的唯一标识。

 redirect_uri

 可选

 应用接收认证服务端返回access_token的回跳地址,必须为绝对路径,且不能出现fragment,即不能包含#

 scope

 可选

 请求用户的授权内容。

 state

 推荐

 CSRF攻击。

 

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参数。

 参数名

 可选/必选

 说明

 access_token

 必选 

 认证服务器颁发的token

 

 

 

 

 

 

 

 

 

 

 

 

 

 

【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 参数

 参数名  可选/必选 说明 
 response_type  必选 必须传参为"code" 。
 client_id 必选   开放认证平台为应用分配的唯一标识。
 redirect_uri  可选  应用接收认证服务端返回code的回跳地址,必须为绝对路径,且不能包含fragment,即不能有#。
 scope  可选  请求的授权范围,由authorization server定义,例如id, profile, email等。多值通过空格分割,例如id%20profile。大小写敏感。如果不传,authorization server需提供默认值。
 state  可选  推荐,防止CSFR攻击,state对authorization server透明,必须原文返回,应用通过对比state防止CSRF。

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接口定义,选取几个实践中比较有意义的扩展参数:
 参数名  可选/必选  说明
 access_type  可选  推荐,取值"online"或"offline",标识应用是否需要用户不在线的情况下刷新access token,如果是"offline",通过code换回token时将返回refresh_token参数,用于在用户不在线且access token过期时轮换新的access token。
 login_hint  可选   可以传user-id快速填充登录页面,也可用于多会话情况下选择合适的会话。
 prompt  可选  consent: 提示用户进行授权
 select_account: 提示用户选择一个账号授权
 none: 不提示

1.4 响应

    authorization server完成用户身份认证并得到用户授权后,将code作为参数重定向给redirect_uri。
 参数名  可选/必选 说明 
 code  必选  authorization server生成,有效期非常短且一次性使用,建议有效期不超过10分钟。code内容对于应用是透明的,且不能假设code的长度。
 state  可选  如果request携带state参数,则必须原文返回。

2. 隐式授权请求API

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

2.1 参数

 
 参数名  可选/必选  说明
 response_type  必选   必须传参为"token"。
 client_id  必选  开放认证平台为应用分配的唯一标识。
 redirect_uri  可选  应用接收认证服务端返回access_token的回跳地址,必须为绝对路径,且不能出现fragment,即不能包含#。
 scope  可选  请求用户的授权内容。
 state  推荐  防CSRF攻击。


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参数。
 参数名  可选/必选  说明
 access_token  必选   认证服务器颁发的token
     
     
     
     
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。