本文由公众号EAWorld翻译发表,转载需注明出处。
作者:Daniel Lindau
译者:白小白
原题:8 Vital OAuth Flows and Powers
原文:http://t.cn/Ew5Fu3h
全文5972字,阅读约需要10分钟
目录:
一、OAuth是什么?什么是“流”?
二、授权流因用例不同而异
三、获取令牌
四、令牌管理
五、为什么区分OAuth流很重要
(注:本文的原文,包括部分参考内容需要以不可描述的方式访问。)
在本文中,Curity的Daniel Lindau概述了重要的OAuth授权流程和能力。
API领域需要授权验证来保证数据的安全,这是现代API设计理念的一种必然趋势。因此,实现正确的授权系统至关重要,甚至可能比需要处理授权的API本身更加重要。
OAuth是一个强大的解决方案。然而,与任何工具一样,OAuth的强大有赖于用户对其能力的理解。理解OAuth是什么,至少对每个特定的授权流程有一个大体了解是非常重要的。在这篇文章中,我们将介绍OAuth,并简要介绍每种授权流程的概念。我们将了解每个流程适用的时机和具体应用。
一、OAuth是什么?什么是“流”?
虽然可能无需赘言,但我们最好还是先了解一下OAuth的基本概念。确切地说,OAuth是基于互联网的代理和授权的开放标准。OAuth的应用场景通常是需要代表用户访问某些资源的客户端。为了完成这一代理过程,OAuth需要发布访问令牌(Access Token)。令牌的存在表示用户允许客户端作为用户的代理访问相关数据。对此令牌的请求、授予和生命周期管理通常被称为“流”,这一术语将在本文中大量使用。
白小白:
OAuth是一个关于授权的开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。参考 http://t.cn/Ewt7pYI。
这里的用户,也就是资源所有者,而第三方应用,就是客户端,而拥有了令牌的客户端,在访问相关资源时,就相当于用户的代理。
第一版OAuth最初创建于2007年,是作为在Twitter API上处理身份验证的一种方式,此后,它在从企业级代码库到私有项目的各种应用程序中变得非常流行。第二版OAuth 2.0,已经成为保障API安全的事实标准。
二、授权流因用例不同而异
OAuth规范接受多种获取和验证令牌的方法,但并不是所有流对所有类型的客户端都是普适的。OAuth规范定义了公共和私有客户端,这种划分,取决于客户端安全存储其凭据的能力。私有客户端通常是具有后端的应用程序,可以保留用于身份验证的密钥。公共客户端无法安全存储密钥,比如,通常没有后端的单页面应用程序(Single Page Application,简称SPA)。
举例来说,带着后端的Web应用被视为私有客户端,而单页应用程序被认为是公共客户端。后端可以安全地存储密钥,而SPA开放一切数据。
移动客户端分类比较棘手,因为他们通常都很擅长存储密钥,但很难给他们一个秘钥。受到通过应用程序商店分发应用程序的方式的制约,很难令OAuth服务器信任某个客户端代表了正确的应用程序而对客户端以某种方式进行身份验证。由于这个原因,移动客户端更多作为公共客户端来进行考量。通过使用其他获取凭据的方法,如动态客户注册,也可以将移动客户端转变成私有客户端。稍后会有更多的描述。
白小白:
SPA是一个相对比较难理解的概念,如果与多页面应用中的Ajax调用相比的话。强行理解的话,SPA将会打破MVC的模式区隔,全部的处理逻辑都是在浏览器端进行的,也就是说,当加载完一个单页面应用之后,所有的相关源码也就在浏览器端了。因此,不可能在这种情况下给客户端一个密钥,因为那必然导致安全问题。同样的,移动应用程序的所有处理逻辑在安装好的一刻也是完全下载到移动设备的。但我的理解是,这两者仅在面对OAuth的场景时才存在这样的限制。毕竟,我们是知道,有很多移动端应用是支持用户名密码式的登陆方式的,也有很多应用支持诸如微信这样的第三方授权登陆。
三、获取令牌
在相关规范中定义的许多授权流中,有四种基本流程用于获取OAuth中的令牌。在这里,我将就这几个基本流程和其他我认为比较重要的流程进行一些描述。
1.代码流
认证代码授权(Authorization Code Grant),或代码流,最广泛使用的OAuth流。要使用代码流获得令牌,客户端只需将浏览器重定向到服务器,就会向OAuth服务器发送授权请求。OAuth服务器确保对用户进行身份验证,并提示用户批准授权。当用户批准时,短时代码(CODE)是发给客户的。此代码可视为一次性密码,或临时码。客户端接收到此代码,现在可以在浏览器之外的经过身份验证的后端调用中使用它,并将其交换为令牌。
这里要提到的一件事是,用户将只向OAuth服务器提供其凭据。用户不必向应用程序提供凭据,它只需将凭证输入到它已经知道并信任的服务器。这是OAuth着手解决的一件事。
另一个好处是令牌是通过浏览器传递,这使得窃取变得更加困难,而且由于交换令牌的调用是经过身份验证的,所以服务器可以确保将令牌传递给正确的客户端。
通常,代码流还将允许您接收刷新令牌,在访问令牌过期之后,允许客户端在不需要用户确认的情况下获得新的访问令牌。代码流只应由私人客户端使用。因为客户端需要在交换代码时向服务器端提供自身的密钥来进行身份验证。
白小白:
认证代码授权的最典型示例是微信网页授权。我们在很多的第三方应用上可以通过微信网页授权来获得微信头像和昵称来登陆应用。第三方应用客户端通过提供APPID来向微信服务器发起请求,会跳到一个页面询问用户是否确认“获得昵称和头像信息”,获得确认后微信将返回CODE。然后客户端附加SECRET和APPID再向微信获取ACCESS_TOKEN,而后再通过ACCESS_TOKEN和OPENID拉取昵称、头像等信息。在此过程中:
1、用户只向微信提供了相关凭证(OPENID),而没有向第三方应用提供
2、刷新令牌的过程不需要经过用户确认。
详细示例说明:http://t.cn/R9zOQQj
代码流客户端由浏览器和后端两部分组成。
2.隐式流
隐式流(Implicit Flow)不像代码流那么复杂。它以与代码流相同的方式开始,客户端向OAuth服务器发出授权请求。用户对委托进行身份验证和批准,但是OAuth服务器不会发出CODE,而是返回访问令牌进行响应。
当然,这里的缺点是令牌是完全可见的,而且由于它在浏览器中,客户端在处理令牌的过程中容易受到安全攻击。
隐式流是为无法自行验证的公共客户端创建的。因此,相关的授信过程依赖于一个名为redirect_uri的参数。OAuth服务器需要为客户端注册一个URL,用来发送响应。仅有这个URL会发出响应,因此,即使恶意应用程序伪装成用户启动代理进程,响应也将始终返回到真正的应用程序。
由于这是针对公共客户端的,因此将不会发出刷新令牌。这意味着只有让用户参与才能接收新的访问令牌。
白小白:
实际上隐式流在很多文档中也称为简化流,相对于认证码授权流,少了第一个获取CODE的过程。QQ的授权登陆的Client-Side模式采用的就是隐式流授权。在第三方网站或者应用中放置“QQ登陆按钮”,然后在用户点击后会向服务器发出请求获取ACCESS_TOKEN,这个请求中只会附加用户的APPID。更多内容可参考如下链接:
http://t.cn/EwtAaVz
隐式流:整个流程发生在浏览器中。
3.客户端凭证流
在客户端凭证流(Client Credentials Flow)中,不涉及用户参与。这是一种严格限定为服务器与服务器之间的通信的流程。服务器需要作为自身访问API。因此,不涉及浏览器,并且需要一个私有客户端。为了得到一个存取令牌,客户端只需将其凭据传递给OAuth服务器并接收令牌即可。
此流中不发出刷新令牌,因为客户端无论如何都可以使用其凭据检索新的访问令牌。
白小白:
所谓客户端所需要的凭据,就微信公众平台的场景来说,就是APPID和SECRET。CCF的授权的服务器TO服务器模式有三层含义,按照官方文档,其一是非交互性的应用资源 ,或者在某些场合可以理解为只读的应用资源,尽管是只读的信息,但又不希望所有人都可以访问时,就可以采用这种方式。其二是通过这种方式授权访问的是与用户个人无关的相关信息,也就是不需要有用户点击“允许获取昵称头像”这个过程。微信公众平台的很多API即是此类,如获得获取用户增减的统计数据。但显然微信公众平台还有很多违反第一类“只读”场景的例子,比如添加删除图文素材等。这就引出了第三种应用场景,即由本人创建的服务,仍旧由本人的其他服务进行调用的场合。微信公众平台的相关信息可以看作是由腾讯创建但只属于公众号运营者所有的资源,而在运营者获取相关信息或进行操作时仍旧需要采用授权的方式来确认安全性。
客户凭证流:客户端根据令牌端点进行身份验证。不涉及用户确认过程。
4.资源所有者密码凭据流
资源所有者密码凭据流(Resource Owner Password Credentials Flow)非常简单。客户端收集用户的凭据(用户名和密码),并将它们与自己的客户端凭据一起传递。服务器以令牌和可选的刷新令牌来进行响应。很简单对吧?但是有一个“但是”,而且很重要。
ROPC这个流程违背了OAuth的目的之一,即用户必须将其凭据交给应用程序客户端,因此无法控制客户端如何使用它。如果可以使用其他流程,则不建议使用该流。它只在规范中指定以便处理遗留或迁移系统的案例。使用ROPC时必须小心谨慎。一个例子可以是企业级桌面应用程序,这类应用不经常更新,但仍需要访问API平台。
我们不建议使用它,但是如果您真的需要的话:这个流只适用于私有客户端,并且客户端可以获得一个刷新令牌。
白小白:
听起来提供用户名和密码来获得令牌和客户凭证流的提供APPID和SECRET获得令牌没什么区别。但实际上,此前的授权流,用户或者客户端只与授权服务器进行交互,而不需要向客户端应用程序提供任何个人信息。而ROPC要求你在客户端中输入个人信息,从而可能带来用户隐私的泄漏。所谓遗留系统的应用场景,比较典型的是你升级后端API服务的验证架构,在不改动旧版客户端的情况下,使用用户名和密码来获得令牌是最方便的,此时就需要使用ROPC方式。
ROPC:客户端将用户凭据连同自己的凭据一起发送。
5.动态客户端注册
虽然并非OAuth核心规范定义的流程,动态客户端注册(Dynamic Client Registration,后文简称为DCR)解决了移动客户端这一重要的应用场景。由于移动应用程序是通过应用程序商店分发的,因此很难给它们一个唯一标识的证书,因此移动客户端通常被标记为公共的客户端。DCR尝试对此进行弥补的方式是,客户端自我注册,以及在安装时请求唯一的凭据。DCR的工作方式是让客户端向OAuth服务器发送注册令牌,OAuth服务器生成一组凭据并将它们返回给客户端。然后,这些凭据可以在代码流中使用,客户机可以对自己进行身份验证。
注册令牌可以通过多种方式获得。可以让用户在隐式流中自行验证,也可以基于预先分发的秘钥使用客户端凭据流。
除了移动端应用场景之外,DCR对于API管理平台非常适用,这类平台需要能够为OAuth服务器创建客户端。
白小白:
和前面的所有模式不同的是,在DCR模式中需要进行授权的客户端是临时创建的,此前在授权服务器上并没有预先定义客户端的凭据,可以说,两方之间是完全陌生的。比如在手机上安装一个应用程序,不可能为这个程序附加一个固定的密钥,来识别这个程序的身份,因为代码可能采用反编译等方式破解。再比如在API管理平台中,新创建了一个应用,这个应用的用户也需要获得令牌。而应用是新创建的,授权服务器并不知晓其存在。关于这种模式,规范中并未提供固定的实现方式。以下地址的实现草案和相关内容,可以参考:
http://t.cn/EwtbhBc
http://t.cn/EwtbyOM
6.辅助令牌流
辅助令牌流(Assisted Token Flow)还处于草案阶段,并不是基本流程的一部分,但值得一提。它是OAuth的同级规范,试图使单页应用程序获得令牌的过程其更容易实现。对于这些类型的应用程序,很难处理隐式流,因为它严重依赖重定向。相反,辅助令牌流定义了与隐式流类似的流程,不同的是,使用iFrame和postMessage作为通讯的方式。
在这里阅读更多:《辅助令牌流:单页应用程序中OAuth集成的答案》(http://t.cn/EwtoblI)
白小白:
单页面应用的最显著特征是页面本身在初次加载后是不进行页面的刷新的,因此无法完成一个向授权服务器的的重定向来获得令牌,辅助令牌流的解决方案就是将代码流和隐式流等相关处理嵌入一个iFrame中进行(在我看来,这种流程才应该叫隐式流,狗头表情参见)。这种方式怎么说都不算高级,而且还会进一步加剧单页面应用本身的SEO问题。但还没有看到有更好的解决方案。
四、令牌管理
7.自省
自省(Introspection)是询问OAuth 服务器令牌是否有效的方法。访问令牌通常通过引用来传递,这意味着除了OAuth服务器之外,它们对任何人都没有任何意义。自省客户端通常是API或者API网关相关形态。自省是一种简单认证调用,客户端发送令牌,服务端响应属于令牌的数据,如过期时间、标题等。
白小白:
OAuth.com上的文档是这样讲的,“ OAuth2.0核心规范没有定义资源服务器应该如何验证访问令牌的特定方法,只是提到它需要资源和授权服务器之间的协调。在某些情况下,特别是对于小型服务,两个端点都是同一个系统的一部分,并且可以在内部(例如在数据库中)共享令牌信息。如果在两个端点位于不同服务器上的大型系统中,将导致两台服务器之间的通信采用专有和非标准协议” 。这个过程相当于,大哥和二哥是兄弟,然后有个张三拿着二哥的口信说让大哥借3000块钱,大哥总要和二哥问问这事是真是假。就其含义来说,与其译为自省还不如译为检查或者令牌检查,但那与原词含义差距太大。我的理解是,这个检查过程仅发生在资源服务器和授权服务器之间,而这两者相当于同一系统中互相信赖的两方,也就是,都是自己人,因此英文原文是Introspection。
8.撤销
撤销(Revocation)是OAuth重要的能力之一。如果没有OAuth,用户一旦将其凭据泄露给应用程序,就无法收回这一确认。唯一的办法是更改密码,然而这将带来更大的副作用,比如,密码修改后,相关应用将无法访问用户的账户。
使用OAuth,用户可以通过撤销令牌的方式随时决定收回确认。在OAuth中,有两种撤销选项。可以撤销访问令牌,这将被视作是当前会话的结束。如果存在刷新令牌,则该令牌仍然有效。撤销刷新令牌将使刷新令牌无效,并使其附带的任何活动的访问令牌无效。
使用经过身份验证的调用执行实际的撤销操作,这一过程由客户端完成。经过身份验证,公共客户端也可以执行撤销。
白小白:
这里面涉及“代理”的概念,一次代理代表客户端以授权的用户身份执行某种操作。而一次代理过程中可能获得多次令牌,包括访问令牌和刷新令牌。
事实上可能存在3种撤销场景:
1、如果某一个当前有效的访问令牌被撤销了,比如访问访问令牌1被撤销,则刷新令牌1仍旧有效。
2、如果某一个当前有效的刷新令牌被撤销了,则所有访问和刷新令牌都会撤销,也就是这一次代理都被撤销
3、如果通过某一个刷新令牌X获得了新的访问令牌和新的刷新令牌。则对这一刷新令牌X的撤销操作不会有任何后续效果。
参见http://t.cn/Ewtcr8X
五、为什么区分OAuth流很重要
在OAuth中似乎有很多类似的流,但是每个流都有其特定的用例。通过这些基本流,您应该能够选择与您的应用程序和场景相匹配的流。虽然这通常都是高水平的,但每一个流量都可以保证它自己的一部分。
白小白:
如果对本文的相关概念作一个梳理,大致如下。这个表格梳理了本文的6种授权流的异同,表格的目的在于让我们以简单的方式理解几种流模式的区别。信息并不全面,也未必准确,仅为个人理解。所谓简称,是我认为可以简单概括其本意的名称。
(点击可放大)
关于作者:Daniel Lindau是Curity的解决方案架构师。他目前的大部分工作是帮助各种规模的公司构建基于安全标准的SSO解决方案。他有作为应用程序开发人员的背景,并且在用SAML、SCIM、OAuth2和OpenIDConnect等标准构建解决方案方面有丰富的经验。
关于EAWorld:微服务,DevOps,数据治理,移动架构原创技术分享,长按二维码关注