现代身份指南
Search…
⌃K

第五章 API安全的成熟度模型

学习身份的目的除了是保护身份本身,更重要的也是保护程序的API。现代应用程序通常是围绕API设计的,API可以让多个不同应用程序能够重用相同业务逻辑,以此加快创新和新业务的上线。API提供对有价值的数据或服务的访问,因此API通常需要限制对应用的访问。因此,应用程序需要正确的授权才能调用API。除了应用程序自身要调用API,如果应用程序需要代表用户调用API来访问用户拥有的资源,则它需要用户的授权同意。在过去,用户常常必须与应用程序共享他们的凭据才能代表他们启用这样的API调用,这给了应用程序不必要的访问量,同时也增加了对于用户凭据泄漏的风险,增加了应用安全负担。正式基于此,OAuth2.0框架为授权应用程序调用 API提供了更为优雅的方式。在后续章节详解介绍身份Oauth2.0和OIDC协议以前,本章将详细引入这两个协议的背景——API安全的演进。
如第三章介绍,布莱恩·库克为了开发Twitter 与社交书签网站的API之间调用,因而发起了关于API授权的讨论和草案的起草,这为现代的API授权思想奠定了基础。

API安全成熟度模型

事实上,API的安全的演进也并非一触而就,也经历了一系列的演进。参考Richardson RMM( API成熟度模型),该模型概述了Web API服务开发成熟度的四个层级。相对应的,从安全角度,构建了API的安全成熟度模型。在这个模型中,随着等级升高,安全性和信任度就越高。
  • Level 0: API 密钥和基础认证 ,API Keys and Basic Authentication
  • Level 1: 基于令牌的认证,Token-Based Authentication
  • Level 2: 基于令牌的授权,Token-Based Authorization
  • Level 3: 基于声明的集中式信任,Centralized Trust Using Claims
5-1 API Security Model.png

Level 0 API密钥和基础认证

级别0的API使用基本身份验证或API密钥来验证API调用。这些值插入在API请求的URL的标头(Header)或正文(Body)中。大多数早期的API都采用这种方式。
例如,一个电子商务商店的应用,它根据用户购买情况对付款API进行API调用。它将身份验证以标头中的API密钥或基本身份验证的形式发送给应用程序,并将其传递给API。将用户的ID放在正文或URL中。在下面的示例中,有两类API:账单类和商品类。由于采用HTTP基本身份验证或API密钥方式,API仅对“商店应用”进行身份验证,因此“商店应用”必须向API传递用户数据。
5-2 Level0.jpg

Level0 缺点

这个方式实际上是非常基本的方法,没有对于安全的考量。首先,密钥在每次API的访问过程中都携带,这样极为容易泄漏。另外,API密钥验证只是对于(商店应用)机器验证,对用户的身份没有是否篡改的校验,容易被利用。最后,这种方式仅提供了应用的身份验证,即证明断言的行为,而没有包含授权的相关信息。

Level 1: 基于令牌的认证 Token-based Authentication

级别1的API在基于令牌的体系结构中利用访问令牌(Access Token)进行身份验证。访问令牌中的信息可以包含用户的类型(机器,应用程序,用户等)。通过启用特权访问,能够有效的对内部和外部用户的安全级别进行分离,有效的帮助提升安全性。同时,因为用户身份是请求的一部分,便于更好的审计。
例如,继续上面的用例,考虑在电子商店中使用基于访问令牌的身份验证。在此场景下,如果API同时需要支持2个应用的调用,即,除了商店应用以外,还有内部的管理后台时,就会非常的明显。即需要使用自定义逻辑来了解该请求是属于具有特权的后台请求,还是来自外部网络用户对于该网上商店的请求。
5-2 Level1.jpg

Level 1的缺点:

在等级1,拥有令牌的任何人都可以修改API,提供了便捷的同时,也意味着特权访问的令牌的风险更高,如果被黑将带来巨大的风险。此外,级别1仅仅涵盖身份验证,而不涉及授权。换句话说,没有策略去限制应用允许做什么不允许做什么?此外,对令牌进行身份验证时,所有授权访问,需要通过自定义代码实现,诸如if语句之类的自定义编码,这无异将权限和业务耦合在了一起。
在第2级和第3级中对此种情况进行了否定,改进的方案可以使用令牌的数据直接进行授权,从而生成授权的逻辑,而无需再业务中去耦合授权控制的逻辑。

Level 2: 基于令牌的授权 Token-based Authorization

为了解决以上级别1的缺陷,在令牌的设计上,级别2在基于令牌认证的体系结构上,引入了授权机制。即,通过描述请求方的特权,询问请求方将被允许做什么?这一思想被应用到Oauth2.0中,作为一种广泛采用的授权标准。
OAuth最大的亮点是在token中包含了作用范围(标准中定义为Scope),范围Scope可以在授权令牌中包含“指定的权限”,即作用范围可以指定用户权限。 这一优点在后续的协议中又得以进一步的规范,如后续的OpenID Connect定义了一组标准的[作用范围],即可以用来生成标准的身份参数。当然,开发者除了标准范围以外,也可以创建[自定义范围]用于自己开发的API。范围可以根据开发者需求包含更多和授权相关的数据,以用于后续的API的授权,这比“ if”语句的编码方式要更为友好和优雅。
这时,让我们再次回顾我们的电子商店的案例。现在,我们引入了通过范围进行授权,因此可以更加容易的实现公共网络的商店和后台可以具有不同的特权。比如,只有管理后台应用才能获取添加商品(AddProduct)的权限。这就有效的区分了不同应用的权限。
但是,此种方案仍然没有尽善尽美,在这个场景下,依然存在些问题。比如,商店应用和管理后台的的某些操作会出现重叠。比如,使用Scope为LIST,用于在账单API中列出发票。 列出发票的ID被包含在URL或作为传递的参数,作为该API的请求参数。因此,可能会出现恶意越权的情况,即一个用户可以操纵窜給传递的ID参数以列出另一个用户的发票。因此,仅仅使用范围是不够的,范围Scope锁定了客户端应用程序被允许做什么操作,但对于对特定用户被允许操作哪些数据没有帮助,因为它们只包含了参数的“名称”,而没有限定“值”。而是应使用Claims,以便将参数“铸造”到令牌中。然后程序就可以很容易地将后台应用特权与公共网络商店应用的特权分开。
5-2 Level2.jpg

Level 2的缺点:

级别2的问题:级别2中的一个问题是系统面临着反编译的威胁。如果将身份的信息直接放在在API参数中,通过对于API的访问进行逆向,其中的逻辑错误很容易被发现和利用。 另外,级别2中引入了更高的系统复杂度,因为某些API请求参数可能会依赖其他API响应或其他条件。如果,一个API调用另一个API时失败了,或者,如果数据请求参数中包含了错误,怎么办?我们不能假设数据从一个API传递到下一个API总是正确的。这些现实问题可能会导致一系列的级联信任问题,这种“意大利面条式的信任”,有可能让系统变成一团糟。

Level 3: 基于声明的集中式信任,Centralized Trust Using Claims

通过对以上各级的问题的总结,最终API的安全计划到第3级,可以认为是目前最完善的API安全思想和实践。这种实践引入了使用Claims和签名的JSON Web令牌(JWT)进行集中式信任。
同时,授权的服务作为一项独立的服务,客户端向授权服务器进行请求授权,将授权与业务进行分离,它定义了不同的流来获取令牌,客户端从而能够在不需要知道用户凭证的情况下授予对资源的访问权。通过这样做,我们解决上述所有问题。
什么是JWT?澄清下常见的对于JWT的误解,JWT不是一种协议。JWT是一种使用了签名的数据。 OAuth协议中使用JWT验证交易。 JWT可以用来共享范围和声明?声明本质上是一种断言。例如,如下声明:“特拉维斯(Travis)说雅各布(Jacob)是一位身份专家。”此声明具有声明方(Travis),被声明的主体(Jacob),和主体的属性(身份专家)。如果您信任Travis,那么您相信此声明。主体的身份可以由许多属性可以组成,例如“主体”属性名称,年龄,身高,体重等。对于这些属性,声明方可能为一个官方的机构。当然,也可以有上下文属性,例如情况,时间,位置,天气,等等。与其信任属性本身,不如信任一个可信的声明方。
如果你相信颁发密钥的OAuth授权服务器,那么您可以信任由它签发提出的声明。
至于,验证声明的是未经篡改的真实性,一般流程如下:
1.请求方向声明颁发方发起请求
2.声明颁发方签发返回的声明数据,并用私钥签名
3.请求方携带签名后的声明数据向第三方去请求服务
4.第三方服务使用公钥验证签名合法性
这种方法通过信任令牌的发行者,而不是信任参数本身的方式,有效的解决了各级信任问题。从而达成集中式的授权机制。

本章重点回顾

信任是主观的东西。在设计基于API的安全系统时,我们应该信任密钥、令牌,密码,机器或用户本身吗?答案要比大多数的API设计人员认为的要复杂,但这对于保护您的平台整体至关重要。
本质上,API安全的顶峰是信任声明,而不是属性。如果没有考虑更高级的安全性,如果GitHub存储库中存在重要的密钥,API很容易受到攻击。因此,API提供者必须做出更明智的安全决策,以保护整个平台的完整性。
正如API安全成熟度模型逐步演进所显示的那样,高度成熟的API只信任很少的源,这些演化的API被信任的令牌的发行者逐渐成为独立的服务。这不能保证100%的真实性,但最接近于验证请求方的身份。通过标准逐渐固化信任标准过程,可以消除系统开发者在身份授权的自定义代码上浪费的精力。
事实上,在网络安全领域,很少鼓励你发明自己的授权规则。为了使集中信任发挥作用,授权系统需要使用稳定的协议。就像街道交通规则一样,身份系统也遵循通用协议。需要它们自己的共享开放标准,这些协议就是OAuth和OpenID Connect。利用这些标准,应用程序可以在JWTs中共享安全的断言数据以进行验证。
下一章将详细的介绍OAuth。