1. 引言
2. OAuth 2.0 协议
OAuth 2.0 是目前比较流行的做法,它率先被Google, Yahoo, Microsoft, Facebook等使用。之所以标注为 2.0,是因为最初有一个1.0协议,但这个1.0协议被弄得太复杂,易用性差,所以没有得到普及。2.0是一个新的设计,协议简单清晰,但它并不兼容1.0,可以说与1.0没什么关系。所以,我就只介绍2.0。
2.1 协议的参与者
此外,为了支持开放授权功能以及更好地描述开放授权协议,OAuth引入了第四个参与实体:
2.2 授权类型
2.3 OAuth协议 - 基本思路
[Figure 1: Abstract Protocol Flow]
如图1所示,协议的基本流程如下:
2.4 授权码类型的开放授权
[Figure 2: Authorization Code Flow]
如图2所示,授权码类型的开放授权协议流程描述如下:
(5) AS在收到authorization_code时需要验证Client的身份,并验证收到的redirect_uri与第3步请求authorization_code时所使用的redirect_uri相匹配。如果验证通过,AS将返回access_token,以及refresh_token(若access_type=offline)。
如果读者对这个流程的细节不甚清楚,那么可以先看第3节的一个实例化描述,然后再回来看这部分内容。
3. OAuth协议实例化描述
下面我以实例化方式来帮助读者理解授权码类型的授权协议的运行过程。假设:
(1) Alice有一个有效的Google帐号;
(2) Facebook.com已经在Google Authorization Server上注册了Client身份,已经获得(client_id, client_secret),注意client_secret是Client与AS之间的一个共享密钥。
(3) Alice想授权Facebook.com查看她的联系人列表(https://www.google.com/m8/feeds)。
图3展示了Alice、Facebook.com、Google资源服务器、以及Google OAuth授权服务器之间的协议运行过程。
[Figure 3: An Instance of Authorization Code Flow]
//若字体无法看清,请单击右键->选择查看原图
(1) 通过https直接将client_secret发送给AS,因为client_secret是由Client与AS所共享,所以只要传送client_secret的信道安全即可。
(2) 通过消息认证码来认证Client身份,典型的算法有HMAC-SHA1。在这种方式下,Client无需传送client_secret,只需发送消息请求的signature即可。由于不需要向AS传递敏感数据,所以它只需要使用http即可。
[Figure 4: RO's Identity Authentication]
[Figure 5: RO's Authorization Decision]
4. OAuth设计上的安全性考虑
4.1 为何引入authorization_code?
协议设计中,为什么要使用authorization_code来交换access_token?这是读者容易想到的一个问题。也就是说,在协议的第3步,为什么不直接将access_token通过重定向方式返回给Client呢?比如:
HTTP/1.1 302
Location:
https://www.facebook.com/?access ... amp;expires_in=3600
如果直接返回access_token,协议将变得更加简洁,而且少一次Client与AS之间的交互,性能也更优。那为何不这么设计呢?协议文档[1]中并没有给出这样设计的理由,但也不难分析:
(1) 浏览器的redirect_uri是一个不安全信道,此方式不适合于传递敏感数据(如access_token)。因为uri可能通过HTTP referrer被传递给其它恶意站点,也可能存在于浏览器cacher或log文件中,这就给攻击者**access_token带来了很多机会。另外,此协议也不应该假设RO用户代理的行为是可信赖的,因为RO的浏览器可能早已被攻击者植入了跨站脚本用来监听access_token。因此,access_token通过RO的用户代理传递给Client,会显著扩大access_token被泄露的风险。 但authorization_code可以通过redirect_uri方式来传递,是因为authorization_code并不像access_token一样敏感。即使authorization_code被泄露,攻击者也无法直接拿到access_token,因为拿authorization_code去交换access_token是需要验证Client的真实身份。也就是说,除了Client之外,其他人拿authorization_code是没有用的。 此外,access_token应该只颁发给Client使用,其他任何主体(包括RO)都不应该获取access_token。协议的设计应能保证Client是唯一有能力获取access_token的主体。引入authorization_code之后,便可以保证Client是access_token的唯一持有人。当然,Client也是唯一的有义务需要保护access_token不被泄露。(2) 引入authorization_code还会带来如下的好处。由于协议需要验证Client的身份,如果不引入authorization_code,这个Client的身份认证只能通过第1步的redirect_uri来传递。同样由于redirect_uri是一个不安全信道,这就额外要求Client必须使用数字签名技术来进行身份认证,而不能用简单的密码或口令认证方式。引入authorization_code之后,AS可以直接对Client进行身份认证(见步骤4和5),而且可以支持任意的Client认证方式(比如,简单地直接将Client端密钥发送给AS)。
在我们理解了上述安全性考虑之后,读者也许会有豁然开朗的感觉,懂得了引入authorization_code的妙处。那么,是不是一定要引入authorization_code才能解决这些安全问题呢?当然不是。笔者将会在另一篇博文给出一个直接返回access_token的扩展授权类型解决方案,它在满足相同安全性的条件下,使协议更简洁,交互次数更少。
4.2 基于Web安全的考虑
OAuth协议设计不同于简单的网络安全协议的设计,因为OAuth需要考虑各种Web攻击,比如CSRF (Cross-Site Request Forgery), XSS (Cross Site Script), Clickjacking。要理解这些攻击原理,读者需要对浏览器安全(eg, Same Origin Policy, 同源策略)有基本理解。比如,在redirect_uri中引入state参数就是从浏览器安全角度考虑的,有了它就可以抵制CSRF攻击。如果没有这个参数,攻击者便可以在redirect_uri中注入攻击者提供的authorization_code或access_token,结果可能导致Client访问错误的资源(比如,将款项汇到一个错误的帐号)。
基于Web安全的考虑,OAuth协议文档中已经有了比较全面的阐述,所以我不打算在此文中进行展开,有兴趣的读者请参考[1]。
5. 结语
本文对OAuth 2.0 开放授权协议及其设计上的安全性考虑做了一个基本的介绍,希望能给参与安全协议设计和开发的同学起到一点帮助。
参考文献:
[1] Hammer-Lahav, E., Recordon, D., and D. Hardt, "The OAuth 2.0 Authorization Framework", draft-ietf-oauth-v2-31 (work in progress), June 2012.
[2] http://aws.amazon.com/iam/
原文作者:郭庆帅
本文转自:http://club.gizwits.com/thread-8127-1-1.html