杂谈

最近数据安全非常的火,由此衍生的API安全成为了很多人的焦点,由此,我们最近会通过视频讲解、图文讲解的形式带大家来了解API。

视频讲解

本期视频我们将从API的发展史,给大家梳理SOAP、RPC、REST、GraphQL常见的这四种API通讯方式,它们各有哪些优势?后出的就一定比之前的要好吗?

API发展史

图片[1]-常见的四种API:SOAP vs RPC vs REST vs GraphQL-FancyPig's blog
一张图看懂API发展历程

主流API技术

Request-Response Api

  • RPC(Remote Procedure Call)
  • Soap(Simple Object Acess Protocols)
  • REST(Representational State Transfer)
  • GraphQL

EDA(Event-Driven Architecture) Api

  • Webhook

API对比

对比 RPC Soap REST GraphQL
发行时间 1998年XML-RPC
2005年JSON-RPC
2016年gRPC
1999年 2000年 2015年
支持格式 JSON,XML,Protobuf,
Thrift,Flatbuffers
仅支持XML XML,JSON,HTML,
纯文本
JSON
上手难度 简单 困难 简单 中等
社区 成长中
应用场景 支付网关
身份管理
客户关系管理解决方案
金融和电信服务
遗留系统支持
公共API
简单的资源驱动型应用程序
移动APIS
复杂的系统
微服务
指挥和行动导向的API
大规模微服务系统中的高性能通信

由于主要研究的是网络安全,故我们可能更关注于请求方式、请求体中的特征是怎样的?因此,下面会着重介绍这些特征,优势和缺点我们在这里不做重点叙述。

RPC

XML-RPC

如果你对此不太了解,你可以尝试在线调试

请求方式

GET或者POST

举例

比方说,我们这里就拿wordpress举例,wordpress就是支持XML的,那如果我们想要获取wordpress下面有哪些接口,可以先通过POST请求/xmlrpc.php,请求体如下

<?xml version='1.0'?>
<methodCall>
	<methodName>system.listMethods</methodName>
</methodCall>

然后就可以看到wordpress系统中有哪些方法

<methodResponse>
    <params>
        <param>
            <value>
                <array><data>
                        <value>
                            <string>system.multicall</string>
                        </value>
                        <value>
                            <string>system.listMethods</string>
                        </value>
                        <value>
                            <string>system.getCapabilities</string>
                        </value>
                        <value>
                            <string>demo.multiplyTwoNumbers</string>
                        </value>
                        <value>
                            <string>demo.addTwoNumbers</string>
                        </value>
                        <value>
                            <string>demo.sayHello</string>
                        </value>
                        <value>
                            <string>pingback.extensions.getPingbacks</string>
                        </value>
                        <value>
                            <string>pingback.ping</string>
                        </value>
                        <value>
                            <string>mt.publishPost</string>
                        </value>
                        <value>
                            <string>mt.getTrackbackPings</string>
                        </value>
                        <value>
                            <string>mt.supportedTextFilters</string>
                        </value>
                        <value>
                            <string>mt.supportedMethods</string>
                        </value>
                        <value>
                            <string>mt.setPostCategories</string>
                        </value>
                        <value>
                            <string>mt.getPostCategories</string>
                        </value>
                        <value>
                            <string>mt.getRecentPostTitles</string>
                        </value>
                        <value>
                            <string>mt.getCategoryList</string>
                        </value>
                        <value>
                            <string>metaWeblog.getUsersBlogs</string>
                        </value>
                        <value>
                            <string>metaWeblog.setTemplate</string>
                        </value>
                        <value>
                            <string>metaWeblog.getTemplate</string>
                        </value>
                        <value>
                            <string>metaWeblog.deletePost</string>
                        </value>
                        <value>
                            <string>metaWeblog.newMediaObject</string>
                        </value>
                        <value>
                            <string>metaWeblog.getCategories</string>
                        </value>
                        <value>
                            <string>metaWeblog.getRecentPosts</string>
                        </value>
                        <value>
                            <string>metaWeblog.getPost</string>
                        </value>
                        <value>
                            <string>metaWeblog.editPost</string>
                        </value>
                        <value>
                            <string>metaWeblog.newPost</string>
                        </value>
                        <value>
                            <string>blogger.deletePost</string>
                        </value>
                        <value>
                            <string>blogger.editPost</string>
                        </value>
                        <value>
                            <string>blogger.newPost</string>
                        </value>
                        <value>
                            <string>blogger.setTemplate</string>
                        </value>
                        <value>
                            <string>blogger.getTemplate</string>
                        </value>
                        <value>
                            <string>blogger.getRecentPosts</string>
                        </value>
                        <value>
                            <string>blogger.getPost</string>
                        </value>
                        <value>
                            <string>blogger.getUserInfo</string>
                        </value>
                        <value>
                            <string>blogger.getUsersBlogs</string>
                        </value>
                        <value>
                            <string>wp.getCommentStatusList</string>
                        </value>
                        <value>
                            <string>wp.newComment</string>
                        </value>
                        <value>
                            <string>wp.editComment</string>
                        </value>
                        <value>
                            <string>wp.deleteComment</string>
                        </value>
                        <value>
                            <string>wp.getComments</string>
                        </value>
                        <value>
                            <string>wp.getComment</string>
                        </value>
                        <value>
                            <string>wp.setOptions</string>
                        </value>
                        <value>
                            <string>wp.getOptions</string>
                        </value>
                        <value>
                            <string>wp.getPageTemplates</string>
                        </value>
                        <value>
                            <string>wp.getPageStatusList</string>
                        </value>
                        <value>
                            <string>wp.getPostStatusList</string>
                        </value>
                        <value>
                            <string>wp.getCommentCount</string>
                        </value>
                        <value>
                            <string>wp.uploadFile</string>
                        </value>
                        <value>
                            <string>wp.suggestCategories</string>
                        </value>
                        <value>
                            <string>wp.deleteCategory</string>
                        </value>
                        <value>
                            <string>wp.newCategory</string>
                        </value>
                        <value>
                            <string>wp.getTags</string>
                        </value>
                        <value>
                            <string>wp.getCategories</string>
                        </value>
                        <value>
                            <string>wp.getAuthors</string>
                        </value>
                        <value>
                            <string>wp.getPageList</string>
                        </value>
                        <value>
                            <string>wp.editPage</string>
                        </value>
                        <value>
                            <string>wp.deletePage</string>
                        </value>
                        <value>
                            <string>wp.newPage</string>
                        </value>
                        <value>
                            <string>wp.getPages</string>
                        </value>
                        <value>
                            <string>wp.getPage</string>
                        </value>
                        <value>
                            <string>wp.getUsersBlogs</string>
                        </value>
                </data></array>     
            </value>
        </param>
    </params>
</methodResponse>

通过观察,我们可以看到有wp.getUserBlogs方法,那我们如何通过这个方法,对用户名、密码进行暴力破解呢?

我们可以POST请求,发送下面的内容,usernamepassword分别代表用户名、密码,由此你也可以使用fuzz模糊测试或者burpsuite对其进行暴力破解,这也是为什么很多wordpress网站需要对xmlrpc.php进行防护,甚至很多人在配置文件里将其关闭。

<?xml version='1.0'?>
<methodCall>
	<methodName>wp.getUserBlogs</methodName>
	<params>
		<param>
			<value>username</value>
		</param>
		<param>
			<value>password</value>
		</param>
	</params>
</methodCall>

JSON-RPC

如果你对此不太了解,你可以尝试在线调试。如果你之前对区块链有所耳闻,其实大多数的挖矿都是通过JSON-RPC进行请求的,我们还可以看上次我分析的文章

如何通过Wireshark分析ssh暴力猜解等异常行为-自由者联盟

请求方式

GETPOST

举例

这里继续拿wordpress进行举例,下面是一个遐想的场景哦!仅用作和XML-RPC进行对比!

我们如果用JSON-RPC的方式请求刚才的接口,请求体的内容又是怎样的呢?

比方说,我们还是想获取系统下有哪些方法,那我们需要进行如下请求

{
    "methodCall": {
        "methodName": "system.listMethods",
    }
}

那如果获取到了wp.getUserBlogs,如何使用用户名、密码登录呢?

{
    "methodCall": {
        "methodName": "wp.getUserBlogs",
        "params": [
            {
                username,
                password
            }
        ]
    }
}

SOAP

请求方式

GET或者POST

请求体格式

POST请求都应该有哪些内容呢?格式如下

<?xml version="1.0"?>  
  
<soap:Envelope  
xmlns:soap="http://www.w3.org/2003/05/soap-envelope/"  
soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">  
  
<soap:Header>  
...  
</soap:Header>  
  
<soap:Body>  
...  
  <soap:Fault>  
  ...  
  </soap:Fault>  
</soap:Body>  
  
</soap:Envelope>

举例

请求URL/getAdUnitsByStatement

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope
        xmlns:soapenv="https://schemas.xmlsoap.org/soap/envelope/"
        xmlns:xsd="https://www.w3.org/2001/XMLSchema"
        xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Header>
    <ns1:RequestHeader
         soapenv:actor="https://schemas.xmlsoap.org/soap/actor/next"
         soapenv:mustUnderstand="0"
         xmlns:ns1="https://www.google.com/apis/ads/publisher/v201605">
      <ns1:networkCode>123456</ns1:networkCode>
      <ns1:applicationName>DfpApi-Java-2.1.0-dfp_test</ns1:applicationName>
    </ns1:RequestHeader>
  </soapenv:Header>
  <soapenv:Body>
    <getAdUnitsByStatement xmlns="https://www.google.com/apis/ads/publisher/v201605">
      <filterStatement>
        <query>WHERE parentId IS NULL LIMIT 500</query>
      </filterStatement>
    </getAdUnitsByStatement>
  </soapenv:Body>
</soapenv:Envelope>

我们可以看到上面的其实核心就查询语句

<query>WHERE parentId IS NULL LIMIT 500</query>

对比JSON-RPC,我们会发现上面属实繁琐太多了

下面是JSON-RPC的请求体部分

{"filter": "WHERE parentId IS NULL LIMIT 500"}

完整的POST请求包

POST /getAdUnitsByStatement HTTP/1.1
HOST: api.example.com
Content-Type: application/json

{"filter": "WHERE parentId IS NULL LIMIT 500"}

REST

请求方式

HEAD或者GET或者POST或者PUT或者PATCH或者Delete

请求方式 作用
HEAD 对任何资源仅请求头信息
GET 获取资源
POST 创建资源
PATCH 使用部分的JSON数据更新资源
PUT 取代资源或资源集合
DELETE 删除资源

状态码

状态码 描述
200 OK 表示请求已经成功。
201 Created 表示请求已经成功,并因此创建了一个新的资源。
202 Accepted 表示已经收到请求但尚未完成。它通常用于日志运行请求和批处理。
203 Non-Authoritative Information 表示返回的实体头中的元信息不是来自源服务器的确定集合,而是从本地或第三方的副本中收集的。提出的集合可能是原始版本的子集或超集。
204 No Content 服务器已经完成了请求,但不需要返回响应体。服务器可以返回更新的元信息。
205 Reset Content 表示客户端要重置发送此请求的文件。
206 Partial Content 当客户端发送Range头时,它被用于只请求一个资源的一部分。
207 Multi-Status (WebDAV) 给客户的一个指示器,表明发生了多个操作,每个操作的状态都可以在响应的正文中找到。
208 Already Reported (WebDAV) 允许客户端告诉服务器相同的资源(具有相同的绑定)在前面被提及。它从不作为真正的HTTP响应代码出现在状态行中,而只出现在正文中。
226 IM Used 服务器已经完成了对该资源的GET请求,并且响应是应用于当前实例的一个或多个实例处理结果的表示。

举例

请求URL

这里以某网站的API进行举例说明

请求方式 URL API 作用
GET /api/users?page=2 列出用户列表
GET /api/users/2 查看某个用户信息
POST /api/users/ 创建用户
PUT /api/users/ 更新用户
PATCH /api/users/ 更新用户
DELETE /api/users/ 删除用户

请求体

如果是PUTPATCHPOST请求

URL为/api/user

{
    "name": "morpheus",
    "job": "leader"
}

总结

我们会发现请求体中也是JSON的格式,其实与JSON-RPC很像,但是这里REST风格的URL让人更容易理解了

GraphQL

请求方式

GET或者POST

举例

我们这里可以使用一个测试站点

https://countries.trevorblades.com/

然后编写我们的查询语句

上面两个在线测试站点均可以完成,我们这里使用下面的语句,尝试第一次查询

query {
  countries {
    name
  }
}
图片[2]-常见的四种API:SOAP vs RPC vs REST vs GraphQL-FancyPig's blog
图片[3]-常见的四种API:SOAP vs RPC vs REST vs GraphQL-FancyPig's blog

这里你可能会有疑问,就是在真正的请求中是怎样的呢?通常GraphQL和REST都会有一个端点,譬如/graphql

我们这里以GET请求为例,则应该是https://countries.trevorblades.com/?query={countries{name}}

这里,我可能讲解的不够细致,详细的可以参考

GrphQL官网的讲解:https://graphql.cn/learn/serving-over-http/

© 版权声明
THE END
喜欢就支持一下吧
点赞14 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容