白话OAuth2.0
2023-1-27 00:2:29 Author: 白帽子(查看原文) 阅读量:22 收藏

1、什么是OAuth?

关于OAuth,官方是这样讲的:

An open protocol to allow secure authorization in a simple and standard method from web, mobile and desktop applications.

OAuth 即 Open standard for Authorization

OAuth就是一个网络开放协议。为保证用户资源的安全授权提供了简易的标准

2、OAuth 1.0

OAuth 1.0协议由于过于复杂,适用性也特别的差,在此不做过多描述,下面贴张图自行了解。

关于OAuth 1.0, 想了解的可以看看这些:

http://www.rfcreader.com/#rfc5849

3、OAuth 2.0

OAuth 1.0已经被OAuth 2.0替代,且2.0不兼容1.0,本篇文章主要讲讲关于OAuth 2.0那点事儿。

先来说一个场景:有一天,小明想要去京东买电脑,但是打开京东商城,发现要登录京东商城。可小明之前一直用淘宝,没有京东商城的账号,注册一个新的吧,又嫌麻烦。小明发现,可以不用注册新的,用QQ就可以登录。于是乎,小明用QQ号登录京东商城,购买了一台Mac Pro回家水贴吧去了。

上处场景中,小明用QQ号登录京东商城购物的这个过程呢,就是一次 OAuth 认证流程。

3.1协议中的角色

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

(2)HTTP service:HTTP服务提供商,本文中简称"服务提供商",即上一节例子中的Google。

(3)Resource Owner:资源所有者,本文中又称"用户"(user)。

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

(5)Authorization server:认证服务器,即服务提供商专门用来处理认证的服务器。

(6)Resource server:资源服务器,即服务提供商存放用户生成的资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。

3.2协议流程

(A)用户打开客户端以后,客户端要求用户给予授权。(比如说你登陆京东,但是不想注册京东账户,于是京东说:没关系,有QQ号么,用QQ号登录就行。于是,京东就会把你引导到QQ的认证服务器上。)

(B)用户同意给予客户端授权。(这个时候你在手机上弹出是否授权,你点击“是”,这个时候会返回一个授权码给京东,为什么是返回给京东呢?因为第一步中发送的认证服务器中会带有一个重定向url,是京东自己的)

(C)客户端使用上一步获得的授权,向认证服务器申请令牌。(京东拿着这个授权码再去找认证服务器)

(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。(京东取得授权码确认无误后,发放accesstoken令牌)

(E)客户端使用令牌,向资源服务器申请获取资源。(京东拿着令牌就可以访问QQ资源服务器)

(F)资源服务器确认令牌无误,同意向客户端开放资源。(QQ资源服务器对比令牌无误后开放资源)

其实在上述过程中,不难看出,(B)在才是整个过程的关键所在,即用户该如何给予客户端授权,有了这个授权过后,客户端才能获取令牌,进而凭令牌获取到相应的资源。

3.3客户端的授权

客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。OAuth 2.0定义了四种授权方式。

  • 授权码模式(authorization code)

  • 简化模式(implicit)

  • 密码模式(resource owner password credentials)

  • 客户端模式(client credentials)

3.3.1授权码模式

授权码模式(authorization code)是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器,与"服务提供商"的认证服务器进行互动。

该模式过程如下:

(A)用户访问客户端,客户端将用户引导向认证服务器。(京东请求QQ)

客户端申请认证的URI,包含以下参数:

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

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

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

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

  • state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。

https://www.example.com/v1/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read&state=xxx

(B)用户选择是否给予客户端授权。

(C)如用户给予授权,认证服务器将用户引导向客户端指定的redirection uri,同时加上授权码code。(用户点击授权后,QQ引导用户访问A步骤中指定的重定向url,并带着授权码和state)

  • code:表示授权码,必选项。该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端ID和重定向URI,是一一对应关系。

  • state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。

https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xxx

(D)客户端收到code后,通过后台的服务器向认证服务器发送code和redirection uri。(京东带着接收到(C)步骤中的请求后,用授权码发送下面的请求去找QQ认证服务器要token)

  • grant_type:表示使用的授权模式,必选项,此处的值固定为"authorization_code"。

  • code:表示上一步获得的授权码,必选项。

  • redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。

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

https://www.example.com/v1/oauth/token?client_id=CLIENT_ID&grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=CALLBACK_URL

(E)认证服务器验证code和redirection uri,确认无误后,响应客户端访问令牌(access token)和刷新令牌(refresh token)。(响应(D)步骤的数据)

  • access_token:表示访问令牌,必选项。

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

  • expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。

  • refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。

  • scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。

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

从上面代码可以看到,相关参数使用JSON格式发送。此外,HTTP头信息中明确指定不得缓存。

使用场景

  • 授权码模式是最常见的一种授权模式,在oauth2.0内是最安全和最完善的。

  • 适用于所有有Server端的应用,如Web站点、有Server端的手机客户端。

  • 可以得到较长期限授权。

思考

授权码模式下的安全问题常出现在(A)步骤当中,京东会state并放在session中,然后再在(A)步骤中的请求中带上state,QQ返回url带有授权码和state的链接给淘宝,淘宝这个时候需要在后台对比这个state是否和session中的一样,用来防止csrf攻击,而开发者没有严格按照协议来,请求中没有带上state,就可能造成账户劫持的问题。那我们该如何测试?

1.确认A步骤中是否带有state,如果没有该参数就可能存在漏洞

2.准备AB两个账号,A是攻击者,B是受害者,两个都登陆的情况下,当然是不同浏览器(这里有个场景限制,就是绑定账户的地方才有,比如说我有个京东账户,但是要记住账号密码登陆很麻烦,我将他绑定到QQ,以后就可以直接用QQ登陆啦)

3.A点击绑定QQ,然后用打开burp抓包,点击授权,一步一步forward,知道遇到请求中带有授权码的请求,复制该请求后drop掉,因为code一般都是一次性的

4.拿去B账户的浏览器中打开(实际攻击中就是csrf),会发现B账户绑定了A账户的QQ,以后A就可以用自己的QQ登陆B的京东了。

3.3.2简化模式

简化模式(implicit grant type)不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了"授权码"这个步骤,因此得名。所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。

该模式过程如下:

(A)客户端将用户导向认证服务器。

A步骤中,客户端发出的HTTP请求,包含以下参数:

  • response_type:表示授权类型,此处的值固定为"token",必选项。

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

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

  • scope:表示权限范围,可选项。

  • state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。

https://www.QQ.com/authorize?response_type=token&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read&state=xxx

(B)用户决定是否给予客户端授权。

(C)假设用户给予授权,认证服务器将用户导向客户端指定的"重定向URI",并在URI的Hash部分包含了访问令牌。

C步骤中,认证服务器回应客户端的URI,包含以下参数:

  • access_token:表示访问令牌,必选项。

  • token_type:表示令牌类型,该值大小写不敏感,必选项。

  • expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。

  • scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。

  • state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。

https://www.example.com/callback#access_token =ACCESS_TOKEN&state=xyz&token_type=example&expires_in=3600&state=xxx

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

(E)资源服务器返回一个网页,其中包含的代码可以获取Hash值中的令牌。

(F)浏览器执行上一步获得的脚本,提取出令牌。

(G)浏览器将令牌发给客户端。

使用场景

  • 适用于所有无Server端配合的应用

  • 如手机/桌面客户端程序、浏览器插件。

  • 基于JavaScript等脚本客户端脚本语言实现的应用。

思考:

简化授权模式下的账户劫持的问题。

(A)https://www.QQ.com/authorize?response_type=token&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read&state=xxx
(C)https://www.example.com/callback#access_token =ACCESS_TOKEN&state=xyz&token_type=example&expires_in=3600&state=xxx

(C)步骤中的请求链接实际上来源A请求中的redirect_uri参数(用于指定重定向的链接),最为关键的地方是(C)请求中带有access_token,那么实际场景就是当state参数不存在的时候可以进行csrf攻击,伪造redirect_uri就好了,但正常情况下
QQ至少会对redirect_uri的域名做校验吧(当然也可能不止这一项),所以不能随便重定向。那我们需要做的是找到受信任的网站下的xss漏洞,然后重定向获取劫持access_token,在获取到access_token后完整攻击。可以发现隐式授权如果存在问题一般是指服务提供商没有做好redirect_uri的校验,同时呢开发人员也没有加上state参数。

3.3.3密码模式

密码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向"服务商提供商"索要授权。

在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。

该模式过程如下:

(A)用户向客户端提供用户名和密码。

(B)客户端将用户名和密码发给认证服务器,向后者请求令牌。

B步骤中,客户端发出的HTTP请求,包含以下参数:

  • grant_type:表示授权类型,此处的值固定为"password",必选项。

  • username:表示用户名,必选项。

  • password:表示用户的密码,必选项。

  • scope:表示权限范围,可选项。

https://www.example.com/token?grant_type=password&username=USERNAME&password=PASSWORD&client_id=CLIENT_ID

(C)认证服务器确认无误后,向客户端提供访问令牌。

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

在该过程中用户必须把自己的密码给客户端,针对于“输入账号”这个操作,小伙伴们能想到的问题都有哪些,那基本上就存在那些问题了!(比如爆破╮(╯▽╰)╭)

3.3.4客户端模式

客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向"服务提供商"进行认证。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在此不做过多解释,只了解过程。

该模式过程如下:

(A)客户端向认证服务器进行身份认证,并要求一个访问令牌。

  • granttype:表示授权类型,此处的值固定为"client_credentials",必选项。

  • scope:表示权限范围,可选项。

https://www.example.com/token?grant_type=client_credentials

(B)认证服务器确认无误后,向客户端提供访问令牌。

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

4.总结

oauth2.0协议本身设计是安全的,制定OAuth 2.0协议的最大动力之一,是希望用一个协议适应多个业务场景授权,这种扩大业务场景的结果,也意味着薄弱点的增多,而在开发过程中没有严格按照协议进行开发,或对流程中的参数校验不完整,造成了一些流程上的漏洞。现在由单一场景变为多个场景直接的交互,也就导致场景之间的安全问题产生了交叉,一些本来属于潜在威胁,很容易通过场景转换而暴露出来,让威胁变得更加严重。对于擅长“由点到面”的攻击者来说,现在只需要针对常见薄弱点(尤其是授权认证流程中的薄弱点)就有可能攻击成功。(攻击成功案例可参考wooyun,hackerone,里面有更详细的攻击流程,更加具体形象)

以上就是针对OAuth2.0学习的过程以及一点点思考。

E

N

D

Tide安全团队正式成立于2019年1月,是新潮信息旗下以互联网攻防技术研究为目标的安全团队,团队致力于分享高质量原创文章、开源安全工具、交流安全技术,研究方向覆盖网络攻防、系统安全、Web安全、移动终端、安全开发、物联网/工控安全/AI安全等多个领域。

团队作为“省级等保关键技术实验室”先后与哈工大、齐鲁银行、聊城大学、交通学院等多个高校名企建立联合技术实验室,近三年来在网络安全技术方面开展研发项目60余项,获得各类自主知识产权30余项,省市级科技项目立项20余项,研究成果应用于产品核心技术研究、国家重点科技项目攻关、专业安全服务等。对安全感兴趣的小伙伴可以加入或关注我们。


文章来源: http://mp.weixin.qq.com/s?__biz=MzAwMDQwNTE5MA==&mid=2650246479&idx=2&sn=1e6179016f7d63bbb964befec67b63c0&chksm=82ea56e6b59ddff05889f7d4c389434016b905f341419a2a565ea23e3167ac343a7605d07103#rd
如有侵权请联系:admin#unsafe.sh