OAuth2.0系列文章 - 为什么我们需要引入OAuth2.0

1. 写在前面的话

我之前参与过一个OpenAPI的项目,其业务形态非常简单,一句话就可以说清楚:第三方应用想要来调用我们系统的接口,以获取我们的内部数据OpenAPI项目最关键的一点,就是要解决对外接口的安全性问题,比如最基础的:

  • 谁能调用我们系统的接口?
  • 他有权限调用哪些接口?

在技术选型的阶段,我们阅读了一些国内做OpenAPI的厂商的公开资料,很自然的就找到了 OAuth2.0这个主流的授权框架,但当我搜索相关资料尝试弄明白这个框架时,却遇到了问题:很多关于OAuth2.0的博客都偏理论,而且内容高度雷同,了解概念有余,但想依靠这些信息来搭建一套安全的OpenAPI平台还是有所不足。为此,我们团队又花了很多时间去阅读OAuth2.0相关的规范文档,对我们比较有帮助的文档如下:

也是在做OpenAPI项目的期间,对OAuth2.0有了一些比较粗浅的理解,这里整理记录下来,以作回顾。
本篇是该系列的第一篇,主要介绍OAuth2.0要解决什么问题。

2. 认证授权就是用户名密码?

我在做OpenAPI项目之前,一直觉得认证授权是一件很简单的事情,就像宋丹丹要把大象装冰箱一样,总共只需要三步:

  1. 用户浏览器中输入用户名和密码,点击登录;
  2. 服务端接收到用户名和密码信息,校验其正确性,成功则返回登录令牌
  3. 浏览器接收到登录令牌,后续向服务端发送的请求都会携带该登录令牌用于身份校验

流程大致如下图所示:
配图1

是吧?相信很多人跟我一样,一提到认证授权的时候,脑子里第一时间想到的流程就是这样的。但我转念一想,不对啊,这三步顶多也就百来行代码能解决的事情,为什么有的公司专门招了几十号人在做认证授权系统,甚至还有一些公司靠提供 IDaas 的服务做到几十亿市值?
奇怪,资本家不可能有错,有错的一定是我自己。所以我们扩展一点来想,除了使用用户名密码登录这种最常见的认证授权场景外,还有哪些场景是值得我们探究的?

3. 名词统一

在开脑洞前,我们先来归纳一下上面这个最简单的认证授权场景里的一些主体,统一一下名词概念,避免我说的跟你理解的不一致,同时也提前跟OAuth2.0中的一些概念对齐。

  • 用户 -> EndUser:即最终使用系统的人,如你和我;
  • 浏览器 -> UserAgent:用户通过 UserAgent 跟我们的系统打交道,Web 系统最常见的 UserAgent 当然是浏览器,也有一些 APP 通过 WebView 套壳能实现类似的能力;
  • 认证要素 -> Credencials:认证要素,用于识别用户的身份。最常见要素是用户名密码,其它诸如指纹、人脸等生物特征也得到了广泛的应用;
  • 登录令牌 -> Token:一段安全生成的、随机且唯一的字符串,用作用户登录后的凭据。比如我们都很熟悉的SessionID,就是登录令牌的一种典型表现;
  • 服务端 -> Server:用户所属系统的服务端,存有用户的认证要素、数据等敏感信息;

按名词填充后的流程图:
配图2

4. 数据安全等级和开放系统

4.1. 构造基础系统

我们来尝试构造一个系统,用于解释后续的各类场景。我们以手机银行 APP为例,假设该系统具有以下四个接口:

序号接口数据安全等级
1查询银行网点不涉及敏感信息,对任何人均可见
2查询银行理财产品需要登录才能查看,但不涉及用户级敏感数据
3查询用户账户列表和余额需登录才能查看,涉及用户级敏感数据,仅用户本人可见
4跨行转账需登录及二次验证,涉及用户级敏感数据,仅用户本人可操作

4.2. 数据安全等级对认证授权的影响

我们考虑下,如果我们就是这家银行的开发人员,如果要保证这几个接口的安全性,可以实现吗?
答案是当然可以。基于现有经验,很简单对不对?

  1. 用户打开手机银行 APP后,在 APP 首页的某个地方可以看到查询银行网点的按钮,点击后即可查询到附近的网点信息,无需用户登录
  2. 当用户点击理财产品页的时候,由于理财产品列表的接口不是对所有人可见的,这时候手机银行 APP会先弹出登录界面,等用户输入认证要素(用户名密码、指纹、人脸等)登录完成后,才能看到所有理财产品列表;
  3. 当用户要查询账号列表和余额时,除一定要登陆外,还可以看到账号或者余额的一部分信息会以星号显示(如账号会显示为 6225****0000),这是银行为防止用户敏感信息泄露,采取了数据脱敏处理;
  4. 当用户需要进行跨行转账操作时,除一定要登录外,还需要额外通过手机验证码、交易密码、指纹等方式进行二次认证,成功后才可以进行本次转账操作;

我们可以看到,对于手机银行 APP而言,即便是同一系统的不同接口,由于接口涉及的数据的安全等级不同,需要采取的安全策略也不同,数据安全等级要求越高,对相关接口的采取的安全策略就会越复杂。

4.3. 开放系统间授权

我们再来进行一些扩展,考虑当手机银行 APP需要跟其他第三方应用产生交互的场景。

  • 场景一:假设公司A推出一款理财 APP,想要调用我们手机银行 APP的“查询银行理财产品”的接口,应该怎么实现?
  • 场景二:还是这款理财 APP,还想调用我们手机银行 APP的“查询用户账户列表和余额”接口,应该怎么实现,跟场景一有什么区别?
  • 场景三:假设公司B推出一款个人资产概览的小程序,其业务很简单,就是查询用户在各家银行的账户余额,将余额汇总计算后展示给用户。该小程序的特点是没有自己的后台系统,仅通过前端的JavaScript代码调用各银行的“查询用户账户列表和余额”接口即可,应该怎么实现?

按照之前的设定,我们是手机银行 APP的开发人员,现在产品找到我们并要求我们能支持上述三个场景。接下来,我们来进行头脑风暴,看看这三个场景分别有什么特点,是需要我们注意的。

4.3.1. 场景一讨论区
  • 程序员小A:如果公司A理财 APP要调用我们的“查询银行理财产品”的接口,这个接口是需要鉴权的,我们现有手机银行 APP的认证授权使用的是用户名密码的认证要素,要不然我们也把公司A作为一个普通的用户来处理,给他分配用户名密码,让理财 APP也以这种模式登录,认证完成之后就可以以普通用户的身份来调用“查询银行理财产品”接口了,这样可以吗?
  • 架构师大B:这是一种比较自然的解决思路,听起来是能实现功能的,但放在我们手机银行 APP的场景下似乎无法落地,你想想为什么?
  • 程序员小A:嗯…我知道了,普通用户在开通我们手机银行之前,需要先办理银行卡,在场景一里,公司A只是想调用理财相关的接口,强制他去办卡似乎不太合理…
    架构师大B:没错,你抓到了一个重点。除此之外,还会对其他业务有影响吗?
  • 程序员小A:嗯…我再想想,即便要求公司A去办卡,也成功开通手机银行 APP,但公司A因为业务原因,其关联的手机银行用户长期都不会有动账交易(取款、转账、缴费等),这可能会被我们系统识别为僵尸用户,最终被冻结处理。
  • 架构师大B:是的,类似这样的情况其实还很多,原因是公司A理财 APP本质上并不是一个真实的用户,但在你的方案里将他们混为一谈了,看似“巧妙”的解决了鉴权的问题,实则会引发一系列的业务矛盾。
  • 程序员小A:您说得对,那我们应该如何做?
  • 架构师大B:很简单,将普通用户和第三方应用概念上拆开。对普通用户,我们仍然存放入user表,分配 username 和 password 用于鉴权;对公司A理财 APP这样的第三方应用,我们存放入client表,分配client_idclient_secret用于鉴权。
  • 程序员小A:好的,我理解了,这样在我们系统中就可以将第三方应用独立处理了,不会影响到普通用户的逻辑。
4.3.2. 场景二讨论区
  • 程序员小A:咦,产品是不是搞错了,场景二和场景一不是一样的吗,为什么要单独提需求?我去找他去。
  • 架构师大B:别,你先坐下,场景二里公司A理财 APP要调用的是“查询用户账户列表和余额”接口,你仔细想想,这个接口跟之前的“查询银行理财产品”有什么区别吗?
  • 程序员小A:哦,你提醒我了,我知道了,这个接口涉及用户敏感数据!!!
  • 架构师大B:是的,还好你想起来了,不管我们做任何系统,一定要谨记,对于用户敏感的数据,虽然是存放在我们手机银行 APP的数据库中,但我们并没有权限绕开用户将这些数据直接提供给公司A使用,这是违法的。在将这些用户敏感数据提供给第三方公司使用时,必须要先征得用户同意,你知道什么是用户同意吗?
  • 程序员小A:这个我知道,就好比我在王者荣耀中想要向游戏好友展示我的微信头像,但是对于微信而言,微信头像和用户的公开信息是属于用户的数据,微信没有权限直接将这些信息提供给王者荣耀使用。所以在流程上,王者荣耀 APP 会先唤起微信 APP,微信 APP 会弹出一个用户告知的界面,告诉我王者荣耀想要使用我的微信头像,问我允不允许,这个征询的过程,就是“用户同意”。
  • 架构师大B:没错,没想到你连这个也知道,真是让我刮目相看!
    配图三
4.3.3. 场景三讨论区
  • 程序员小A:场景一和场景二算是理解了,但场景三这个需求我又有点懵了,不都是调用“查询用户账户列表和余额”接口吗,和场景二难道有区别?
  • 架构师大B:是的,有区别,但这个区别不在我们,在他们,你想想为什么?
  • 程序员小A:他们?我能看出来,这个公司B个人资产概览小程序有点特殊,他没有后台,是纯H5的应用,但这对我们而言能有什么影响呢?
  • 架构师大B:会有影响,你结合场景一和场景二想一想,公司B个人资产概览小程序对我们手机银行 APP 而言,他是算user(普通用户)还是client(第三方应用)?
  • 程序员小A:这个小程序需要查我们系统很多普通用户的账户余额,显然应该算是client
  • 架构师大B:对,对于client而言,我们会给他分配client_idclient_secret用于鉴权,没错吧,你想想对于公司B个人资产概览小程序而言,他怎么实现这个鉴权的功能?
  • 程序员小A:哦…我知道了,对于公司A理财 APP,这个client_idclient_secret可以存储在他的后端服务器上,这样是可以保证这个认证要素的安全性。但对于公司B个人资产概览小程序,他是没有后端服务器的纯H5的应用,他没有任何手段可以让这个认证要素不泄露出去(PS:H5应用运行在浏览器上,如果将client_idclient_secret硬编码在JavaScript代码里,是可以轻易被任何人获取到的,所以无法保证其安全性)!
  • 架构师大B:不错,脑子转的挺快的,就是这个原因。所以你看,想要将我们手机银行 APP的接口安全的开放给第三方应用使用,并不是这么容易的事情。不仅需要考虑接口的数据特征,比如是否涉及用户敏感数据等,还需要考虑第三方应用的特征,比如他是否有能力保障认证要素的安全性,等等。
  • 程序员小A:是的,现在想起来,我一开始想用用户名密码来解决所有这些场景的想法,实在是太粗浅了。那对于这些问题,有什么一劳永逸的解决方案吗?
  • 架构师大B:当然,用OAuth2.0!!!

5. 名词再次统一

讨论到这里,我们引入了一个重要的主体,就是client,这个主体在OAuth2.0中非常重要,所以我们单独提出来,加深印象。

  • 第三方应用 -> Client:即需要调用资源所有者系统接口的第三方应用;
    • Confidential Clients:私密应用,能够保障其凭证的保密性(在安全的服务器上部署的应用,对其凭证的访问受到限制。如公司A理财 APP,其凭据可以存放在后端服务器上,相对安全);
    • Public Clients:公开应用,无法保障其凭证的保密性(本地应用或基于 web 浏览器的应用。如公司B个人资产概览小程序,其凭据只能存放在前端,非常不安全);

6. 小结

花了很大的篇幅,我们终于意识到由于数据安全等级不同、开放系统间授权场景不同,对认证授权系统也提出了更多的要求。传统意义上的用户名密码并不是银弹,他没有办法解决上述场景下的各种问题,但同时我们也明确的知道,上述的问题并非是无解的,对于这些问题的解,就是OAuth2.0

所以再下一篇文章中,我们就要进入正题,聊聊复杂场景下的授权体系:OAuth2.0

如果觉得有帮助,请关注我的微信公众号

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值