HTTP超文本传输协议

@wintry大约 13 分钟

HTTP协议概述

HTTP 是一种能够获取如 HTML 这样的网络资源的通讯协议(超文本传输协议)。

是一种 client-server 协议,客户端和服务端通过交换各自的消息进行交互。由像浏览器这样的客户端发出的消息叫做 request,被服务端响应的消息叫做 response

一个完整的 Web 文档通常是由不同的子文档拼接而成的,像是文本、图片、视频、脚本等等。

HTTP 是无状态,有会话的

HTTP 是无状态的:在同一个连接中,两个执行成功的请求之间是没有关系的。

这就带来了一个问题,用户没有办法在同一个网站中进行连续的交互,比如在一个电商网站里,用户把某个商品加入到购物车,切换一个页面后再次添加了商品,这两次添加商品的请求之间没有关联,浏览器无法知道用户最终选择了哪些商品。

而使用 HTTP 的头部扩展,HTTP Cookies 就可以解决这个问题。把 Cookies 添加到头部中,创建一个会话让每次请求都能共享相同的上下文信息,达成相同的状态。

注意,HTTP 本质是无状态的,使用 Cookies 可以创建有状态的会话。

HTTP连接

一个连接是由传输层来控制的,这从根本上不属于 HTTP 的范围。HTTP 并不需要其底层的传输层协议是面向连接的,只需要它是可靠的,或不丢失消息的(至少返回错误)。在互联网中,有两个最常用的传输层协议:TCP 是可靠的,而 UDP 不是。因此,HTTP 依赖于面向连接的 TCP 进行消息传递,但连接并不是必须的。

在客户端(通常指浏览器)与服务器能够交互(客户端发起请求,服务器返回响应)之前,必须在这两者间建立一个 TCP 链接,打开一个 TCP 连接需要多次往返交换消息(因此耗时)。HTTP/1.0 默认为每一对 HTTP 请求/响应都打开一个单独的 TCP 连接。当需要连续发起多个请求时,这种模式比多个请求共享同一个 TCP 链接更低效。

为了减轻这些缺陷,HTTP/1.1 引入了流水线(被证明难以实现)和持久连接的概念:底层的 TCP 连接可以通过Connection头部来被部分控制。HTTP/2 则发展得更远,通过在一个连接复用消息的方式来让这个连接始终保持为暖连接。

HTTP 对 TCP 连接的使用,分为两种方式:俗称“短连接”和“长连接”。

HTTP/1.1 默认使用长连接(持久化连接)。

HTTP建立连接的过程

  1. 在TCP连接上发送HTTP报文;根据规则, 只有低层协议建立之后才能进行高层协议的连接
  2. 发送请求行,GET /dir/xx.php HTTP/1.1
  3. 发送请求头,浏览器发送一行空白行来告知服务器结束请求头信息发送
  4. 服务器响应, HTTP/1.1 200 OK(协议版本号和HTTP状态码)
  5. 服务器发送响应头,服务器自己的相关信息(同样用空白行表示结束响应头)
  6. 服务器向浏览器发送数据, 以 Content-Type 响应头信息所描述的格式发送用户所请求的实际数据
  7. 服务器关闭TCP连接,如果请求头或响应头加了这行 Connection:keep-alive,会保持连接

HTTP报文

请求(Request)

相关信息

Method:请求方法

Path:访问网站的路径

Version:HTTP协议版本号

Headers:HTTP请求头

A basic HTTP request

响应(Response)

相关信息

Version:HTTP协议版本号

Status code:状态码,告知对应请求执行成功或失败,以及失败的原因。

Status message:状态信息,这个信息是非权威的状态码描述信息,可以由服务端自行设定。

Headers:HTTP响应头

img

HTTP请求方法

请求方法作用
GET请求指定的资源,只用于获取数据
POST发送数据给服务器。请求主体的类型由 Content-Type 首部指定
OPTIONS用于获取目的资源所支持的请求方法
HEAD请求资源的头部信息,获取资源大小,响应不包含响应体,可以节约带宽资源
PUT使用请求中的负载创建或者替换目标资源
DELETE删除指定的资源
TRACE实现沿通向目标资源的路径的消息环回(loop-back)测试,提供了一种实用的 debug 机制
PATCH用于对资源进行部分修改 补丁
CONNECT开启一个客户端与所请求资源之间的双向沟通的通道。可以用来创建隧道(tunnel)

警告

PUTPOST 方法的区别在于,PUT 方法是幂等的:调用一次与连续调用多次是等价的(即没有副作用),而连续调用多次 POST 方法可能会有副作用,比如将一个订单重复提交多次。

如果目标资源不存在,并且 PUT 方法成功创建了一份,那么源头服务器必须返回201 (Created) 来通知客户端资源已创建。

HTTP/1.1 201 Created
Content-Location: /new.html

如果目标资源已经存在,并且依照请求中封装的表现形式成功进行了更新,那么,源头服务器必须返回200 (OK) 或者204 (No Content) 来表示请求的成功完成。

HTTP/1.1 204 No Content
Content-Location: /existing.html

HTTP状态码

状态码类别

类别原因短语
1XXInformational(信息性状态码)接受的请求正在处理
2XXSuccess(成功状态码)请求正常处理完毕
3XXRedirection(重定向状态码)需要进行附加操作以完成请求
4XXClient Error(客户端错误状态码)服务器无法处理请求
5XXServer Error(服务器错误状态码)服务器处理请求出错
常见状态码(点击展开)

100:表示收到请求消息头,客户端应继续发送主体

200:请求被正常处理

201:PUT请求返回这个状态码,表示请求已成功提交

204:请求被受理但没有资源可以返回

206:客户端只是请求资源的一部分,服务器只对请求的部分资源执行GET方法,相应报文中通过Content-Range指定范围的资源。

301:永久性重定向

302:临时重定向

303:与302状态码有相似功能,只是它希望客户端在请求一个URI的时候,能通过GET方法重定向到另一个URI上

304:发送附带条件的请求时,条件不满足时返回,指示浏览器使用缓存中所请求资源的副本

307:临时重定向,与302类似,只是强制要求使用POST方法

400:请求报文语法有误,服务器无法识别

401:请求需要认证

403:请求的对应资源禁止被访问

404:服务器无法找到对应资源

405:不支持请求中使用的请求方法

413:请求主体过长,服务器无法处理 (探查缓冲区溢出时会有)

414:请求URL过长,服务器无法处理

500:服务器内部错误

503:服务器正忙,用来说明服务器现在无法为请求提供服务,但将来可以 (服务器负载过大)

HTTP请求头

Accept

用来告知(服务器)客户端可以处理的内容类型,这种内容类型用MIME 类型来表示。

展开语法
Accept: text/html
Accept: image/*
Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8

Accept-Charset

用来告知(服务器)客户端可以处理的字符集类型

展开语法
Accept-Charset: iso-8859-1
Accept-Charset: utf-8, iso-8859-1;q=0.5
Accept-Charset: utf-8, iso-8859-1;q=0.5, *;q=0.1

Accept-Encoding

将客户端能够理解的内容编码方式,通常是某种压缩算法,通知给服务端

展开语法
Accept-Encoding: gzip
Accept-Encoding: compress
Accept-Encoding: deflate
Accept-Encoding: br
Accept-Encoding: identity
Accept-Encoding: *

Authorization

请求消息头含有服务器用于验证用户代理身份的凭证,通常会在服务器返回401 Unauthorized 状态码以及WWW-Authenticate 消息头之后在后续请求中发送此消息头。

Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l

Connection

决定当前的事务完成后,是否会关闭网络连接。如果该值是“keep-alive”,网络连接就是持久的,不会关闭,使得对同一个服务器的请求可以继续在该连接上完成。

展开语法
Connection: keep-alive
Connection: close

X-Forwarded-For (XFF)

获取最初发起请求的客户端的 IP 地址,也是一个电子邮件相关协议中用到的首部,用来表示一封电子邮件是从其他账户转发过来的。

如果一个请求经过了多个代理服务器,那么每一个代理服务器的 IP 地址都会被依次记录在内。

也就是说,最右端的 IP 地址表示最近通过的代理服务器,而最左端的 IP 地址表示最初发起请求的客户端的 IP 地址。

展开语法
X-Forwarded-For: <client>, <proxy1>, <proxy2>
X-Forwarded-For: 2001:db8:85a3:8d3:1319:8a2e:370:7348
X-Forwarded-For: 47.11.22.33
X-Forwarded-For: 47.11.22.33, 70.41.3.18, 150.172.238.178

更多其它头部

Cache-Control: 缓存的控制 
Transfer-Encoding: 报文主体的传输编码方式
Host: 请求资源所在服务器和端口号 Accept: 可处理的媒体类型 Accept-Charset: 可接收的字符集 Accept-Encoding: 可接受的内容编码 Accept-Language: 可接受的自然语言
Cookie: 用于向服务器提交它以前发布的cookie
If-Modified-Since:  用于说明最后一次收到所请求资源的时间,如果自那之后资源没有变化,服务器会返回一个状态码304的响应,指示客户端使用资源的缓存副本
If-None-Match: 用于指定一个实体标签,当最后一次收到所请的求资源时,浏览器提交服务器发布的实体标签,服务器可以使用实体标签,确认浏览器是否使用资源的缓存副本
Origin: 用在Ajax跨域请求中,用于指示提出请求的域
Referer: 指示发出当前请求的原始URL
User-Agent: 提供生成请求客户端软件的有关信息
Allow: 资源可支持的HTTP方法 
Location: 在重定向响应中,说明重定向的目标 
Server: 提供所使用的Web服务器软件的信息
Accept-Ranges: 可接受的字节范围
Content-Type: 规定消息主体的类型 Content-Encoding: 实体主体适用的编码方式,一些应用程序用它压缩响应加快传输 Content-Language: 实体主体的自然语言 Content-Length: 规定消息主体的字节长度 (HEAD方法例外) Content-Range: 实体主体的位置范围,一般用于发出部分请求时使用
Transfer-Encoding:  chunked 分块传输;常用它指定块编码,它是指定HTTP传输对消息主体使用的任何编码的
Access-Control-Allow-Origin: 指示可否通过跨域Ajax请求获取资源
Set-Cookie: 用于向浏览器发布Cookie,浏览器会在随后的请求中将其返回给服务器
WWW-Authenticate: 在带401状态码的响应中,提供与服务器所支持的身份验证类型的有关信息 (如基础认证)
X-Frame-Options: 指示浏览器框架是否加载以及如何加载当前响应

HTTP协议是无状态的,为使用正确的状态数据处理每个请求,常用Cookie对用户会话进行唯一标识。

浏览器会存储 cookie 并在下次向同一服务器再发起请求时携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。

Cookie 一般由一个 名/值 对组成(id=12345),也可以包含任何不含空格的字符串。

除Cookie的实际值外,Set-Cookie消息头还可以包含以下可选属性,用它们控制浏览器处理Cookie的方式。

HTTP头作用
expires用于设定Cookie有效时间,此时间内cookie一直有效(如没有则关闭浏览器失效)
domain用于指定cookie的有效域,这个域必须和收到Cookie的域相同,或是它的父域
path指定cookie的有效URL路径
secure如果设置这个属性,则仅在HTTPS请求中提交Cookie
HTTPOnly如果设置这个属性,将无法通过客户端javascript直接访问Cookie

HTTP 身份验证

HTTP 提供一个用于权限控制和认证的通用框架。最常用的 HTTP 认证方案是 HTTP Basic authentication。

**Basic:**基础认证,使用用户的 ID/密码作为凭证信息,并且使用 base64 算法进行编码。

使用BurpSuite的 Intruder模块自定义迭代器base64编码payload后请求可攻击基础认证。

Tomcat默认的认证方式就是HTTP basic认证,当然常用啊Apache和Nginx也可以设置基础认证。

使用 Apache 限制访问和基本身份验证

要对 Apache 服务器上的目录进行密码保护,你需要一个 .htaccess 和 a .htpasswd 文件。

.htaccess 文件格式通常看起来像这样:

AuthType Basic
AuthName "Access to the staging site"
AuthUserFile /path/to/.htpasswd
Require valid-user

.htaccess 文件引用一个 .htpasswd 文件,其中每行用冒号(“:”)分隔的用户名和密码。你不能看到真实的密码因为它们是 encryptedopen in new window (在这个例子中是使用了 MD5). 你可以命名.htpasswd 文件 为你所喜欢的名字,但是应该保证这个文件不被其他人访问。(Apache 通常配置阻止访问 .ht* 类的文件).

aladdin:$apr1$ZjTqBB3f$IF9gdYAGlMrs2fuINjHsz.
user2:$apr1$O04r.y2H$/vEkesPhVInBByJUkXitA/

Nginx 访问限制和基本认证

在 nginx 配置中,对需要保护的 location 你需要做如下配置:auth_basic 指令提供密码保护域的名称;auth_basic_user_file 指令指定包含用户密文的证书的文件(与 apache 例子中一致)

在 nginx 中,你需要指定一个保护区域和该 auth_basic 指令提供的保护区域名字。然后该 auth_basic_user_file 指令指向一个.htpasswd 包含加密用户凭据的文件,就像上面的 apache 例子。

location /status {
    auth_basic           "Access to the staging site";
    auth_basic_user_file .htpasswd;
}

在线生成.htpasswd https://www.sojson.com/htpasswd.htmlopen in new window

HTTP代理

当配置浏览器使用代理服务器时,它会将所有的请求提交到代理服务器,代理服务器再将请求转给Web服务器。常用的代理服务器软件有BurpSuite和Fiddler。

如果使用代理服务器,HTTP工作机制会出现两方面差异:

(1) 当使用代理服务器发布HTTP请求时,它会将完整的URL插入请求中,代理服务器将提取主机名和端口,用这些信息将请求指向正确的目标Web服务器

(2) 当使用HTTPS时,浏览器无法与代理服务器进行SSL握手,因为这样会破坏隧道,使通信遭受拦截攻击,因此浏览器必须将代理作为一个纯粹的TCP中继,一直开放TCP连接

HTTP/1.1新特性

一、 默认持久连接,Connection: keep-alive

二、 管线化 ( pipelining ),客户端可以同时发出多个HTTP请求,而不用一个个等待响应

三、 断点续传。实际上就是利用HTTP消息头使用分块传输编码,将实体主体分块传输

利用新特性有两种Bypass WAF(绕过Web应用防火墙)的方法。