说透OAuth 2.0 [1] - 什么是认证和授权?

    • 认证实体变更

    • 认证方式变更

    • 信任系统变更

    • 引子

    • 认证


    • 授权

    • 总结


引子

我在面试Web相关岗位时,经常会问面试者一个问题,什么是认证,什么是授权?(也请你花一分钟时间思考一下)

部分面试者会给我如下的答案:

当用户打开浏览器或者App的时候,如果某些功能不是匿名用户能操作的,那么我们就会将用户引导到登录页面,让用户输入自己的用户名和密码、当然也可能是手机短信验证等方式,在安全性较高的系统还会要求输入验证码。如果验证通过,那么用户就拥有了可以操作这些功能的权限。这里的登录动作就是认证,对不同类型用户进行的访问权限切分就是授权。

能给到类似如上答案的面试者,已经是思路相对清晰的候选人,而更多的面试者是含糊的告诉我,在用户登录的这个步骤里,就已经同时完成认证和授权的动作。

这些答案不能说不对,但随着你对系统整体认知程度的加深,对这些基础概念的理解应该要有更成体系的认识。否则如果认证和授权真如上述所说只是个用户登录的过程,那为何还需要引入OAuth 2.0这种相对复杂的规范,甚至是更上层的OpenID Connect(OpenID Connect会在后续有专题讲解,当前可以简单理解为基于OAuth的上层规范)?

所以,我尝试以目前的理解来解释何为认证,何为授权,以引入后续对OAuth 2.0相关的介绍。能力有限,不当之处烦请指出。

认证

我们设想这样的场景,比如小A需要通过网上银行,查询自己的账户余额,那小A大概会按如下步骤进行:

  • 小A打开浏览器,在地址栏输入网上银行的地址;

  • 在网上银行的登录页,输入自己的账号和密码,并点击登录;

  • 点开账户相关功能,查询账户余额;

这是一个典型的登录操作,我们抽取其中的参与方,可以抽象出三个要素:

  • 认证实体:小A

  • 认证方式:账号密码

  • 信任系统:网上银行

但这并不全面,这中间还有一个关键的隐式要素,叫:

  • 凭证:登录成功后颁发的token(比较典型的如JSESSIONID)

我们通过这四个要素将场景重新描述一遍:认证实体,通过账号密码的认证方式,在信任系统中进行登录操作,在认证成功后,信任系统返回一个凭证(即token),认证实体通过持有该凭证,可以在信任系统中进行后续的操作。

OK,至此,我们对我们所熟悉的典型的登录场景进行了拆解,抽象出认证实体、认证方式、信任系统和凭证四个要素,可是,为什么要把简单的事情复杂化?接下来,我们来看下这个场景的变种。

认证实体变更

还是查询账户余额的场景,银行内部的某个管理系统A,它自身并没有账户余额相关的数据,但是它希望网上银行系统为它提供一个接口,可以通过传递账户id,去查询指定账户余额(请注意,真实的世界不会对提出这样的需求,即便有类似需求,也不会在网银系统实现)。那基于上述小A的案例和当下的需求,我们立刻可以给出如下设计:

  1. 网上银行生成一个特殊的账号密码,我们姑且称之为系统级账号密码,并分配给管理系统A(因为系统级账号并不同于小A的用户级账号,所以其存储和验证方式都不同);

  2. 网上银行开放两个新的端点:

    • /token端点, 根据系统级账号密码,可以换取凭证

    • /account/{accountId}的端点,传输指定的账户id,即可返回余额;

  3. 管理系统A通过系统级账号密码在/token端点执行认证的动作,换回凭证;

  4. 管理系统A携带凭证,并请求/account/{accountId}端点,以获取指定accountId的账户余额;

如上的场景在于我们的认证实体发生了改变,由人变成了服务器(由小A变成了管理系统A),所以我们可以得到的启发是,所谓的认证,其认证实体最常见是人,但并不仅限于人,还可以是:

  • 如:上述场景中,通过系统级账号密码,认证访问网上银行接口的是合法的服务器

  • 如:在ATM取钱时,我们插入银行卡,输入对应的交易密码,认证此次是合法的交易

  • 如:在小区门禁处刷卡时,认证此次是合法的出行

  • 其它;

认证方式变更

由认证实体不同,我们可能采用的认证方式也不尽相同,比如在上述案例中,分别出现过用户级账号密码、系统级账号密码、交易密码和磁卡。接下来,我们对管理系统A和网上银行间的认证进行升级:

  1. 管理系统A的系统管理员通过openssl生成一对公私钥,将私钥放置于管理系统A所在服务器,将公钥放置于网上银行所在服务器;

  2. 网上银行开放两个新的端点:

    • /token端点,使用公钥对传入的签名进行验签,如果验签通过,返回凭证;

    • /account/{accountId}的端点,传输指定的账户id,即可返回余额;

  3. 管理系统A使用私钥进行签名,并传入/token端点,验证通过可换取凭证;

  4. 管理系统A携带凭证,并请求/account/{accountId}端点,以获取指定accountId的账户余额;

很明显,我们弃用了系统级用户密码的方式,而改用非对称中的签名算法,其原因:

  • 用户名密码是较为不安全的方式:

    • 用户名密码会在网络中传输,存在泄露的风险;

    • 密码如果要求不严格,存在弱密码风险,容易被猜解;

    • 用户名密码存在撞库风险;

  • 公私钥相对安全:

    • 公私钥下发后将一直存储在本地,泄露风险较小;

    • 公私钥猜解的风险极低,在当前计算条件下,其数理逻辑上逆运算的耗时在十几年甚至以上;

    • 公私钥可辅助进行业务交易签名,实现交易的不可抵赖性等;

熟悉密码学的同学应该明白此次升级的意义(不熟悉也没关系,后续会有专题介绍)。

此时我们再引申想一想,在网上银行中,当我们需要进行转账类交易时,即便我们刚登录过网上银行系统,它仍然会再一次要求进行手机短信验证码的认证,来保障这类敏感的交易的可靠性,我们管这类认证叫二次认证。更有甚者,当我们的交易金额足够大时,网上银行在要求进行手机短信码认证的同时,还需要插上ukey来共同完成此次认证,而这类认证则叫做多要素认证
在我看来,认证的方式很多,我们无法说明哪种方式是最好的,但基于认证实体、业务场景、行业规范和用户体验,我们可以采用相对合理的认证方案。但读至此处,希望大家能意识到认证方式的多样性,绝非“用户名密码”就能涵扩的。

信任系统变更

我们注意到在上述案例中有个重要的参与者,就是网上银行,也就是我们抽象要素中的信任系统。那现在请你花一分钟想想,为什么它叫信任系统?

你是不是有过这样的体验,一封不明来路的邮件,带来一条不明去向的链接,点击链接后要你输入自己的个人信息,比如身份证、手机号等。我想,但凡有一点安全常识的人,也不会输入这些数据,甚至直接忽视这封邮件。而这条链接所引导你去的系统,就是你不信任的系统。在这种场景下,所谓的信任系统,是你可以放心的将自己的隐私数据交由其保管的系统,比如金融类(网银、手机银行等)、出行类(滴滴、携程等)或电商类(淘宝、京东等),这些系统一般都有大厂的背书,你信任它们,放心将自己的隐私数据交由它们保管。

而这时候,出现一个第三方系统,比如不知名天气系统A,它希望能通过分析你在携程的出行和酒店记录,来提醒你天气变化注意加衣服,多么贴心和友善的系统,但你能放心的把自己在携程的账号密码托管给天气系统A吗?答案自然是否定的,因为这类中小系统未必有足够的安全级别去保障你的数据安全,如果你托管的携程账号因此泄露,则相关的隐私数据将在恶意攻击者的眼前一览无余。

可是,我们因此就要否认这类需求的意义吗?在讲求开放和数字化的今天,显然不行。因此,我们的“认证(其实此处更准确的是授权)”有了更大的挑战,当非信任系统出现时,我们如何提供受限的方式,让它合法的获取信任系统的数据,这其实也是OAuth 2.0要解决的主要问题之一

此处我们先不解释如何解决此类问题,你暂时只需要知道,当非信任系统出现并想要获得你的隐私数据时,整个认证和授权的方式将变得复杂和有趣起来。

授权

在上述的讨论中我们已经大概明晰,认证的作用,是通过某种认证方式,让信任系统能验证待认证实体的身份,并在验证通过后颁发凭证的过程。而认证和授权经常混为一谈的原因,是因为授权往往紧随其后,是当系统在验证完待认证实体身份后,授予该实体访问某些特定资源的权限

我们回顾之前讲解认证时涉及的场景:

  1. 小A在网上银行登录成功后:

    1. 网上银行授予小A访问网银系统查询类业务的权限,如账户查询类、账户交易历史查询、基金理财产品查询类等,只要携带凭证,小A可以随意访问此类业务;

    2. 对于动账类交易,如发起一笔转账,小A需要通过手机短信验证码进行二次认证,才会被授予进行该笔转账交易的权限。如果需要发起另一笔转账,则还需要再进行一次完全独立的二次认证;

    3. 当小A从网上银行登出后,即便使用之前的凭证,也无法访问任何业务;

  2. 管理系统A通过系统级用户密码在网上银行验证成功后:

    1. 网上银行授予管理系统A访问/account和/token端点的权限;

    2. 当管理系统A访问其它端点时,网上银行将直接拒绝其请求;

通过上面的回顾,我们会发现授权有几个重点:

  • 授予的资源

  • 授予的周期

  • 授予的凭证

只有在授权的有限周期内,通过凭证访问被授予的资源,才能访问成功,否则都应被拒绝

总结

所以,如上是对认证和授权的概述,由此我们可以知道,当认证实体、认证方式和信任系统等出现变更时,我们的技术实现也将对应变更。而在一些更复杂的情况,比如单点登录、开放系统间的数据访问等场景下,我们要如何保证应用和用户的数据安全,这是一个非常大的挑战。好在OAuth 2.0的出现,为我们提供了一个范式,我们可以以此为规范,去实践这些复杂场景下的应用。OAuth 2.0也是本系列博客后续的重点。


添加回复:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。