理解 OAuth2.0

文章转载于阮一峰老师的博客:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.htmlphp

参考文章:https://learnku.com/articles/20082html

 1、应用场景json

       为了理解 OAuth 的适用场景,阮老师在这里举了一个例子说明,以下:api

       有一个 "云冲印" 的网站,能够将用户存储在 Google 的照片,冲印出来。这里须要说明一下"云冲印"相对于 Google 是一个第三方。浏览器

那么若是要想让"云冲印"可以打印用户存储在 Google 上的照片,就必需要能让"云冲印"能读取用户存储在 Google 上的照片。安全

       问题来了,Google 确定不会让一个未经用户受权的第三方去读取用户存储在 Google 上的照片,那么"云冲印"怎么获取用户的受权?服务器

       传统的方法就是用户将本身 Google 的账号密码告诉"云冲印",后者就能够拿着账号密码登陆 Google 去读取用户的照片了,可是这时cookie

你们确定会想到这很不安全,都有哪些风险呢?session

       1 若是"云冲印"保存了用户的账号密码,那这样很不安全app

       2 "云冲印"有了用户的账号密码后,就拥有了和用户同样的权限能够读取用户全部的资料,用户没办法限制"云冲印"得到受权的范围和

有效期

       3 用户只有修改密码,才能收回"云冲印"的权限,可是这样作,会使得其余全部得到用户受权的第三方应用程序失效

       4 若是其中一个第三方应用程序被破解,那么用户的账号密码泄露

       OAuth 就是为了解决上面的问题诞生的

2、名词定义

       1 Third-party application:第三方应用程序,本文中又称"客户端(client)",即上面例子中的"云冲印"

       2 HTTP service:HTTP 服务提供商,本文中简称"服务提供商",即上面例子中的"Google"

       3 Resource Owner:资源拥有者,本文中指的是"用户"

       4 User Agent:用户代理,本文中就是浏览器

       5 Authorization server: 认证服务器,服务提供商专门用来解决认证处理的服务器

       6 Resource server:资源服务器,服务提供商存放用户所拥有资源的服务器,它与认证服务器能够是一台服务器也能够不是一台服务器

      了解了上面这些名词,能够知道,OAuth 其实就是"客户端"安全可控的获取"用户受权",与"服务提供商"交互 

3、OAuth 的思路

       OAuth 在客户端和服务提供商之间,设置了一个"受权层",客户端不能直接登陆服务提供商,只能登陆受权层,以此将用户和客户端区分

开来,客户端登陆受权层所用的令牌(token),与用户的密码不一样。用户在登陆的时候能够指定受权层令牌的权限范围和有效期

       客户端登陆受权层以后,服务提供商根据令牌的权限范围和有效期,向客户端开放用户存储的资料

4、运行流程

       OAuth2.0 的运行流程以下图:

    A: 用户打开客户端之后,客户端须要用户给与权限

    B:用户赞成给与客户端受权

    C:客户端使用上一步得到的受权,向认证服务器申请令牌

    D:认证服务器对客户端进行认证之后,确认无误,赞成发放令牌

    E:客户端使用令牌,向资源服务器申请得到资源

    F:资源服务器确认令牌无误后,赞成向客户端开放资源

    上面六步中,B 是关键的一步,用户怎么才能客户端受权,客户端被受权后访问认证服务器申请令牌,而后凭借有效的令牌访问资源服务器,

下面看一下客户端获取受权的四种模式

5、客户端的受权模式

      客户端必须得到用户受权以后,才能拿到令牌(access token),OAuth2.0 提供了四种受权方式,阮一峰老师的博客里面详解每一种,在这里我

只介绍下经常使用的两种模式

      受权码模式(authorization code)

      简化模式(implicit)

6、受权码模式

      受权码模式是目前功能最完善,流程最严密的受权模式,它的特色就是经过客户端的后台服务器和服务提供商的认证服务器进行互动,以下图:

       A:用户访问客户端,客户端将用户导向认证服务器

       B:此时会弹出相关页面让用户选择是否赞成受权给客户端

       C:假设用户赞成给与受权,认证服务器将用户导向事先指定好的"重定向URI",同时附上一个受权码(authorization code)

       D:客户端收到受权码以后,附上以前的重定向URI,向认证服务器申请令牌(access token),这一步是在客户端的服务器上完成的

       E:认证服务器核对了受权码和重定向URI,确认无误后,向客户端发送令牌(access token)和刷新令牌(refresh token)

       下面是上面这些步骤所须要的参数

       A 步骤中,客户端申请认证的URI:

       response_type:表示受权类型,必选项,此处为固定值 "code"

       client_id:表示客户端的ID,必选项

       redirect_uri:表示重定向 URI,可选项

       scope:表示申请的权限范围,可选项

       state:表示客户端当前状态,能够试任意值,认证服务器会原封不动的返回这个值

       以下示例:

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

  C 步骤中,认证服务器返回给客户端的参数:

       code:受权码,受权码的有效期比较短,而且只能使用一次

       state:若是客户端中的请求中包含这个参数,则认证服务器必须原封不动的回应这样一个参数

       以下示例:

HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
          &state=xyz

  D 步骤中,客户端向认证服务器申请令牌的HTTP请求的参数:

       grant_type:表示使用的受权模式,此处为固定值:authorization code

       code:表示上一步获取的受权码,必填

       redirect_uri:表示重定向URI,若是受权请求中包含 redirect_uri 则返回时必填

       client_id:客户端 ID

       以下示例:

POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

  E 步骤认证服务器向客户端发送的请求回复参数:

       access_token:表示令牌

       token_type:表示令牌类型,该值大小写不敏感,必选项,能够是bearer类型或mac类型

       expires_in:表示过时时间,单位为秒

       refresh_token:表示更新令牌,用来获取下一次令牌

       scope:表示权限范围,若是与客户端申请的范围一致,能够省略

       以下示例:

HTTP/1.1 200 OK
     Content-Type: application/json;charset=UTF-8
     Cache-Control: no-store
     Pragma: no-cache

     {
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "token_type":"example",
       "expires_in":3600,
       "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
       "example_parameter":"example_value"
     }

 

7、简化模式

       简化模式(简化获取受权码流程)不经过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过"受权码"这个流程,

全部步骤都是在浏览器中完成的,以下图所示:

      步骤以下:

      A:用户访问客户端,客户端将用户导向认证服务器

      B:用户决定是否给与客户端受权

      C:假设用户赞成受权,认证服务器将用户导向客户端指定的"重定向URI",并在 URI的 HASH 部分包含了访问令牌

      D:浏览器向资源服务器发出请求,其中不包括上一步收到的 HASH 值

      E:资源服务器返回一个网页,其中包含的代码能够获取 HASH 值中的令牌

      F:浏览器执行上一步获取得脚本,提取出令牌

      G:浏览器将令牌发给客户端

      下面是上面步骤中所须要的参数:

      A 步骤客户端发出的 HTTP 请求参数:

      response_type:表示受权类型,此处的值为固定值"token"

      client_id:表示客户端的 ID

      redirect_uri:表示重定向 URI

      scope:表示受权范围

      state:表示客户端状态,能够指定任意值,认证服务器会原封不动的返回这个值

      以下示例:

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

  C步骤中,认证服务器回应客户端的URI:

       access_token:表示访问令牌

       token_type:表示令牌类型

       expires_in:表示过时时间

       scope:表示权限范围

       state:若是客户端的请求中包含这个参数,则认证服务器的回应中也须要包含一个如出一辙的参数

       以下示例:

 HTTP/1.1 302 Found
     Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA
               &state=xyz&token_type=example&expires_in=3600

  在上面的例子中,认证服务器用 HTTP 头信息的 Location 栏,指定浏览器重定向的网址,注意,这个网址的 HASH 部分包含了令牌,

根据上面的步骤,下一步浏览器会访问Location指定的网址,可是 HASH 部分不会被发送,而后资源服务器发送过来的代码,会提取出HASH

中的令牌

 

-----------------------------------------2019/03/29----------------------------------------------

关于 OAuth2.0 中的 state 参数 

          在看完阮一峰老师的文章关于使用受权码模式实现受权登陆后关于 state 这个参数就有一点疑问,其中阮一峰老师在文章中讲到,若是客

户端的传递参数中包含 state 这个参数,则服务端必需要原封不动传递回来,阮老师也没有具体说到这个参数的真正做用,后来看了相关文章后,

这个参数能够说是必传的参数,若是少了这个参数可能会形成 CSRF 攻击

           咱们经过一个常见场景说一下,参考文章:https://blog.csdn.net/gjb724332682/article/details/54428808

           1. 用户 A 登陆一个第三方站点,如今用户想要把这个第三方站点的账号和本身的微博账号进行绑定,此时用户到了绑定页面,可是尚未

绑定,在绑定页面提功力一个绑定按钮:"绑定微博" (地址a:http://aaa.com/index.php?m=user_3rd_bind_sina)

            2.用户点击绑定按钮,第三方站点会将用户导向微博的认证服务器(该过程用户无感知),而后认证服务器会弹出一个页面询问用户是否赞成

受权,用户赞成受权以后认证服务器会将用户导向第三方站点请求参数里面的回跳地址,并返回受权码

            该过程当中涉及到的一些请求参数,第三方站点将用户导向认证服务器时的请求:https://api.weibo.com/oauth2/authorize?client_id=&redirect

_url=【http://aaa.com/index.php?m=user_3rd_bind_sina】&response_type=code

           认证服务器返回给第三方站点的地址:http://aaa.com/index.php?m=user_3rd_bind_sina&code=【受权码】

           从上面认证服务返回给第三方站点的地址来看实际上是和当前登陆用户一点关系都没有,这个地址只能证实微博用户信息,没有一个标识能证实

第三方站点的用户信息,这样就出现了漏洞。

           假设如今有甲和乙两个用户同时发起绑定请求,都在认证服务器返回受权码这一步停下,而后甲和乙互换地址,会出现什么样的结果?

           由于返回受权码的地址没有任何标识能有效证实第三方站点当前登陆用户信息,因此会出现甲绑定乙的微博账号,乙绑定甲的微博账号,而攻击

者的目标就是获取本身帐号的地址,而后诱骗已登陆第三方站点的用户点击,从而改变绑定关系,将用户的微博账号绑定到攻击者的账号

           为了应对这种状况,OAuth2.0加入了 state 这个参数,不少第三方开放平台都会有这个参数,好比新浪微博的(https://open.weibo.com/wiki/Oauth

2/authorize),咱们可使用这个参数去验证请求的有效性,第三方向认证服务器发送请求时带上这个参数,认证服务器在返回的时候也须要带上这个参数,

每一个用户的state参数都是惟一的,若是检验传递过去的和返回的不同则认为是不合法的,这样就能够有效的避免CSRF(跨站请求伪造)攻击

           关于如何生成state参数,不一样的开发者有本身的实现方式,通常状况下都是一个随机字符串将其保存在cookie或session中,回调时检查cookie或ses

sion中该参数的有效性便可

相关文章
相关标签/搜索