互联网架构安全性(一) 认证与授权篇
互联网架构安全性(二) 凭证与保密篇
互联网架构安全性(三) 传输与验证篇
我们谈论的计算机系统安全,不仅仅是指“防御系统被黑客攻击”这样狭隘的安全,与安全相关的问题,一般不会直接创造价值,解决起来又烦琐复杂,费时费力,因此经常性被开发者有意无意地忽略掉。庆幸的是这些问题基本上也都是与具体系统、具体业务无关的通用性问题,这意味着它们往往会存在着业界通行的、已被验证过是行之有效的解决方案,乃至已经形成行业标准,不需要开发者自己从头去构思如何解决。
1. 认证(Authentication)
认证、授权和凭证可以说是一个系统中最基础的安全设计,哪怕再简陋的信息系统,大概也不可能忽略掉“用户登录”功能。信息系统为用户提供服务之前,总是希望先弄清楚“你是谁?”(认证)、“你能干什么?”(授权)。
这两个基本问题又并不像部分开发者认为的那样,只是一个“系统登录”功能,仅仅是校验一下用户名、密码是否正确这么简单。账户和权限信息作为一种必须最大限度保障安全和隐私,同时又要兼顾各个系统模块甚至系统间共享访问的基础主数据,它的存储、管理与使用都面临一系列复杂的问题。
HTTP 认证
认证方案(Authentication Schemes),它是指生成用户身份凭证的某种方法,这个概念最初源于 HTTP 协议的认证框架(Authentication Framework)。IETF 在 RFC 7235 中定义了 HTTP 协议的通用认证框架,要求所有支持 HTTP 协议的服务器,在未授权的用户意图访问服务端保护区域的资源时,应返回 401 Unauthorized 的状态码,同时应在响应报文头里附带以下两个分别代表网页认证和代理认证的 Header 之一,告知客户端应该采取何种方式产生能代表访问者身份的凭证信息:
WWW-Authenticate: <认证方案> realm=<保护区域的描述信息>
Proxy-Authenticate: <认证方案> realm=<保护区域的描述信息>
接收到该响应后,客户端必须遵循服务端指定的认证方案,在请求资源的报文头中加入身份凭证信息,由服务端核实通过后才会允许该请求正常返回,否则将返回 403 Forbidden 错误。请求头报文应包含以下 Header 项之一:
Authorization: <认证方案> <凭证内容>
Proxy-Authorization: <认证方案> <凭证内容>
HTTP 认证框架提出认证方案是希望能把认证“要产生身份凭证”的目的与“具体如何产生凭证”的实现分离开来,无论客户端通过生物信息(指纹、人脸)、用户密码、数字证书抑或其他方式来生成凭证,都属于是如何生成凭证的具体实现,都可以包容在 HTTP 协议预设的框架之内。

以上概念性的介绍可能会有些枯燥抽象,下面笔者将以最基础的认证方案——HTTP Basic 认证为例来介绍认证是如何工作的。HTTP Basic 认证是一种主要以演示为目的的认证方案,也应用于一些不要求安全性的场合,譬如家里的路由器登录等。Basic 认证产生用户身份凭证的方法是让用户输入用户名和密码,经过 Base64 编码“加密”后作为身份凭证。譬如请求资源GET /admin
后,浏览器会收到来自服务端的如下响应:
HTTP/1.1 401 Unauthorized
Date: Mon, 24 Feb 2022 16:50:53 GMT
WWW-Authenticate: Basic realm="example from xxx.com"
此时,浏览器必须询问最终用户,即弹出类似如图所示的 HTTP Basic 认证对话框,要求提供用户名和密码。

用户在对话框中输入密码信息,譬如输入用户名baicai
,密码123456
,浏览器会将字符串baicai:123456
编码为aWN5ZmVuaXg6MTIzNDU2
,然后发送给服务端,HTTP 请求如下所示:
GET /admin HTTP/1.1
Authorization: Basic aWN5ZmVuaXg6MTIzNDU2
服务端接收到请求,解码后检查用户名和密码是否合法,如果合法就返回/admin
的资源,否则就返回 403 Forbidden 错误,禁止下一步操作。注意 Base64 只是一种编码方式,并非任何形式的加密,所以 Basic 认证的风险是显而易见的。除 Basic 认证外,IETF 还定义了很多种可用于实际生产环境的认证方案,列举如下。
-
Digest:HTTP 摘要认证,可视为 Basic 认证的改良版本,针对 Base64 明文发送的风险,Digest 认证把用户名和密码加盐(一个被称为 Nonce 的变化值作为盐值)后再通过 MD5/SHA 等哈希算法取摘要发送出去。但是这种认证方式依然是不安全的,无论客户端使用何种加密算法加密,无论是否采用了 Nonce 这样的动态盐值去抵御重放和冒认,遇到中间人攻击时依然存在显著的安全风险。 -
Bearer:基于 OAuth 2 规范来完成认证,OAuth2 是一个同时涉及认证与授权的协议,在“授权”小节将详细介绍 OAuth 2。 -
HOBA:(HTTP Origin-Bound Authentication)是一种基于自签名证书的认证方案。基于数字证书的信任关系主要有两类模型:一类是采用 CA(Certification Authority)层次结构的模型,由 CA 中心签发证书;另一种是以 IETF 的 Token Binding 协议为基础的 OBC(Origin Bound Certificate)自签名证书模型。
Web 认证
以 HTTP 协议为基础的认证框架也只能面向传输协议而不是具体传输内容来设计,如果用户想要从服务器中下载文件,弹出一个 HTTP 服务器的对话框,让用户登录是可接受的;但如果用户访问信息系统中的具体服务,身份认证肯定希望是由系统本身的功能去完成的,而不是由 HTTP 服务器来负责认证。这种依靠内容而不是传输协议来实现的认证方式,在万维网里被称为“Web 认证”,由于实现形式上登录表单占了绝对的主流,因此通常也被称为“表单认证”(Form Authentication)。
表单认证与 HTTP 认证不见得是完全对立的,两者有不同的关注点,可以结合使用。
2019 年 3 月,万维网联盟(World Wide Web Consortium,W3C)批准了由FIDO(Fast IDentity Online,一个安全、开放、防钓鱼、无密码认证标准的联盟)领导起草的世界首份 Web 内容认证的标准“WebAuthn”, WebAuthn 彻底抛弃了传统的密码登录方式,改为直接采用生物识别(指纹、人脸、虹膜、声纹)或者实体密钥(以 USB、蓝牙、NFC 连接的物理密钥容器)来作为身份凭证,从根本上消灭了用户输入错误产生的校验需求和防止机器人模拟产生的验证码需求等问题,甚至可以省掉表单界面,所以这个规范不关注界面该是什么样子、要不要验证码、是否要前端校验这些问题。
WebAuthn 相对复杂,硬件方面,要求用带有 Touch ID 的 MacBook,或者其他支持指纹、FaceID 验证的手机(目前在售的移动设备基本都带有生物识别装置)。软件方面,直至 iOS 13.6,iPhone 和 iPad 仍未支持 WebAuthn,但 Android 和 Mac OS 系统中的 Chrome,以及 Windows 的 Edge 浏览器都已经可以正常使用 WebAuthn 了。如图展示了使用 WebAuthn 登录不同浏览器的操作界面。

WebAuthn 规范涵盖了“注册”与“认证”两大流程,先来介绍注册流程,它大致可以分为以下步骤:
用户进入系统的注册页面,这个页面的格式、内容和用户注册时需要填写的信息均不包含在 WebAuthn 标准的定义范围内。 当用户填写完信息,点击“提交注册信息”的按钮后,服务端先暂存用户提交的数据,生成一个随机字符串(规范中称为 Challenge)和用户的 UserID(在规范中称作凭证 ID),返回给客户端。 客户端的 WebAuthn API 接收到 Challenge 和 UserID,把这些信息发送给验证器(Authenticator),验证器可理解为用户设备上 TouchID、FaceID、实体密钥等认证设备的统一接口。 验证器提示用户进行验证,如果支持多种认证设备,还会提示用户选择一个想要使用的设备。验证的结果是生成一个密钥对(公钥和私钥),由验证器存储私钥、用户信息以及当前的域名。然后使用私钥对 Challenge 进行签名,并将签名结果、UserID 和公钥一起返回客户端。 浏览器将验证器返回的结果转发给服务器。 服务器核验信息,检查 UserID 与之前发送的是否一致,并用公钥解密后得到的结果与之前发送的 Challenge 相比较,一致即表明注册通过,由服务端存储该 UserID 对应的公钥。

登录流程与注册流程类似,如果你理解了注册流程,就很容易理解登录流程了。登录流程大致可以分为以下步骤:
用户访问登录页面,填入用户名后即可点击登录按钮。 服务器返回随机字符串 Challenge、用户 UserID。 浏览器将 Challenge 和 UserID 转发给验证器。 验证器提示用户进行认证操作。由于在注册阶段验证器已经存储了该域名的私钥和用户信息,所以如果域名和用户都相同的话,就不需要生成密钥对了,直接以存储的私钥加密 Challenge,然后返回给浏览器。 服务端接收到浏览器转发来的被私钥加密的 Challenge,以此前注册时存储的公钥进行解密,如果解密成功则宣告登录成功。
WebAuthn 采用非对称加密的公钥、私钥替代传统的密码,这是非常理想的认证方案,私钥是保密的,只有验证器需要知道它,连用户本人都不需要知道,也就没有人为泄漏的可能;公钥是公开的,可以被任何人看到或存储。公钥可用于验证私钥生成的签名,但不能用来签名,除了得知私钥外,没有其他途径能够生成可被公钥验证为有效的签名,这样服务器就可以通过公钥是否能够解密来判断最终用户的身份是否合法。
WebAuthn 还一揽子地解决了传统密码在网络传输上的风险,无论密码是否客户端进行加密、如何加密,对防御中间人攻击来说都是没有意义的。更值得夸赞的是 WebAuthn 为登录过程带来极大的便捷性,不仅注册和验证的用户体验十分优秀,而且彻底避免了用户在一个网站上泄漏密码,所有使用相同密码的网站都受到攻击的问题,这个优点使得用户无须再为每个网站想不同的密码。
2. 授权( Authorization)
授权行为在程序中的应用非常广泛,给某个类或某个方法设置范围控制符(public、protected、private、
)在本质上也是一种授权(访问控制)行为。而在安全领域中所说的授权就更具体一些,通常涉及以下两个相对独立的问题:
-
确保授权的过程可靠:对于单一系统来说,授权的过程是比较容易做到可控的,以前很多语境上提到授权,实质上讲的都是访问控制,理论上两者是应该分开的。而在涉及多方的系统中,授权过程则是一个比较困难却必须严肃对待的问题:如何既让第三方系统能够访问到所需的资源,又能保证其不泄露用户的敏感数据呢?常用的多方授权协议主要有 OAuth2 和 SAML 2.0(两个协议涵盖的功能并不是直接对等的)。 -
确保授权的结果可控:授权的结果用于对程序功能或者资源的 [访问控制](Access Control),成理论体系的权限控制模型有很多,譬如 [自主访问控制](Discretionary Access Control,DAC)、[强制访问控制](Mandatory Access Control,MAC)、[基于属性的访问控制](Attribute-Based Access Control,ABAC),还有最为常用的 [基于角色的访问控制](Role-Based Access Control,RBAC)。
RBAC(Role-Based Access Control)
所有的访问控制模型,实质上都是在解决同一个问题:“谁(User)拥有什么 权限(Authority)去 操作(Operation)哪些 资源(Resource)”。
这个问题初看起来并不难,一种直观的解决方案就是在用户对象上设定一些权限,当用户使用资源时,检查是否有对应的操作权限即可。不过,这种把权限直接关联在用户身上的简单设计,在复杂系统上确实会导致一些比较烦琐的问题。试想一下,如果某个系统涉及到成百上千的资源,又有成千上万的用户,一旦两者搅合到一起,要为每个用户访问每个资源都分配合适的权限,必定导致巨大的操作量和极高的出错概率,这也正是 RBAC 所关注的问题之一。
RBAC 模型在业界中有多种说法,其中以美国 George Mason 大学信息安全技术实验室提出的 RBAC96 模型最具有系统性,得到普遍的认可。为了避免对每一个用户设定权限,RBAC 将权限从用户身上剥离,改为绑定到“角色”(Role)上,将权限控制变为对“ 角色 拥有操作哪些 资源 的 许可 ”这个逻辑表达式的值是否为真的求解过程。

许可是抽象权限的具象化体现,权限在 RBAC 系统中的含义是“允许何种 操作 作用于哪些 资源 之上”,这句话的具体实例即为“许可”。提出许可这个概念的目的其实与提出角色的目的是完全一致的,只是更为抽象。角色为的是解耦用户与权限之间的多对多关系,而许可为的是解耦操作与资源之间的多对多关系,譬如不同的数据都能够有增、删、改等操作,如果将数据与操作搅和在一起也会面临配置膨胀问题。
采用 RBAC 不仅是为了简化配置操作,还天然地满足了计算机安全中的“[最小特权原则]”(Least Privilege)。在 RBAC 模型中,角色拥有许可的数量是根据完成该角色工作职责所需的最小权限来赋予的,最典型例子是操作系统权限管理中的用户组,根据对不同角色的职责分工,如管理员(Administrator)、系统用户(System)、验证用户(Authenticated Users)、普通用户(Users)、来宾用户(Guests)等分配各自的权限,既保证用户能够正常工作,也避免用户出现越权操作的风险。当用户的职责发生变化时,在系统中就体现为它所隶属的角色被改变,譬如将“普通用户角色”改变“管理员角色”,就可以迅速让该用户具备管理员的多个细分权限,降低权限分配错误的风险。
RBAC1
RBAC 还允许对不同角色之间定义关联与约束,进一步强化它的抽象描述能力。如不同的角色之间可以有继承性,典型的是 RBAC-1 模型的角色权限继承关系。譬如描述开发经理应该和开发人员一样具有代码提交的权限,描述开发人员都应该和任何公司员工一样具有食堂就餐的权限,就可以直接将食堂就餐赋予公司员工的角色上,把代码提交赋予到开发人员的角色上,再让开发人员的角色从公司员工派生,开发经理的角色从开发人员中派生即可。
RBAC2
不同角色之间也可以具有互斥性,典型的是 RBAC-2 模型的角色职责分离关系。互斥性要求权限被赋予角色时,或角色被赋予用户时应遵循的强制性职责分离规定。举个例子,角色的互斥约束可限制同一用户只能分配到一组互斥角色集合中至多一个角色,譬如不能让同一名员工既当会计,也当出纳,否则资金安全无法保证。角色的基数约束可限制某一个用户拥有的最大角色数目,譬如不能让同一名员工从产品、设计、开发、测试全部包揽,否则产品质量无法保证。
垂直权限 和 水平权限
建立访问控制模型的基本目的是为了管理垂直权限和水平权限。垂直权限即功能权限,譬如前面提到的审稿编辑有通过审核的权限、开发经理有代码提交的权限、出纳有从账户提取资金的权限,这一类某个角色完成某项操作的许可,都可以直接翻译为功能权限。由于实际应用与权限模型具有高度对应关系,将权限从具体的应用中抽离出来,放到通用的模型中是相对容易的,Spring Security、Apache Shiro 等权限框架就是这样的抽象产物,大多数系统都能采用这些权限框架来管理功能权限。
与此相对,水平权限即数据权限管理起来则要困难许多。譬如用户 A、B 都属于同一个角色,但它们各自在系统中产生的数据完全有可能是私有的,A 访问或删除了 B 的数据也照样属于越权。一般来说,数据权限是很难抽象与通用的,仅在角色层面控制并不能满足全部业务的需要,很多时候只能具体到用户,甚至要具体管理到发生数据的某一行、某一列之上,因此数据权限基本只能由信息系统自主来来完成,并不存在能放之四海皆准的通用数据权限框架。
Spring Security 的访问控制模型
Spring Security 的设计里,用户和角色都可以拥有权限,譬如在它的 HttpSecurity 接口就同时有着 hasRole()和 hasAuthority()方法,可能刚接触的程序员会疑惑,混淆它们之间的关系。Spring Security 的访问控制模型如图所示,可与前面 RBAC 的关系图对比一下。

从实现角度来看,Spring Security 中的 Role 和 Authority 的差异很小,它们完全共享同一套存储结构,唯一的差别仅是 Role 会在存储时自动带上“ROLE_”前缀罢了。但从使用角度来看,Role 和 Authority 的差异可以很大,用户可以自行决定系统中到底 Permission 只能对应到角色身上,还是可以让用户也拥有某些角色中没有的权限。
OAuth2(开放授权)
OAuth2 是在RFC 6749中定义的国际标准,在 RFC 6749 正文的第一句就阐明了 OAuth2 是面向于解决第三方应用(Third-Party Application)的认证授权协议。
如果我们单体架构中就既不为第三方提供服务,也不使用第三方的服务,那引入 OAuth2 其实并无必要。为什么强调第三方?在多方系统授权过程具体会有什么问题需要专门制订一个标准协议来解决呢?笔者举个现实的例子来解释。
-
密码泄漏:如果 Travis-CI 被黑客攻破,将导致我的 GitHub 的密码也同时被泄漏。 -
访问范围:Travis-CI 将有能力读取、修改、删除、更新我放在 GitHub 上的所有代码仓库,而我并不希望它能够修改删除文件。 -
授权回收:只有修改密码才能回收我授予给 Travis-CI 的权力,可是我在 GitHub 的密码只有一个,授权的应用除了 Travis-CI 之外却还有许多,修改了意味着所有别的第三方的应用程序会全部失效。
以上列举的这些问题,也正是 OAuth2 所要解决的问题,尤其是要求第三方系统没有支持 HTTPS 传输安全的环境下依然能够解决这些问题,这并非易事。
OAuth2 给出了多种解决办法,这些办法的共同特征是以令牌(Token)代替用户密码作为授权的凭证。有了令牌之后,哪怕令牌被泄漏,也不会导致密码的泄漏;令牌上可以设定访问资源的范围以及时效性;每个应用都持有独立的令牌,哪个失效都不会波及其他。这样上面提出的三个问题就都解决了。有了一层令牌之后,整个授权的流程如图所示。

这个时序图里面涉及到了 OAuth2 中几个关键术语,我们通过前面那个具体的上下文语境来解释其含义,这对理解后续几种认证流程十分重要:
-
第三方应用(Third-Party Application):需要得到授权访问我资源的那个应用,即此场景中的“Travis-CI”。 -
授权服务器(Authorization Server):能够根据我的意愿提供授权(授权之前肯定已经进行了必要的认证过程,但它与授权可以没有直接关系)的服务器,即此场景中的“GitHub”。 -
资源服务器(Resource Server):能够提供第三方应用所需资源的服务器,它与认证服务可以是相同的服务器,也可以是不同的服务器,此场景中的“我的代码仓库”。 -
资源所有者(Resource Owner):拥有授权权限的人,即此场景中的“我”。
“用令牌代替密码”确实是解决问题的好方法,但这充其量只能算个思路,距离可实施的步骤还是不够具体的,时序图中的“要求/同意授权”、“要求/同意发放令牌”、“要求/同意开放资源”几个服务请求、响应该如何设计,这就是执行步骤的关键了。对此,OAuth2 一共提出了四种不同的授权方式:
授权码模式(Authorization Code) 隐式授权模式(Implicit) 密码模式(Resource Owner Password Credentials) 客户端模式(Client Credentials)
授权码模式(第三方应用授权)
授权码模式是四种模式中最严谨的,它考虑到了几乎所有敏感信息泄漏的预防和后果。

-
操作代理(User Agent):指用户用来访问服务器的工具,对于人类用户来说,这个通常是指浏览器,但在微服务中一个服务经常会作为另一个服务的用户,此时指的可能就是 HttpClient、RPCClient 或者其他访问途径。
开始进行授权过程以前,第三方应用先要到授权服务器上进行注册,所谓注册,是指向认证服务器提供一个域名地址,然后从授权服务器中获取 ClientID 和 ClientSecret,以便能够顺利完成如下授权过程:
第三方应用将资源所有者(用户)导向授权服务器的授权页面,并向授权服务器提供 ClientID 及用户同意授权后的回调 URI,这是一次客户端页面转向。 授权服务器根据 ClientID 确认第三方应用的身份,用户在授权服务器中决定是否同意向该身份的应用进行授权,用户认证的过程未定义在此步骤中,在此之前应该已经完成。 如果用户同意授权,授权服务器将转向第三方应用在第 1 步调用中提供的回调 URI,并附带上一个授权码和获取令牌的地址作为参数,这是第二次客户端页面转向。 第三方应用通过回调地址收到授权码,然后将授权码与自己的 ClientSecret 一起作为参数,通过服务器向授权服务器提供的获取令牌的服务地址发起请求,换取令牌。该服务器的地址应与注册时提供的域名处于同一个域中。 授权服务器核对授权码和 ClientSecret,确认无误后,向第三方应用授予令牌。令牌可以是一个或者两个,其中必定要有的是访问令牌(Access Token),可选的是刷新令牌(Refresh Token)。访问令牌用于到资源服务器获取资源,有效期较短,刷新令牌用于在访问令牌失效后重新获取,有效期较长。 资源服务器根据访问令牌所允许的权限,向第三方应用提供资源。
-
会不会有其他应用冒充第三方应用骗取授权?
ClientID 代表一个第三方应用的“用户名”,这项信息是可以完全公开的。但 ClientSecret 应当只有应用自己才知道,这个代表了第三方应用的“密码”。在第 5 步发放令牌时,调用者必须能够提供 ClientSecret 才能成功完成。只要第三方应用妥善保管好 ClientSecret,就没有人能够冒充它。
-
为什么要先发放授权码,再用授权码换令牌?
这是因为客户端转向(通常就是一次 HTTP 302 重定向)对于用户是可见的,换而言之,授权码可能会暴露给用户以及用户机器上的其他程序,但由于用户并没有 ClientSecret,光有授权码也是无法换取到令牌的,所以避免了令牌在传输转向过程中被泄漏的风险。
-
为什么要设计一个时限较长的刷新令牌和时限较短的访问令牌?不能直接把访问令牌的时间调长吗?
这是为了缓解 OAuth2 在实际应用中的一个主要缺陷,通常访问令牌一旦发放,除非超过了令牌中的有效期,否则很难(需要付出较大代价)有其他方式让它失效,所以访问令牌的时效性一般设计的比较短,譬如几个小时,如果还需要继续用,那就定期用刷新令牌去更新,授权服务器就可以在更新过程中决定是否还要继续给予授权。
尽管授权码模式是严谨的,但是它并不够好用,这不仅仅体现在它那繁复的调用过程上,还体现在它对第三方应用提出了一个“貌似不难”的要求:第三方应用必须有应用服务器,因为第 4 步要发起服务端转向,而且要求服务端的地址必须与注册时提供的地址在同一个域内。
隐式授权模式(无服务端应用授权)
隐式授权省略掉了通过授权码换取令牌的步骤,整个授权过程都不需要服务端支持,一步到位。代价是在隐式授权中,授权服务器不会再去验证第三方应用的身份,因为已经没有应用服务器了,ClientSecret 没有人保管,就没有存在的意义了。

-
Fragment:
https://juejin.cn/#/page/1 就是 # 号后边的部分 /page/1 Fragment 是用于客户端定位的 URI 从属资源,譬如 HTML 中就可以使用 Fragment 来做文档内的跳转而不会发起服务端请求,此外,RFC 3986 还规定了如果浏览器对一个带有 Fragment 的地址发出 Ajax 请求,那 Fragment 是不会跟随请求被发送到服务端的,只能在客户端通过 Script 脚本来读取。
在时序图所示的交互过程里,隐式模式与授权码模式的显著区别是授权服务器在得到用户授权后,直接返回了访问令牌,这显著地降低了安全性,但 OAuth2 仍然努力尽可能地做到相对安全,譬如在前面提到的隐式授权中,尽管不需要用到服务端,但仍然需要在注册时提供回调域名,此时会要求该域名与接受令牌的服务处于同一个域内。此外,同样基于安全考虑,在隐式模式中明确禁止发放刷新令牌。
密码模式(系统内子模块授权)
前面所说的授权码模式和隐私模式属于纯粹的授权模式,它们与认证没有直接的联系,如何认证用户的真实身份是与进行授权互相独立的过程。但在密码模式里,认证和授权就被整合成了同一个过程了。

密码模式原本的设计意图是仅限于用户对第三方应用是高度可信任的场景中使用,因为用户需要把密码明文提供给第三方应用,第三方以此向授权服务器获取令牌。这种高度可信的第三方是极为较罕见的,尽管介绍 OAuth2 的材料中,经常举的例子是“操作系统作为第三方应用向授权服务器申请资源”,但真实应用中极少遇到这样的情况,合理性依然十分有限。
如果要采用密码模式,那“第三方”属性就必须弱化,把“第三方”视作是系统中与授权服务器相对独立的子模块,在物理上独立于授权服务器部署,但是在逻辑上与授权服务器仍同属一个系统,这样将认证和授权一并完成的密码模式才会有合理的应用场景。
密码模式下“如何保障安全”的职责无法由 OAuth2 来承担,只能由用户和第三方应用来自行保障,尽管 OAuth2 在规范中强调到“此模式下,第三方应用不得保存用户的密码”,但这并没有任何技术上的约束力。
客户端模式(服务间认证授权)
客户端模式是四种模式中最简单的,它只涉及到两个主体,第三方应用和授权服务器。如果严谨一点,现在称“第三方应用”其实已经不合适了,因为已经没有了“第二方”的存在,资源所有者、操作代理在客户端模式中都是不必出现的。甚至严格来说叫“授权”都已不太恰当,资源所有者都没有了,也就不会有谁授予谁权限的过程。

客户端模式是指第三方应用(行文一致考虑,还是继续沿用这个称呼)以自己的名义,向授权服务器申请资源许可。此模式通常用于管理操作或者自动处理类型的场景中。微服务架构并不提倡同一个系统的各服务间有默认的信任关系,所以服务之间调用也需要先进行认证授权,然后才能通信。此时,客户端模式便是一种常用的服务间认证授权的解决方案。
互联网架构安全性(一) 认证与授权篇
互联网架构安全性(二) 凭证与保密篇
互联网架构安全性(三) 传输与验证篇
原文始发于微信公众号(白菜说技术):互联网架构安全性(一) 认证与授权篇
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/39894.html