API安全技术与实战
上QQ阅读APP看书,第一时间看更新

1.3 现代API常用的协议和消息格式

现代API技术的发展要追溯到23000年,在动态网页技术的推动下,大量的企业级应用如雨后春笋般涌现,为了满足不同技术栈构建的应用在架构和开发上能平滑融合和解耦,API技术也得到了快速的发展。

1.3.1 REST成熟度模型

现代API的奠基人Roy Fielding博士在他的论文《架构风格以及基于网络的软件架构设计》(Architectural Styles and the Design of Network-based Software Architectures)中第一次提到REST(Representational State Transfer)概念,其目的是满足现代Web架构的设计与开发的需要;之后,Leonard Richardson提出“REST成熟度模型”,该模型把REST服务按照成熟度划分成4个层次。

■ Level 0:Web服务使用HTTP协议作为传输方式,实际上是远程过程调用(Remote Procedure Call,RPC)的雏形,SOAP和XML-RPC都属于此类,其表现形式为一个URI,一个HTTP方法。例如:

■ Level 1:Web服务引入了资源的概念,每个资源有对应的标识符和表述。其表现形式为多个URI,一个HTTP方法。例如:

■ Level 2:Web服务使用不同的HTTP方法来进行不同的操作,并且使用HTTP状态码来表示不同的结果。如HTTP GET方法来获取资源,HTTP DELETE方法来删除资源,这是当前使用范围最为广泛的层次。其表现形式为多个URI,多个HTTP方法。例如:

■ Level 3:Web服务使用HATEOAS,在资源的表述中包含了链接信息,客户端可以根据链接来发现可以执行的动作。Level 3是比较理想的层级,但目前实际应用较少。

从“REST成熟度模型”中各个层次的含义来看,目前大多数应用基本都停留在Level 1、Level 2的层次,所以在后续讨论RESTful API的章节中,主要是指Level 1、Level 2两个层次。

1.3.2 RESTful API技术

在当前的互联网上,因RESTful API简洁易用,在降低软件开发复杂度的同时,也提高了软件应用的拓展性,从而占据着主流地位。从REST成熟度模型来看,表现形式以Level 2为主,一次RESTful API请求,其典型的消息格式样例如下:

在样例中,包含以下RESTful API相关的协议信息。

■ 资源URL格式为schema://host[:port]/version/path,其中schema是指定使用的应用层协议,比如HTTP、HTTPS、FTP等;host是API服务器的IP地址或域名;port是指API服务器的端口;version是指API请求的版本;path是指API请求资源的路径。

■ 资源请求分配的HTTP请求方法,除了样例中的GET方法外,常用的请求方法还有用于服务器新增数据或资源的POST方法,用于获取资源请求的元数据HEAD方法,用于更新服务器资源的PUT方法,用于删除服务器资源的DELETE方法以及查询与资源相关选项的OPTIONS方法等。不同HTTP请求方法的调用样例如下:

在实际应用中,对于API请求路径的命名通常遵循一定的规范或规律,比如将功能相近的API端点放在一起:

通过这些接口规范性的特征,读者很容易识别出RESTful API类的接口。而作为技术开发者,为了满足这些接口标准,一般采用业界通用API规范。在现行的API规范中,OpenAPI当之无愧排在首位,其官网地址为https://swagger.io/specification/。从其官方文档可以了解到,OpenAPI规范于2015年已捐赠给Linux基金会,其规范内容为RESTful API定义了一个与开发语言无关的标准接口,可通过有效映射与之关联的所有资源和操作,来帮助用户轻松地开发和使用RESTful API。OpenAPI规范中描述REST风格通信消息所采用的MIME类型以JSON格式为主,如图1-10所示。

●图1-10 REST采用的MIME类型

同时,在规范中,关于身份认证与鉴权的安全性支持方案,如APIKey、HTTP Basic、OAuth 2.0等也做出了相应的描述,在后续的API安全设计章节中将为读者做详细的介绍。

1.3.3 GraphQL API技术

GraphQL是Facebook推出的一种基于用户自定义数据类型的API查询语言和现代应用程序对接云服务的全面解决方案,在很多场景下,可以作为REST、SOAP或gRPC的替代方案。

一个典型的GraphQL服务是通过定义类型、类型上的字段、字段的解析函数来对外部提供能力服务的。这里,以用户admin的查询为样例,描述其交互过程。当请求GraphQL服务时,其查询结构为:

这不是JSON格式的数据,但它们很相似,此GraphQL查询的表达含义如下。

通过用户名admin来查询用户信息。

仅查询id、name、address三个字段的信息。

对于通信地址address,需要查询首选地址和备用地址。

而与之对应的服务器响应为:

这个响应的消息结构显示了GraphQL的两个重要的特性。

■ 服务器能理解客户端的要求并根据定义的模式完成查询和响应,这种特性能帮助使用者从技术路线层面解决OWASP API安全中的批量分配问题。而在业务层面,使后端服务的开发人员更多的关注开发,而不用关心业务数据的接口,由前端查询来控制其想获取的字段。

■ 可以嵌套地访问数据资源,在RESTful API如果想查询用户上述信息,则对应的API端点为/v1/user和/v1/user/address,而GraphQL API则一次性完成。这在大型的互联网应用中,可以减少时间成本的消耗。

也正是GraphQL的这些特性,当技术人员尝试使用它时,也有诸多的不便。举例如下。

GraphQL语言自身特有的查询语法需要投入学习成本,且其结构没有JSON直观,在编写过程中需要特定的辅助工具。

为了适应其嵌套查询的特性,需要定义大量的schema,并进行服务器端改造。

嵌套查询对普通关系型数据的服务器性能挑战较大。

1.3.4 SOAP API技术

SOAP API相对于其他的API技术来说,已进入了衰退期,但在企业级应用中,因历史遗留问题仍在普遍使用着。通俗地说,SOAP协议是基于HTTP协议的XML通信技术,主要用于Web Service服务通信。在技术实现上,一个完整的SOAP API由3部分组成:SOAP(简单对象访问协议)、UDDI(Web Services提供信息注册中心的实现标准规范)、WSDL(描述Web Services以及如何对它们进行访问),它们之间的相互关系如图1-11所示。

●图1-11 SOAP API技术的组成

WSDL为服务消费者提供了Web Services接口的详细描述,通过解析WSDL获取调用参数的详细描述后,使用XML格式的数据与服务提供者进行数据交互。

一个典型的SOAP消息,其基本格式如下所示:

其中Envelope和Body为必选节点,Envelope用于标识此消息为SOAP消息,Body包含所有调用和响应的必须信息。这里,通过获取API版本的SOAP消息请求与响应来让读者对SOAP消息有更理性的认识,如下所示。

SOAP请求:用于请求API的版本信息,当获取的API名称为test的API版本时,发送的SOAP消息样例。其中m:GetApiVersionm:ApiName是应用程序业务专用的自定义节点。代码如下所示:

SOAP响应:服务器端对获取API版本信息的响应报文样例,其中m:Version表示版本信息为2.5.0版本。代码如下所示:

1.3.5 gRPC API技术

gRPC是一套高性能、开源的远程调用框架,通过Server/Client模式,使得通信中的各个应用之间像调用本地接口一样调用远程API。在其官网中,对于为什么要使用gPRC有如下描述。

gRPC是可以在任何环境中运行的现代开源高性能RPC框架,它可以通过可插拔方式,有效地支撑数据中心内和跨数据中心的服务连接,以实现负载平衡、跟踪、运行状况检查和身份验证。它同样也适用于分布式计算的“最后一公里”,以将设备、移动应用程序和浏览器连接到后端服务。

在gRPC API中,客户端应用程序通过远程方法调用在其他服务器的应用程序,多个RPC系统之间,围绕API服务的思想,通过协议约定接口参数和返回类型,完成不同服务能力的组合。不同的客户端或服务器端之间,无须考虑编程语言的不同,均参照协议约定远程调用接口,如图1-12所示。

●图1-12 gRPC通信

在客户端与服务器端之间,将数据(比如JSON格式数据)序列化为二进制编码,然后使用Protobuf协议进行通信。gRPC API通常适用于对接口安全性或性能要求较高的场景,比如某个具备管理功能属性的接口,想通过严格的gRPC API约束其调用者的范围,则Protobuf协议恰好满足此需求。

Protobuf协议的消息结构是通过Protocol Buffer Language语言进行定义和描述的,其数据结构描述文件的拓展名是.proto,其样例结构如下:

在使用时,需要先将.proto的文件编译,再序列化,才能在通信中使用。读者可以将其理解为:客户端和服务器端通信时,先将JSON或XML格式的数据使用Protobuf技术转换为二进制流的数据格式,再进行传输。

在表现形式上,gRPC API比RESTful API相对来说具有更好的隐蔽性,同时gRPC API的技术实现中也支持多种安全机制,比如通信链路的SSL/TLS安全协议、X.509数字证书的认证、OAuth协议授权访问、Google令牌认证等。

1.3.6 类XML-RPC及其他API技术

类XML-RPC及其他API技术比较杂乱,以类XML-RPC技术为主,它除了包含XML-RPC的API接口调用外,还有一些以XML为数据格式的信息交换技术,如即时通信的XMPP,在这里,也将这类的接口都归类到类XML-RPC API中。另外,还有一些如JMS、Dubbo之类的接口技术,也归类到这里,做统一的叙述。

下面,一起来看看类XML-RPC API。

XML-RPC是一种简单、古老的远程接口调用方法,使用HTTP将信息在客户端和服务器端之间传输。从通信的消息格式上看,与其他的API技术典型的差异在于消息体的XML文档化,如下面样例所示。

类XML-RPC请求:在请求消息中,所有的节点包含在methodCall中,其中methodName节点表示调用的方法名,param节点表示调用时使用的参数类型及其参数值。比如此样例中,请求调用的方法为testRPC,调用时参数值为2:

类XML-RPC响应:在响应消息中,所有的节点包含methodResponse中,其中param节点为正确响应的内容。比如此样例中,响应消息的值为字符串类型的admin:

从样例可以看出,变化的主要内容是通信交互的消息体,还有一点需要注意的是,对于远程接口中某个方法的调用,是在消息体中定义的,比如样例中调用远程接口的testRPC方法包含在XML格式中,而不是像普通的HTTP请求,放在URL路径中。除了上述差异,其他(如HTTP Header相关字段)与普通HTTP消息无异,调用堆栈与1.2.1节描述的RMI无异,更多差异化的细节体现在后端服务的逻辑实现上。

JMS作为Java消息服务类应用程序接口在大型企业级项目中也被频繁使用,市场上也有多种具体的产品实现,比如ActiveMQ、Kafka、Rabbit MQ等。与XML-RPC类不同,JMS的组成结构相对复杂些,如图1-13所示。

●图1-13 JMS通信过程

JMS主要用于两个应用程序之间或分布式系统中发送消息,进行同步或异步通信。消息发布者产生消息,并将消息发布到消息队列或对外发布主题Topic。在P2P模式下,每条消息仅会传送给一个消费者;而在发布/订阅模式下,每条消息会发送给订阅的多个消息消费者。JMS消息作为通信内容的载体,其结构主要分为消息头、属性和消息体三个部分。根据消息类型的不同,常用的主要有TextMessage文本消息、MapMessage键值对消息、BytesMessage二进制数据格式消息、ObjectMessage Java序列化对象消息以及StreamMessage以XML为传输载体的流消息。

通过理解JMS、XML-RPC的消息传输,能帮助读者快速理解Dubbo、XMPP等类型接口的技术原理,这也是将其他的API技术归类到此类型的另一个原因。