【Bug Bounty Hunter】第一章-网络请求
【Bug Bounty Hunter】笔记系列
0x00 HTTP基础知识
1. 超文本传输协议(HTTP)
HTTP通信由客户端和服务器组成,其中客户端向服务器发送请求。服务器收到请求后并返回所请求的资源。HTTP通信的默认端口是80,但可以根据Web服务器配置将其更改为其他端口。当我们通过浏览器访问不同的网站时候,都是通过输入URL(Uniform Resource Locator)来进行访问的。
1.1 URL
我们看一下URL的结构:
以下是每个组成部分所代表的含义:
组成部分 | 示例 | 说明 |
---|---|---|
Scheme | http:// https:// |
用于标识客户端访问的协议,以:// 结尾。 |
User Info | admin:password@ | 这是一个可选组件,包含用于验证主机身份的凭据(用: 分隔),并用@ 与主机分隔。 |
Host | inlanefreight.com | 主机表示资源位置,可以是主机名或IP地址。 |
Port | :80 | 端口与主机之间用冒号: 隔开。如果未指定端口http方案默认为80端口,https默认为443端口。 |
Path | /dashboard.php | 这指向被访问的资源,可以是文件或文件夹。如果没有指定路径,服务器将返回默认索引,如index.html 。 |
Query String | ?login=true | Query String 以? 开头,由一个参数和一个值组成。多个参数之间可以用& 分隔。 |
Fragments | #status | Fragments 由客户端的浏览器处理,用来定位页面资源的位置。 |
1.2 HTTP工作流程
上图展示了HTTP请求的流程。用户第一次在浏览器中输入URL(inlanefreight.com)时,它会向DNS(域名解析)服务器发送请求以解析该域并获取其IP。 DNS服务器查找 inlanefreight.com的IP地址并返回它。
注意:浏览器通常会先在本地
/etc/hosts
文件中查找记录,如果请求的域名不存在,然后他们会联系其他DNS服务器。我们可以使用/etc/hosts
手动添加记录以进行DNS解析。
浏览器获得所请求域名的IP地址后,它就会向默认HTTP端口(例如80)发送GET请求,询问根(/
)路径。然后,Web服务器接收请求并处理它。默认情况下,服务器配置是在收到 /
请求时返回索引文件。
在这种情况下,Web服务器将读取index.html
的内容并将其作为HTTP响应返回。响应还包含状态代码(例如 200 OK ),这表明请求已成功处理。然后浏览器显示index.html
内容并呈现给用户。
1.3 cURL
在本节中我们将通过两个重要的工具发送Web请求:浏览器(例如Chrome或Firefox)以及cURL命令行工具。
cURL 是一个命令行工具和库,主要支持HTTP以及许多其他协议。这使得它成为脚本和自动化的优秀工具。
我们可以通过cURL发送请求的信息,如下图:
1 | d4rk30@linux$ curl google.com |
我们看到与Web浏览器不同,cURL不会渲染HTML/JavaScript/CSS代码,而是以其原始格式打印它。同时我们还可以使用cURL下载页面或文件,使用-O
会将内容输出到文件中。并且如果我想指定下载文件的名称,可以使用-o
。
1 | d4rk30@linux$ curl -O inlanefreight.com/index.html -o 1.html |
如我们所看到的,这次没有直接显示网页的内容,而是保存到1.html中。并且cURL在处理请求时打印一些状态。我们可以使用-s
来屏蔽这些内容的输出,如下所示:
1 | d4rk30@linux$ curl -s -O inlanefreight.com/index.html -o 1.html |
这次,cURL没有输出任何内容。最后,我们可以使用-h
来查看cURL帮助信息,详细展示了其他参数的用法。
1 | d4rk30@linux$ curl -h |
2. 安全超文本传输协议(HTTPS)
HTTP的一个重要的问题是所有数据都以明文方式传输。这意味着在源和目标之间的任何人都可以执行中间人攻击(Man-in-the-middle,建成后MITM)来查看传输的数据。为了解决这个问题,HTTPS (HTTP Secure) 协议 应运而生,所有通信都以加密格式传输,因此即使第三方拦截了请求,也无法从中提取数据。因此,HTTPS已成为互联网网站的主流方案,而HTTP协议正在被逐步淘汰。
2.1 HTTPS概述
如果我们检查一个HTTP请求,就能看到浏览器和网站之间不安全通信的效果。例如,下面是一个HTTP登录请求的内容:
我们可以看到登录信息(账号和密码)使用明文显示。这样一来同一网络(如公共无线网络)中的其他人就可以轻松捕获请求,从而获取登陆信息。
相反,当有人拦截并分析来自HTTPS请求的流量时,他们会看到如下内容:
正如我们看到的,数据作为一个独立的加密信息流而进行传输,其他人想要获取这些数据变得非常困难。
注意:虽然通过HTTPS协议传输的数据可能会被加密,但如果请求联系明文DNS服务器,该请求仍然可能会泄露所访问的URL。因此,建议使用加密的DNS服务器(例如 8.8.8.8 或 1.1.1.1),或使用VPN服务以确保所有流量都正确加密。
2.2 HTTPS工作流程
让我们看看HTTPS是如何运行的:
如果我们输入http://
而不是https://
来访问强制执行HTTPS的网站,浏览器会尝试解析域并将用户重定向到托管目标网站的网络服务器。请求首先发送到端口80,这是未加密的 HTTP协议。服务器检测到此情况并将客户端重定向到安全HTTPS端口443。这是通过301 Moved Permanently响应完成的。
接下来,客户端(网络浏览器)发送一个”client hello”数据包,提供关于自己的信息。之后服务器回复”server hello”,接着进行密钥交换,交换SSL证书。客户端验证密钥/证书,并发送自己的密钥/证书。之后开始加密握手,以确认加密和传输是否正常。
一旦握手成功完成,正常的HTTP通信就会继续进行,并在此后进行加密。
注意:根据具体情况,攻击者可能会实施HTTP降级攻击,将HTTPS通信降级为HTTP,使数据以明文形式传输。具体方法是设置一个中间人代理,在用户不知情的情况下通过攻击者的主机传输所有流量。不过,大多数现代浏览器、服务器和网络应用程序都能防范这种攻击。
2.3 使用cURL处理HTTPS请求
一般情况下cURL会自动处理所有HTTPS通信标准,执行安全握手,然后自动加密和解密数据。不过,如果我们接触到一个SSL证书无效或过期的网站,那么cURL默认情况下不会继续通信,以防止前面提到的中间人攻击。
在测试本地Web应用程序或出于练习目的,访问测试的目标网站时,我们可能会遇到此类问题,因为此类Web应用程序可能尚未实现有效的SSL证书。要跳过cURL的证书检查,我们可以使用-k
参数:
1 | d4rk30@linux$ curl -k https://test.com |
3. HTTP请求和响应
HTTP通信主要由HTTP请求和HTTP响应组成。 HTTP请求由客户端(例如 cURL/浏览器)发出,并由服务器(例如 Web 服务器)处理。请求包含我们需要从服务器获取的所有详细信息,包括资源(如URL、路径、参数等)。服务器接收HTTP请求,对其进行处理并通过发送HTTP响应进行响应,其中包含响应代码,并且可能包含资源数据(如果请求者有权访问它)。
3.1 HTTP请求
上图显示了对URL的HTTP GET请求:
任何HTTP请求的第一行都包含三个主要字段,“以空格分隔”:
字段 | 示例 | 说明 |
---|---|---|
Method | GET | 指定要执行的操作类型的 HTTP 方法或动词。 |
Path | /users/login.html | 访问资源的路径。该字段也可以用查询字符串作为后缀(例如:?username=user )。 |
Version | HTTP/1.1 | 第三个也是最后一个字段用于表示 HTTP 版本。 |
下一行包含HTTP header值对,例如Host、User-Agent、Cookie和许多其他可能的header。这些header用于指定请求的各种属性。header用换行结束,这是服务器验证请求所必需的。最后请求可能会以请求正文和数据结束。
注意:HTTP版本1.X以明文形式发送请求,并使用换行符分隔不同的字段和不同的请求。另一方面,HTTP版本2.X以字典形式的二进制数据发送请求。
3.2 HTTP响应
HTTP响应的第一行包含两个以空格分隔的字段。第一个是HTTP版本(例如 HTTP/1.1 ),第二个表示HTTP响应代码(例如200 OK)。
响应代码用于确定请求的状态,在第一行之后,响应列出了其header ,类似于HTTP请求。
最后,响应可能以响应正文结束,响应正文在header后面用换行分隔。响应正文通常定义为HTML代码。但是,它还可以响应其他代码类型(例如JSON)、网站资源(例如图像、样式表或脚本),甚至是文档(例如托管在网络服务器上的PDF文档)。
3.3 用cURL查看请求与响应内容
在我们之前使用cURL的示例中,我们仅指定URL并获取返回的响应正文。然而,cURL还允许我们预览完整的HTTP请求和完整的HTTP响应,要查看完整的HTTP请求和响应,我们只需将-v
(verbose)添加到之前的命令中,它就会打印请求和响应:
1 | d4rk30@linux$ curl google.com -v |
-vvv 显示更详细的输出。尝试使用此参数来查看显示了哪些额外的请求和响应详细信息。
4. HTTP Headers
HTTP Headers可以有一个或多个值,附加在Header名称后面并用冒号分隔。我们可以将Headers分为以下几类:
- General Headers (通用标头)
- Entity Headers (实体标头)
- Request Headers (请求标头)
- Response Headers (响应标头)
- Security Headers (安全标头)
4.1 General Headers
General Headers 用于HTTP请求和响应。它们是上下文相关的,用于描述消息而不是其内容。
Header | 示例 | 说明 |
---|---|---|
Data | Date: Wed, 16 Feb 2022 10:38:44 GMT | 表示信息发出的日期和时间。最好将时间转换为标准 UTC 时区。 |
Connection | Connection: close | 指示当前网络连接是否应在请求结束后保持激活状态。该Header的两个常用值是close和keep-alive。客户端或服务器的close值表示他们希望终止连接,而 keep-alive 标头则表示连接应保持开放以接收更多数据和输入。 |
4.2 Entity Headers
与General Headers类似,Entity Headers可同时用于请求和响应。这些标头用于描述消息传输的内容(实体)。它们通常出现在响应POST或PUT请求中。
Header | 示例 | 说明 |
---|---|---|
Content-Type | Content-Type: text/html | 用于描述传输的资源类型。该值由浏览器在客户端自动添加,并在服务器响应中返回。charset 字段表示编码标准,如 UTF-8。 |
Media-Type | Media-Type: application/pdf | Media-Type 与 Content-Type 类似,描述传输的数据。该 Header 对服务器解释我们的输入起着至关重要的作用。字符集字段也可与该标头一起使用。 |
Boundary | boundary=”b4e4fbd93540” | 当同一信息中有多个内容时,作为分隔内容的标记。例如,在表单数据中,该边界会被用作 --b4e4fbd93540 来分隔表单的不同部分。 |
Content-Length | Length Content-Length: 385 | 表示所传递实体的大小。服务器使用该 Header 从报文正文中读取数据,浏览器和 cURL 等工具会自动生成该标头。 |
Content-Encoding | Content-Encoding: gzip | 数据在传递之前可以进行多重转换。例如,可以对大量数据进行压缩,以减小信息的大小。使用的编码类型应使用 Content-Encoding Header 指定。 |
4.3 Request Headers
客户端在HTTP事务中发送Request Headers。这些Headers用于HTTP请求,与信息内容无关。以下是HTTP请求中常见的标头。
Header | 示例 | 说明 |
---|---|---|
Host | Host: www.inlanefreight.com | 用于指定查询资源的主机。可以是域名或 IP 地址。HTTP 服务器可配置为不同网站的主机,这些网站可根据主机名显示。这使得 Host Header 成为一个重要的枚举目标,因为它可以显示目标服务器上是否存在其他主机。 |
User-Agent | User-Agent: curl/7.77.0 | |
Referer | Referer: http://www.inlanefreight.com/ | 表示当前请求来自哪里。例如,点击谷歌搜索结果中的链接会使 https://google.com 成为引用者。信任这个标头是很危险的,因为它很容易被操纵,导致意想不到的后果。 |
Accept | Accept: / | Accept Header 描述了客户端可以理解的媒体类型。它可以包含多个媒体类型,以逗号分隔。*/* 值表示接受所有媒体类型。 |
Cookie | Cookie: PHPSESSID=b4e4fbd93540 | 包含 name=value 格式的 Cookie 值对。Cookie 是存储在客户端和服务器上的一段数据,用作标识符。每次请求都会将这些数据传递给服务器,从而保持客户端的访问权限。Cookie 还可用于其他目的,如保存用户偏好或会话跟踪。一个标头中可以有多个 Cookie,中间用分号隔开。 |
Authorization | Authorization: BASIC cGFzc3dvcmQK | 服务器识别客户的另一种方法。认证成功后,服务器会返回客户端独有的令牌。与 Cookie 不同,令牌只存储在客户端,由服务器根据每次请求进行检索。根据所使用的网络服务器和应用程序类型,有多种类型的身份验证类型。 |
可以在此处找到请求标头及其用法的完整列表。
4.4 Response Headers
Response Headers 可在HTTP响应中使用,但与内容无关。某些Response Headers(如年龄、位置和服务器)用于提供有关响应的更多上下文。以下是HTTP中常见的Response Headers
Header | 示例 | 说明 |
---|---|---|
Server | Server: Apache/2.2.14 (Win32) | 包含处理请求的 HTTP 服务器的信息。它可用于获取服务器的信息(如版本)并进一步枚举。 |
Set-Cookie | Set-Cookie: PHPSESSID=b4e4fbd93540 | 包含客户端识别所需的 cookie。浏览器会解析 cookie 并将其存储起来,以备将来请求之用。该 Header 的格式与 Cookie request header 相同。 |
WWW-Authenticate | WWW-Authenticate: BASIC realm=”localhost” | 通知客户端访问请求资源所需的身份验证类型。 |
4.5 Security Headers
最后是 Security Headers。随着浏览器种类的增多和基于网络的攻击的增加,有必要定义某些增强安全性的Header。HTTP Security Headers是一类响应Header ,用于指定浏览器在访问网站时应遵循的某些规则和策略。
Header | 示例 | 说明 |
---|---|---|
Content-Security-Policy | Content-Security-Policy: script-src ‘self’ | 规定网站对外部注入资源的策略。这可以是JavaScript代码,也可以是脚本资源。该Header指示浏览器只接受来自特定可信域的资源,从而防止跨站脚本 (XSS) 等攻击。 |
Strict-Transport-Security | Strict-Transport-Security: max-age=31536000 | 防止浏览器通过明文HTTP协议访问网站,并强制所有通信通过安全的HTTPS协议进行。这样,攻击者就无法嗅探网络流量和访问受保护的信息,如密码或其他敏感数据。 |
Referrer-Policy | Referrer-Policy: origin | 决定浏览器是否应包含通过Referer标头指定的值。它有助于避免在浏览网站时泄露敏感的URL和信息。 |
注意:本节只提及一小部分常见的 HTTP 标头。HTTP 通信中还可以使用许多其他上下文标头。应用程序也可以根据自己的需求定义自定义标头。标准 HTTP 标头的完整列表可在此处找到
4.6 使用cURL查看Headers内容
在上一节中,我们看到了如何使用 cURL 的-v
来显示HTTP请求和响应的全部细节。如果我们只想查看response headers,那么可以使用-I
发送HEAD请求,并只显示response headers。此外,我们可以使用-i
来显示头部和响应正文(例如HTML代码)。两者的区别在于,-I
发送的是HEAD请求(将在下一节中介绍),而-i
发送的是我们指定的任何请求,并同时打印Headers信息。
下面的命令显示了使用-I
的输出示例:
1 | d4rk30@linux$ curl -I google.com |
除了查看Headers信息外,cURL还允许我们使用-H
设置Request Headers信息,我们将在后面的章节中看到这一点。有些Headers,如User-Agent或Cookie标头,有自己的参数。例如,我们可以使用-A
来设置User-Agent
,如下所示:
1 | d4rk30@linux$ curl -I google.com -A 'Mozilla/5.0' |
0x01 HTTP方法
1. HTTP方法和代码
HTTP支持多种访问资源的方法。在HTTP协议中,多种请求方法允许浏览器向服务器发送信息、表单或文件。除其他外,这些方法用于告诉服务器如何处理我们发送的请求以及如何回复。
我们在前面部分测试的HTTP请求中看到了不同的HTTP方法。使用cURL,如果我们使用-v
预览完整请求,第一行包含HTTP方法(例如GET/ HTTP/1.1 ),而使用浏览器开发工具,HTTP方法将显示在Method列中。此外,response headers还包含HTTP响应代码,该代码说明了处理HTTP请求的状态。
1.1 请求方法
以下是一些常用的方法:
Method | 说明 |
---|---|
GET | 请求特定资源。附加数据可通过 URL 中的查询字符串(如 ?param=value)传递给服务器。 |
POST | 向服务器发送数据。它可以处理多种类型的输入,如文本、PDF和其他形式的二进制数据。这些数据会附加在请求正文中,出现在标头之后。POST方法通常用于发送信息(如表单/登录)或向网站上传数据(如图像或文档)。 |
HEAD | 请求向服务器发出 GET 请求时返回的Headers信息。它不会返回请求正文,通常用于在下载资源前检查响应长度。 |
PUT | 在服务器上创建新资源。允许使用这种方法而不进行适当控制,可能会导致上传恶意资源。 |
DELETE | 删除网络服务器上的现有资源。如果安全措施不当,可能会删除网络服务器上的关键文件,从而导致拒绝服务(DoS)。 |
OPTIONS | 返回有关服务器的信息,如服务器接受的方法。 |
PATCH | 对指定位置的资源进行部分修改。 |
该列表仅突出显示了一些最常用的HTTP方法。特定方法的可用性取决于服务器以及应用程序配置。有关 HTTP 方法的完整列表,您可以访问此链接。
注意:大多数现代Web应用程序主要依赖GET和POST方法。但是,任何使用REST API 的Web应用程序也依赖于PUT和DELETE ,它们分别用于更新和删除API端点上的数据。有关更多详细信息,请参阅Web 应用程序简介模块。
1.2 响应代码
HTTP 态代码用于告诉客户端其请求的状态。 HTTP服务器可以返回五种类型的响应代码:
Type | 说明 |
---|---|
1XX | 提供信息,不影响对申请的处理。 |
2XX | 当请求成功时返回。 |
3XX | 服务器重定向客户端时返回。 |
4XX | 表示客户端请求不当。例如,请求不存在的资源或请求不良格式。 |
5XX | 当HTTP服务器本身出现问题时返回。 |
以下是上述每种HTTP方法类型的一些常见示例:
Code | 说明 |
---|---|
200 OK | 请求成功时返回,响应体通常包含请求的资源。 |
302 Found | 将客户端重定向到另一个URL。例如,在成功登录后将用户重定向到其仪表板。 |
400 Bad Request | 遇到畸形请求(如缺少行结束符的请求)时返回。 |
403 Forbidden | 表示客户端没有适当的资源访问权限。当服务器检测到用户的恶意输入时,也会返回该值。 |
404 Not Found | 当客户端请求的资源在服务器上不存在时返回。 |
500 Internal Server Error | 当服务器无法处理请求时返回。 |
有关标准HTTP响应代码的完整列表,您可以访问此链接。除了标准的HTTP代码之外,各种服务器和提供商(例如 Cloudflare 或 AWS)还实现了自己的代码。
2. GET
每当我们访问任何URL时,我们的浏览器都会默认使用GET请求来获取该URL上托管的远程资源。一旦浏览器收到它请求的初始页面;它可以使用各种HTTP方法发送其他请求。
2.1 HTTP基本身份验证
当我们访问一些网站时,它会提示我们输入用户名和密码。与使用HTTP参数来验证用户凭据(例如 POST 请求)的常用登录表单不同,这种类型的身份验证使用basic HTTP authentication由Web服务器直接处理的来保护特定页面/目录,而不直接与Web应用程序交互。
我们尝试使用cURL访问该页面,然后添加-i
以查看响应标头:
1 | d4rk30@linux$ curl -i http://<SERVER_IP>:<PORT>/ |
正如我们所看到的,我们获得Access denied了响应正文,并且 WWW-Authenticate 的Header信息中展示了Basic realm=”Access denied”,这确认了该页面确实使用了basic HTTP auth。我们在cURL中使用-u
参数来发送验证信息:
1 | d4rk30@linux$ curl -u admin:admin http://<SERVER_IP>:<PORT>/ |
这次我们在响应信息中可以看到页面内容。我们还可以通过另外一种方式提供的basic HTTP auth信息,进行验证:
1 | d4rk30@linux$ curl http://admin:admin@<SERVER_IP>:<PORT>/ |
2.2 HTTP授权Header
让我们对上述命令添加一个-v
参数:
1 | d4rk30@linux$ curl -v http://admin:admin@<SERVER_IP>:<PORT>/ |
我们可以看到HTTP请求将Authorization Header设置为 Basic YWRtaW46YWRtaW4=
,这是base64对admin:admin
进行编码之后得到的。如果我们使用现代的身份验证方法(例如JWT),则Authorization将是Bearer类型,并将包含更长的加密令牌。
让我们尝试手动设置Authorization,而不提供凭据,看看它是否允许我们访问该页面。我们可以使用-H
参数设置Headers,并将使用与上述HTTP请求相同的值。我们可以多次添加-H
来指定多个Header:
1 | d4rk30@linux$ curl -H 'Authorization: Basic YWRtaW46YWRtaW4=' http://<SERVER_IP>:<PORT>/ |
正如我们所看到的,这也使我们能够访问该页面。这些是我们可以用来对页面进行身份验证的几种方法。大多数现代 Web 应用程序使用使用后端脚本语言(例如 PHP)构建的登录表单,该表单利用 HTTP POST 请求对用户进行身份验证,然后返回 cookie 来维持其身份验证。
3. POST
在上一节中,我们了解了 Web 应用程序如何使用 GET 请求来实现搜索和访问页面等功能。但是,每当 Web 应用程序需要传输文件或从 URL 移动用户参数时,它们都会使用 POST 请求。
HTTP POST 将用户参数放置在 HTTP 请求正文中。这具有三个主要优点:
- 减少日志记录:由于 POST 请求可能会传输大文件(例如文件上传),因此服务器将所有上传的文件记录为请求的 URL 的一部分并不高效,就像使用通过 GET 请求上传的文件。
- 更少的编码要求:URL 被设计为共享,这意味着它们需要符合可以转换为字母的字符。 POST 请求将数据放置在可接受二进制数据的正文中。唯一需要编码的字符是用于分隔参数的字符。
- 可发送更多数据:可以发送更多数据:最大 URL 长度因浏览器 (Chrome/Firefox/IE)、Web 服务器 (IIS、Apache、nginx)、内容而异交付网络(Fastly、Cloudfront、Cloudflare),甚至 URL 缩短器(bit.ly、amzn.to)。一般来说,URL 的长度应保持在 2,000 个字符以下,因此它们无法处理大量数据。
3.1 使用cURL发送POST请求
我们将使用 -X POST 标志来发送 POST 请求。然后,要添加 POST 数据,我们可以使用 -d 标志并在其后添加上述数据,如下所示:
1 | d4rk30@linux$ curl -X POST -d 'username=admin&password=admin' http://<SERVER_IP>:<PORT>/ |
提示:许多登录表单在经过身份验证后会将我们重定向到不同的页面(例如/仪表板.php)。如果我们想使用 cURL 进行重定向,我们可以使用 -L 标志。
3.2 Authenticated Cookies
如果我们成功通过身份验证,我们应该会收到一个 cookie,以便我们的浏览器可以保留我们的身份验证,并且我们不需要每次访问该页面时都登录。我们可以使用 -v 或 -i 标志来查看响应,该响应应包含带有我们经过身份验证的 cookie 的 Set-Cookie Header:
1 | d4rk30@linux$ curl -X POST -d 'username=admin&password=admin' http://<SERVER_IP>:<PORT>/ -i |
通过经过身份验证的 cookie,我们现在应该能够与 Web 应用程序进行交互,而无需每次都提供我们的凭据。为了测试这一点,我们可以在 cURL 中使用 -b 标志设置上述 cookie,如下所示:
1 | d4rk30@linux$ curl -b 'PHPSESSID=c1nsa6op7vtk7kdis7bcnbadf1' http://<SERVER_IP>:<PORT>/ |
正如我们所看到的,我们确实通过了身份验证并进入了搜索功能。也可以将 cookie 指定为Header,如下所示:
1 | d4rk30@linux$ curl -H 'Cookie: PHPSESSID=c1nsa6op7vtk7kdis7bcnbadf1' http://<SERVER_IP>:<PORT>/ |
3.3 JSON Data
大部分情况下,POST 请求发送时候都是带有 json 格式的数据,尝试用 cURL 发送一个 json 数据的请求:
1 | d4rk30@linux$ curl -X POST -d '{"search":"london"}' -b 'PHPSESSID=c1nsa6op7vtk7kdis7bcnbadf1' -H 'Content-Type: application/json' http://<SERVER_IP>:<PORT>/search.php |
4. CRUD API
4.1 APIs
API 有多种类型。许多API用于与数据库交互,这样我们就可以在API查询中指定请求的表和请求的行,然后使用HTTP方法执行所需的操作。
4.2 CRUD
正如我们所看到的,我们可以通过此类 API 轻松指定要执行操作的表和行。然后我们可以利用不同的 HTTP 方法对该行执行不同的操作。一般来说,API 对请求的数据库实体执行 4 个主要操作:
操作 | HTTP 方法 | 说明 |
---|---|---|
Create | POST | 将指定数据添加到数据库表 |
Read | GET | 从数据库表中读取指定实体 |
Update | PUT | 更新指定数据库表的数据 |
Delete | DELETE | 从数据库表中删除指定行 |
这四个操作主要与众所周知的 CRUD API 相关,但相同的原理也适用于 REST API 和其他几种类型的 API。当然,并非所有 API 都以相同的方式工作,用户访问控制将限制我们可以执行的操作以及我们可以看到的结果。 Web 应用程序简介模块进一步解释了这些概念,因此您可以参考它以获取有关 API 及其用法的更多详细信息。
4.3 Read
与 API 交互时我们要做的第一件事就是读取数据。如前所述,我们可以简单地在 API 后面指定表名(例如 /city ),然后指定我们的搜索词(例如 /london ),如下所示:
1 | d4rk30@linux$ curl http://<SERVER_IP>:<PORT>/api.php/city/london |
我们看到结果以 JSON 字符串的形式发送。为了将其正确格式化为 JSON 格式,我们可以将输出通过管道传输到 jq 实用程序,该实用程序将对其进行正确格式化。我们还将使用 -s 静默任何不需要的 cURL 输出,如下所示:
1 | d4rk30@linux$ curl -s http://<SERVER_IP>:<PORT>/api.php/city/london | jq |
4.4 Create
要添加新条目,我们可以使用 HTTP POST 请求,这与我们在上一节中执行的操作非常相似。我们可以简单地 POST JSON 数据,它将被添加到表中。由于此 API 使用 JSON 数据,我们还将 Content-Type 标头设置为 JSON,如下所示:
1 | d4rk30@linux$ curl -X POST http://<SERVER_IP>:<PORT>/api.php/city/ -d '{"city_name":"City", "country_name":"Country"}' -H 'Content-Type: application/json' |
现在,我们可以读取我们添加的城市,看看它是否已成功添加:
1 | d4rk30@linux$ curl -s http://<SERVER_IP>:<PORT>/api.php/city/City | jq |
4.5 Update
现在我们知道如何通过 API 读取和写入条目,让我们开始讨论其他两种 HTTP 方法到目前为止我们还没有使用过: PUT 和 DELETE 。正如本节开头提到的, PUT 用于更新 API 条目并修改其详细信息,而 DELETE 用于删除特定实体。
注意: HTTP PATCH 方法也可用于更新 API 条目而不是 PUT 。准确地说,PATCH 用于部分更新条目(仅修改其部分数据“例如仅 city_name”),而 PUT 用于更新整个条目。我们还可以使用HTTP OPTIONS方法来查看服务器接受两者中的哪一个,然后相应地使用适当的方法。在本节中,我们将重点关注 PUT 方法,尽管它们的用法非常相似。
使用 PUT 与 POST 非常相似,唯一的区别是我们必须指定我们想要的实体的名称在 URL 中进行编辑,否则 API 将不知道要编辑哪个实体。因此,我们所要做的就是在 URL 中指定城市名称,将请求方法更改为 PUT ,并像使用 POST 一样提供 JSON 数据,如下所示:
1 | d4rk30@linux$ curl -X PUT http://<SERVER_IP>:<PORT>/api.php/city/london -d '{"city_name":"New_City", "country_name":"Country"}' -H 'Content-Type: application/json' |
注意:在某些 API 中,更新操作也可用于创建新条目。基本上,我们会发送数据,如果它不存在,它会创建它。例如,在上面的示例中,即使包含伦敦城市的条目不存在,它也会使用我们传递的详细信息创建一个新条目。然而,在我们的示例中,情况并非如此。尝试更新一个不存在的城市,看看会得到什么。
4.6 DELETE
最后,我们尝试删除一个城市,这就像读取一个城市一样简单。我们只需为 API 指定城市名称并使用 HTTP DELETE 方法,它就会删除该条目,如下所示:
1 | d4rk30@linux$ curl -X DELETE http://<SERVER_IP>:<PORT>/api.php/city/New_City |