这是一份关于HTTP协议的学习总结

前言

随着互联网的发展,网络已经愈来愈普及了,绝大多数的网络请求都是基于HTTP协议的,所以在开发中,了解HTTP的基本原理是必要的,在TCP/IP四层体系结构中,HTTP协议位于应用层,它是应用层主要使用的协议,应用层往下一层就是运输层,HTTP在运输层采用的是TCP协议来保证可靠传输,知道这些后,接下来详细介绍一下 Http。html

1、HTTP协议版本演变

咱们先来简单了解一下 HTTP 协议的历史演变:git

  • HTTP/1.0:1996年,HTTP/1.0 版本发布,能够传输文字,图像、视频、二进制文件,它的特色是每次请求都须要创建一个单独的TCP链接,发送数据完毕,链接就关闭,若是还要请求其余资源,就必须再新建一个链接,上一次请求和下一次请求彻底分离,这种非持续链接过程又叫作短链接。它的特色也是它的缺点,客户端和服务端每次请求都要创建TCP链接,而创建TCP链接和关闭TCP链接都是相对比较费时的过程,严重影响客户端和服务端的性能。
  • HTTP/1.1:1997年,HTTP/1.1 版本发布,1999年普遍应用于各大浏览器网络请求中,直到如今HTTP/1.1也是使用最为普遍的HTTP协议,它进一步完善了HTTP/1.0,HTTP/1.1支持在一个TCP链接上传送多个HTTP请求和响应,即一个TCP链接能够被多个请求复用,减小了创建和关闭链接的消耗延迟,必定程度上弥补了HTTP/1.0每次请求都要建立链接的缺点,这种持续链接过程又叫作长链接,HTTP/1.1默认使用长链接。
  • HTTP/2.0:2015年,HTTP/2 .0版本发布,前面的两个版本都是基于超文本的协议,HTTP 2.0把基于超文本的协议改为了基于二进制的,把HTTP请求和响应变成数据帧,这样易于实现多路复用,在一个TCP链接上能够同时“混合”发送多个HTTP的请求和响应,效率大大提升。

长链接和多路复用的区别算法

上面讲到HTTP/1.1的长链接和HTTP 2.0的多路复用都是复用TCP链接,它们之间有什么区别呢?在讲解它们的区别以前先来聊一聊HTTP/1.1的长链接,HTTP/1.1的长链接能够分为非流水线和流水线工做方式:数据库

  • 非流水线:在同一个TCP链接下,客户端的下一个请求只有收到当前请求的响应后才能发出;
  • 流水线:又称Pipelining、管道化,在同一个TCP链接下,客户端能够连续的发送请求,而不用等待响应返回,当请求一个接着一个到达服务器时,服务器可以连续发回响应;

如图:api

因此你会发现非流水线工做方式的长链接的若干个请求只能排队发送,后面的请求等待前面请求的响应返回才能得到执行机会,一旦有某请求处理超时,后续请求只能被阻塞,这样会致使TCP链接空闲,浪费资源;而流水线工做方式的长链接就能够连续的发送多个请求而没必要等待响应的返回,这样看起来效率提升了一些。浏览器

因此流水线工做方式就是好的吗?这里根据我查到的资料是:Pipelining在现代浏览器中是默认关闭的,由于因为技术和安全的关系,实现Pipelining在HTTP/1.X上是很复杂,同时Pipelining技术不支持全部的请求方法,并且就算开启了,因为队头阻塞的存在,它的效率也不会提升多少,假设多个请求按顺序 (现实状况可能因为网络拥堵不会按顺序到达) 到达服务端,多个请求会在服务端缓存那边排队,若是第一个请求处理时间过长,会致使后面的请求阻塞,并且颇有可能后面有优先级更高的请求,这样致使高优先级请求不能被优先处理,因此无论有没有流水线工做方式,请求仍是要排队处理,队头阻塞仍是存在,流水线工做方式只能说是对非流水线方式的一种改进。缓存

那么就没有办法提升响应效率了吗?为了解决这些问题,HTTP1.x支持在同一个域名(host)下创建多个TCP链接,现代浏览器支持同时创建5~10个TCP链接,即支持并行发送请求,每一个浏览器都有一个Max-Connection最大链接限制,例如谷歌浏览器的Max-Connection值为6,即同一个域名下最多创建6个TCP链接,一次最多同时发送6个请求,超过限制后续请求就会被阻塞。安全

因此,综上所述,因为Pipelining技术在浏览器中默认是关闭的,因此HTTP1.1长链接的工做方式是非流水线形式,为了实现并行发送请求只能经过创建多个TCP链接,这在HTTP1.x时代中已经很不错了,可是随着技术的发展,如今一个网站每秒简简单单就上百个请求,而频繁的创建和保留TCP链接又是一件工做量不小的工做,因此并行TCP链接带来的效率有时也会很低。服务器

因此为了解决以上全部问题,HTTP/2.0就诞生了,HTTP/2.0的多路复用(multiplexing)才是作到了同一个TCP链接下的真正的并发请求,多个请求可同时在一个TCP链接上并行发送,某个请求任务超时,不会影响到其它链接的正常执行,并且每一个请求均可以分配优先级,优先级高的先执行。cookie

如图:

HTTP/2.0从协议的层面改进了HTTP,是将来的应用,对于HTTP2.0的更多优势能够查看HTTP2.0新特性, 因为HTTP/2.0还未大规模应用,因此下面的讨论都是围绕HTTP/1.x

HTTP1.1的长链接在浏览器中是默认开启的,经过指定首部Connection:Keep-Alive,后面会讲到长链接的工做原理。

2、HTTP工做过程

HTTP是基于TCP的应用层协议,从更高层次封装了TCP的使用细节,使得网络操做更为简单,一个HTTP请求就是一个典型的C/S模式,HTTP协议首先要和服务端创建TCP链接,当创建TCP链接的三报文握手的前两次报文握手完成后,在第三次握手,客户端就把HTTP请求报文做为第三个握手报文的数据发送给服务端,服务端收到请求报文后,就把所请求的文档做为响应报文返回给客户端,以下:

HTTP的工做特色能够总结为如下3点:

  • 一、面向无链接的:即通讯双方在交换HTTP报文时不须要向创建HTTP链接,但HTTP使用了面向链接的TCP做为运输层协议;
  • 二、无状态的:服务端不会记得每一个客户访问的状态,同一个客户访问两次服务端上的页面时,服务端响应与第一次访问相同,因此出现了Cookie/Session机制维护链接的状态;
  • 三、面向事务的:即对一系列信息的交换,要么全部信息交换都完成,要么一次交换都不进行。

3、HTTP的请求方法

HTTP协议提供了几种请求方式,你们熟知的请求方式有8种GET、POST、DELETE、PUT、HEAD、TRACE、OPTIONS、CONNECT,其中最经常使用的是PUT(增)、DELETE(删)、POST(改)、GET(查)。下面以一张表来看看它们各自的做用。

请求 做用
GET 获取资源:客户端经过URL获取服务端中的某个资源,请求参数放在URL中,而后服务端返回对应资源给客户端
POST 传输实体主体:POST请求一般会用来提交HTML表单,把数据填在表单中,传给服务器,而后服务器对这些数据进行处理,虽然GET方法也能够用来传输主体实体,可是通常采用POST方法
PUT 传输文件:与GET相反,PUT向服务器写入数据,通常用来传输文件,把须要传输的文件放在请求报文的主体上,而后保存到URL指定的位置
DELETE 删除文件:与PUT相反,DELETE请求求服务器删除URL所指定的资源,请求参数放在URL中,可是服务端能够在客户端不知情下撤销此请求
HEAD 获取报文首部:HEAD与GET相似,但服务器在响应中只返回首部不会返回主体部分,HEAD是用来在不获取资源的状况下获取资源的首部进行检查,如查看响应的状态码,看看资源是否被修改,对象是否存在
TRACE 追踪路径:客户端发起一个请求时,可能要穿过防火墙,代理,网关等,每个中间点都会修改HTTP原始请求报文,TRACE容许请求最终发送给服务端时,看看它最终变成什么样,服务端会返回一个状态码200 OK的响应报文,报文主体包含了TARCE信息
OPTIONS 询问支持的方法:OPTIONS询问服务端支持的用来查询指定URL资源的方法,这就让客户端不用访问那些实际的资源就能断定访问各类资源的最优方法
CONNECT 要求使用隧道协议链接代理:CONNECT要求在与代理服务器通讯时创建隧道,实现用隧道进行TCP通讯,隧道就是通过加密的通讯信路,通常使用SSL/TLS协议把通讯内容加密后经隧道传输

HTTP/1.0支持的方法有:

GET、POST、PUT、HEAD、DELETE;

HTTP/1.1新增的方法有:

OPTIONS、TARCE、CONNECT。

代理服务器:代理服务器是一种具备转发功能的服务器,它扮演了服务器和客户端之间的中间人角色,它能够接收客户端发来的请求并转发给服务端,也能够接收服务端返回的响应并转发给客户端,在这个过程当中它不会改变任何URL,报文每通过一个代理服务器,都须要在首部via字段的末尾插入一个能够表明代理服务器的独特的字符串, 代理服务器主要做用有:缓存代理(减小网络带宽)、访问控制(提升安全性)等。

4、HTTP的报文格式

用于HTTP协议交换的信息称为HTTP报文,客户端发出的HTTP报文叫作请求报文,服务端返回的HTTP报文叫作响应报文,它们都是由多行数据构成的字符串文本,用CR + LF (回车符 + 换行符) 做为换行符,HTTP报文大致分为报文首部报文主体两块,由第一个出现的空行(CR + LF)划分,其中报文主体不是必须的,以下:

其中报文首部又能够分为:开始行、首部行;开始行根据报文的不一样又分为:请求行、状态行;首部行根据报文的不一样与首部字段的做用又能够分为:请求首部字段、响应首部字段、通用首部字段、实体首部字段。

下面分别简单介绍一下HTTP的请求报文和响应报文:

一、请求报文

一个HTTP的请求报文一般由请求行,请求首部,空行(CR + LF),请求主体4个部分组成,如图:

  • 请求行

    又叫起始行,就是报文的第一行,在请求报文中说明要以什么方式作什么请求;

  • 请求首部

    又叫首部,在请求行以后,由零个或多个首部字段组成,每一个字段包含一个key和value,用冒号 : 分割,如Connection:keep-Alive,每一个首部字段以一个CR + LF结束;

  • 请求主体

    又叫主体,其中能够包含任意类型的数据,如图片,视频、文本等,而请求首部和请求行只能是文本形式,在请求主体中包括了要发送给Web服务端的数据。

不一样的请求方式,它们的请求报文格式可能有点差异的,有些请求方式它的请求主体为空,有些则不为空,可是请求行和请求首部是必须存在的,下面以GET、POST请求报文举例:

1.一、GET的请求报文

对于GET方法来讲,它全部的请求参数都是拼接在URL最后,第一个参数前经过"?"链接,而后请求参数按照"key=value"格式进行追加,每一个请求参数之间经过"&"链接,如 :

www.myhost.com/text/?id=1&…

这个URL对于GET请求表示获取 www.myhost.com/text/ 位置下用户id为1名为rain的文本,相应的请求报文格式以下:

GET /text/?id=1&name=rain HTTP/1.1
Host: www.myhost.com
Cache-Control: no-cache
复制代码

从上面的HTTP请求报文格式知,第一行为请求行,代表请求方式为GET,子路径为 /text/?id=1&name=rain,HTTP版本为1.1,后两行为请求首部,Host为主机地址,Cache-Controlno-cache,表示客户端不接受服务端缓存过的资源,而GET的请求参数都在URL中,因此请求主体为空。

注意:对于URL的最长长度,不一样的浏览器又不一样的限制,大约为1024字节(1KB)。

1.二、POST的请求报文

对于POST方法来讲,它们的报文格式通常是表单格式,也就是说请求参数存储在请求主体位置上,以下:

POST /local/ HTTP/1.1
Host: www.myhost.com
Accept-Encoding:gzip
Content-Length: 222222
Content-Type: multipart/from-data;boundary=dRGP2cPPTxE6WRTssnh4jC7HJLcSde
Connection:Keep-Alive

--dRGP2cPPTxE6WRTssnh4jC7HJLcSde
Content-Disposition:from-data;name=“username”  //name = username
Content-Type:text/plain:charset=UTF-8
Content-Transfer-Encoding: 8bit

rain										//value = rain
--dRGP2cPPTxE6WRTssnh4jC7HJLcSde
Content-Diaposition:from-data:name="image"      //name = image
filename="/storage/emulated/0/image/1234.png"
Content-Type:application/octet-stream
Content-Transfer-Encoding:binary

//...省略二进制数据					        //value = 二进制数据
--dRGP2cPPTxE6WRTssnh4jC7HJLcSde--
复制代码

上述的请求报文的含义是向 www.myhost.com/local/ 这个地址发送一个POST请求,接受的内容编码方式为gzip,请求的数据长度为222222字节,请求的数据格式为 multipart/from-data(表单),报文的boundary值为dRGP2cPPTxE6WRTssnh4jC7HJLcSdeKeep-Alive为开启长链接,空行以后,接下来就是请求报文的主体,主体有两个请求参数:

一个是名为username值为rain的文本;

一个是名为image值为二进制数据的图片.

请求参数是以两横杠+boundary开始的,而后是请求参数的一些首部,又称实体首部字段,如参数名,格式等,而后加上一个空行,最后才是参数的值,如上述的username=name,其表示以下:

--dRGP2cPPTxE6WRTssnh4jC7HJLcSde		       //两横杠加boundary做为参数的开始
Content-Disposition:from-data;name=“username” //name = username
Content-Type:text/plain:charset=UTF-8
Content-Transfer-Encoding: 8bit
						                    
rain						                 //value = rain
复制代码

当报文主体中包含多个参数时,都要遵照这种格式:每一个参数以两横杠+boundary分隔,参数首部字段与值之间有一个空行

请求主体的最后是以两横杆+boundary+两横杠做为整个报文的结束符,如上面报文的最后一个参数 (图片二进制数据) 最后的**- -dRGP2cPPTxE6WRTssnh4jC7HJLcSde- -**,以下:

--dRGP2cPPTxE6WRTssnh4jC7HJLcSde			 //两横杠加boundary做为参数的开始
Content-Diaposition:from-data:name="image"    //name = image
filename="/storage/emulated/0/image/1234.png" 
Content-Type:application/octet-stream
Content-Transfer-Encoding:binary
										  //不可省略的空行
//...省略二进制数据						  //value = 二进制数据
--dRGP2cPPTxE6WRTssnh4jC7HJLcSde--	          //整个报文的结束符
复制代码

二、响应报文

一个HTTP的响应报文一般由状态行、响应首部、空行(CR + LF)、响应主体组成,以下:

  • 状态行

    在响应报文中粗略的说明了报文的执行结果;

  • 响应首部

    又叫首部,在状态行以后,由零个或多个首部字段组成,每一个字段包含一个key和value,用冒号 : 分割,每一个首部以一个CR + LF结束;

  • 响应主体

    其中能够包含任意类型的数据,如图片,视频、文本等,而首部和状态行只能是文本形式,在响应主体中包含了服务端要返回给客户端的数据.

能够看到响应报文与请求报文的格式相似,最大的不一样的就是第一行用状态信息代替了请求信息,格式以下:

HTTP-Version Status-Code Reason-Phrase CRLF
复制代码

其中HTTP-Version表明HTTP协议版本,Status-Code表明响应状态码,Reason-Phrase表明状态码的文本描述,其中状态码的5种取值范围以下:

取值范围 含义
100~199 信息状态码,表示请求已被接收,正在处理
200~299 成功状态码,表示请求已被成功处理
300~399 重定向状态码,表示完成请求必需要进行进一步的操做
400~499 客户端错误状态码,表示客户端请求有语法错误或请求没法实现
500~599 服务端错误状态码,表示服务端处理请求时出错

例如这是一个GET请求的返回的响应报文格式:

HTTP1.1 200 OK
Data:Sat, 30, Dec 2006 23:23:00 GMT
Content-Type:text/html;charset=UTF-8
Content-Length:852

<!DOCTYPE html>
<html lang="zh-CN">
	//...省略文档内容
</html>
复制代码

上面HTTP响应报文表示,HTTP协议版本为1.1,响应状态码为200,表示请求成功,返回数据的类型为text/html(html), 编码为UTF-8,返回数据的内容长度为852字节,空行以后,接下来就是返回的数据,是一个html文档。

5、常见的状态码

状态码的职责是当客户端向服务端发送请求时,描述服务端返回的请求结果,借助状态码,咱们就能够得知服务端是正常处理了请求,仍是出现了错误,下面是开发中常常碰见的状态码:

一、2XX成功

2XX的响应结果表示请求被正常处理了.

  • 200 OK:该状态码表示从客户端发来的请求在服务端被正常处理了,在返回的响应报文中,随状态码返回的信息会由于请求方法的不一样而不一样。例如GET方法,响应报文的主体会包含请求的资源,而对于HEAD方法,响应报文不包含主体部分,只包含响应首部;
  • 204 No Content:该状态码表示服务端接收的请求已成功处理,可是在返回的响应报文中不包含主体部分,这说明请求处理成功,可是没有任何资源返回。好比当浏览器发出的请求处理后,返回204响应,那么浏览器显示的页面将不会发生任何更新;
  • 206 Partial Content: 该状态码表示客户端进行了范围请求,而服务端成功返回了这一部分范围的资源,即响应报文的主体部分中会包含由Content-Range指定范围的内容。

二、3XX重定向

3XX的响应结果表示客户端须要执行某些特殊操做后,服务端才能继续处理请求.

  • 301 Moved Permanently:永久性重定向,该状态码表示请求的资源已被分配了新的URL,之后都应使用新的URL来访问该资源,这时响应报文首部的Location字段会提示新的URL。例如你使用这个最后忘记加斜杠 / 的地址 www.myhost.com 来访问服务端,就会返回301状态码,提示你使用正确的地址访问,不过这些重定向的操做浏览器在背后已经替咱们处理了,因此用户是没法感知的;
  • 302 Found:临时重定向,该状态码表示请求的资源暂时被分配了新的URL,本次应使用新的URL来访问该资源,302和304的区别就是一个是临时性,一个是永久性,302表明资源不是被永久移动,而是临时移动,即本次会重定向到地址a,下一次可能会重定向到地址b或者不变,因此响应报文首部的Location字段提示的新URL并非永久性的,而是临时性的;
  • 303 See Other:临时重定向,该状态码表示请求的资源暂时被分配了新的URL,本次应使用新的URL经过GET方法来访问该资源,303和302功能类似,可是303明确表示客户端重定向时应采用GET方法获取资源,而302就没有这个要求。(可是在现实中,大部分浏览器都没有遵循规范,无论是30一、302仍是303,都会把POST改为GET,而后从新获取资源);
  • 304 Not Modified:304虽然被划分在3XX中,可是它和重定向没有任何关系,该状态码表示客户端访问的资源存在,可是未符合请求的附带条件,不允返回,这时返回的304响应报文不包含主体部分,请求的附带条件是指请求报文中包含If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since中任一首部。例如客户端想要检查本地资源缓存是否过时,就在GET请求中附带If-Modified-Since条件,If-Modified-Since的值是本地资源的Last-Modified(上一次修改时间)的值,服务端接收请求后,就会检查资源在服务端的上一次修改的时间是否比If-Modified-Since的值更新,若是没有,说明资源没有被修改过,返回304响应报文,告诉客户端能够继续使用本地缓存。(关于HTTP的缓存机制能够查看HTTP 协议缓存机制详解 )。

三、4XX客户端错误

4XX的响应结果表示客户端发生错误的缘由所在.

  • 400 Bad Request:该状态码表示客户端的请求报文中有语法错误,不能被服务端理解,当发生该错误后须要修改请求内容后再次发送;
  • 401 Unauthorized:该状态码表示发送的请求须要有经过HTTP认证的认证信息,401的响应报文会包含一个被请求资源的WWW-Authenticate首部用来质询用户信息,当浏览器初次接收到401响应,会弹出认证窗口,当浏览器第二次收到401响应,表示认证失败;
  • 403 Forbidden:该状态码表示服务端收到了请求,可是拒绝提供服务,服务端不会给出拒绝的详细理由,例如没有文件的访问权限等都会返回404响应;
  • 404 Not Found:该状态码表示请求资源在服务端上不存在,或者服务端拒绝请求但不想说明理由也会返回404;

四、5XX服务端错误

5XX的响应结果表示服务端发送错误的缘由所在.

  • 500 Internal Server Error:该状态码表示服务端执行请求时发生了不可预估的错误,它代表服务端Web应用存在bug或其余故障;
  • 503 Server Unavailable:该状态码表示服务端当前不能处理客户端请求,一段时间后可能恢复正常,它代表服务端暂时处于超负载或停机维护状态,若是服务端得知故障恢复时间,它会在响应报文的Retry-After首部字段写入返回给客户端。

更多状态码信息请访问HTTP状态码

6、常见的首部字段

下面列举了HTTP/1.1中的47种常见首部字段,分为通用首部字段、请求首部字段、响应首部字段、实体首部字段:

一、通用首部字段

表示请求报文和响应报文双方都会使用的首部。

首部字段名 说明
Cache-Control 控制缓存的行为
Connection 容许客户端和服务端指定与请求/响应链接相关的选项
Date 建立报文的日期时间
Pragma 报文指令
Trailer 报文末端的首部一览
Transfer-Encoding 告知接收端为了保证报文的可靠传输性,对报文采用了什么的编码方式
Upgrade 升级为其余协议
Via 代理服务器的相关信息
Warning 错误通知

二、实体首部字段

表示请求报文和响应报文的主体的实体部分使用的首部,主要做用是补充资源内容的更新时间与实体相关的信息,能够看到大多都是以Content开头的。

首部字段名 说明
Allow 资源可支持的 HTTP 方法
Content-Encoding 实体主体适用的编码方式
Content-Language 实体主体的天然语言
Content-Length 实体主体的大小
Content-Location 替代对应资源的 URI
Content-MD5 实体主体的报文摘要
Content-Range 实体主体的位置范围
Content-Type 实体主体的媒体类型
Expires 实体主体过时的日期时间
Last-Modified 资源的最后修改日期时间

三、请求首部字段

表示从客户端向服务端发送请求报文时使用的首部,主要做用是补充请求的附加内容、客户端信息、响应内容相关优先级、编码等信息。

首部字段名 说明
Accept 客户端可识别的内容类型列表
Accept-Charset 客户端可识别的字符集
Accept-Encoding 客户端可识别的数据编码
Accept-Language 客户端可识别的语言(天然语言)
Authorization Web 认证信息
Expect 期待服务器的特定行为
From 用户的电子邮箱地址
Host 请求的主机名
If-Match 比较实体标记(ETag)
If-Modified-Since 比较资源的更新时间
If-None-Match 比较实体标记(与 If-Match 相反)
If-Range 资源未更新时发送实体 Byte 的范围请求
If-Unmodified-Since 比较资源的更新时间(与 If-Modified-Since 相反)
Max-Forwards 最大传输逐跳数
Proxy-Authorization 代理服务器要求客户端的认证信息
Range 实体的字节范围请求
Referer 对请求中 URI 的原始获取方
TE 传输编码的优先级
User-Agent 发出请求的浏览器类型,能够自行设置

四、响应首部字段

表示服务端向客户端返回响应报文时使用的首部,主要做用是补充响应的附加内容、要求客户端附加额外的内容等信息

首部字段名 说明
Accept-Ranges 是否接受字节范围请求
Age 推算资源建立通过时间
ETag 资源的匹配信息
Location 令客户端重定向至指定 URI
Proxy-Authenticate 代理服务器对客户端的认证信息
Retry-After 对再次发起请求的时机要求
Server HTTP 服务器的安装信息
Vary 代理服务器缓存的管理信息
WWW-Authenticate 服务器对客户端的认证信息

下面列举几个对HTTP首部的常见使用。

五、具体应用

5.一、 长链接原理

从HTTP/1.1起,默认都开启了长链接保持链接特性,经过在首部指定Connection:Keep-Alive,Keep-Alive也是一个首部,简单地说,当一个网页打开完成后,客户端和服务端之间用于传输HTTP数据的TCP链接不会关闭,若是客户端再次访问这个服务端上的网页,会继续使用这一条已经创建的TCP链接,Keep-Alive不会永久保持链接,它有一个保持时间,能够在不一样服务端软件中设置这个时间。

那么,长链接是如何工做的呢?长短链接是运输层(TCP)的概念,HTTP是应用层协议,它只能说告诉运输层我打算一段时间内复用TCP通道,而没有本身去创建、释放TCP通道的能力,那么HTTP是如何告诉运输层复用TCP通道的呢?分为如下几个步骤:

  • 一、客户端第一次发送请求报文时,顺带发送一个Connection: Keep-Alive的Header,表示须要保持链接,同时客户端能够顺带发送Keep-Alive: timeout=5, max=100这个Header给服务端;
  • 二、而后服务端识别Connection: Keep-Alive这个Header,而且经过响应报文Header带一样的Connection: Keep-Alive,告诉客户端我能够保持链接;
  • 三、客户端和服务端之间经过保持的TCP链接收发数据;
  • 四、当客户端最后一次发送请求报文,顺带发送Connection:close这个Header,表示长链接关闭。

Keep-Alive: timeout=5,max=100表示TCP链接空闲时最多保持5秒,长链接接受100次请求就断开,长链接虽好,可是长时间的TCP链接容易致使系统资源无效占用,浪费系统资源,因此须要有一些限制。

Connection首部除了用于管理链接外,还能控制再也不转发的首部,格式为:Connection: 再也不转发的首部,当通过代理服务器时,代理服务器会把Connection首部字段中指定的首部删除后,再把报文转发给服务端。

5.二、内容协商

一个网站在服务器中可能有多种语言版本、有多份相同内容的页面,例如英文版的网页和中文版的网页,在HTTP通讯时客户端与服务端进行内容协商,让服务端返回最合适的内容给客户端,内容协商会以类型、字符集、编码、语言等方式为标准返回合适的响应资源。

客户端能够在请求报文中设定特定的Accept-XX首部字段,例如 Accept、Accept-Charset、Accept-Encoding、Accept-Language等,服务端根据这些字段返回特定的资源,这些字段的解释以下:

  • Accept

    示例:Accept: text/html,image/jepg;q=0.8,video/mpeg;q=0.5,*/*;q=0.1

    客户端在Accept首部中列举了它支持的内容类型,服务端从这些内容类型中挑选出一个优先级最高的类型,返回这个类型的内容给客户端,内容类型通常是type/subtybe形式,例如文本类型text/html、text/plain、...,图片类型image/jepg、image/gif、...,视频类型video/mpeg、...,等,多个类型之间用逗号 , 分隔,能够用 * 通配符表示接受全部类型,经过q表示优先级,与类型用分号 ; 分隔, q值越大,优先级越高,q值得范围是(0~1),若是不指定优先级,默认优先级都是1.0,内容类型放置顺序按优先级排序;

  • Accept-Charset

    示例:Accept-Charset: iso-8859,unicode-1-1;q=0.5

    客户端在Accept-Charset首部中列举了它支持的字符集,服务端从这些字符集中挑选出一个优先级最高的字符集,返回这个字符集的内容给客户端,与Accept相同,能够经过q指定字符集的优先级,而且和Accept同样,字符集的放置顺序按优先级排序;

  • Accept-Encoding

    示例:Accept-Encoding: gzip,compress,deflate;q=0.5

    客户端在Accept-Encoding首部中列举了它支持的内容压缩格式,服务端从这些内容压缩格式中挑选出一个优先级最高的,把响应内容用这种格式压缩后再返回给客户端,客户端收到压缩的内容后,用相应的解压算法解压内容,再显示出来,与Accept相同,能够经过q指定优先级,经过 * 通配符表示支持任意压缩格式;

  • Accept-Language

    示例:Accept-Language: zh-cn,en-us;q=0.5

    客户端在Accept-Language首部中列举了它支持的语言,服务端从这些语言中挑选出一个优先级最高的,返回相应语言版本的内容给客户端,若是没有优先级最高的语言版本,就返回次优先级的语言版本,例如示例中,没有中文版时,就返回英文版。

当服务器从各类选择列表中挑选出客户端支持的类型、字符集、编码、语言后,就会在响应报文的首部指定Content-XX首部字段,告诉客户端响应内容的类型、字符集、编码、语言,例如Content-Type、Content-Encoding、Content-Language等,Content-Type表示内容类型,还会指明内容的字符集,Content-Encoding表示内容的编码类型,Content-Language表示内容的语言。

上述的内容协商叫作服务器驱动协商,即由客户端经过首部告诉服务端它支持的东西,而后服务端作出选择,可是对于用户来讲,浏览器替咱们作的决定不必定是最优的,例如我看不懂英文,浏览器根据代理地理位置作了判断,返回了英文版的内容,这然对用户来讲不是最优的,因此还有一种叫作客户端驱动协商,由用户告诉服务端他想要什么类型的内容,这时浏览器会弹出选择列表让用户选择,用户选择后,浏览器把用户的选择填入Accept-XX首部,再发送给服务端。

5.三、Cookie机制

Cookie是用来管理客户端和服务端之间的状态,它是服务器发送到客户端并保存在本地的小型文本文件,其内容为一系列的键值对,Cookie并不属于HTTP/1.x的规范,可是因为HTTP的无状态特性,Cookie被普遍应用于各大Web网站的状态管理及用户识别。

Cookie的工做过程主要使用到了Set-CookieCookie这两个首部,Set-Cookie首部存在于响应报文中,Set-Cookie首部包含服务端返回给客户端状态管理使用的Cookie信息,客户端收到响应后会从Set-Cookie首部中取出Cookie信息保存到本地;Cookie首部存在于请求报文中,Cookie首部包含客户端从服务端接收到的Cookie信息,每次客户端发起请求时,都会在请求报文的Cookie首部中携带Cookie信息发送给服务端。

Cookie须要和服务端的Session配合使用,Cookie是存储在客户端中,而Session是存储在服务器端中,Session是服务端保存用户状态的方式,它们的工做过程大概以下:

  • 一、当用户登录网站时,填入帐号、密码等信息,而后提交表单,这些信息会被放入HTTP的请求报文,而后发送给服务端;
  • 二、服务端收到请求后,验证该用户名和密码,若是正确,则为该用户建立一个Session对象,Session对象中保存了用户的状态信息,并生成Session对象的惟一ID,称为Session ID,而后把Session对象存储到内存或数据库中,根据Session ID根据从内存或数据库获取到Session对象;
  • 三、接着服务端把Session ID的值以name=value的形式放入响应报文的Set-Cookie首部中,其中name为Session ID的名字,value就是Session ID的值,name=value形式的Session ID就称为Cookie,Set-Cookie首部除了Session ID以外,还有一些其余信息,如Cookie的有效期、Cookie的域名范围等,而后把这个响应报文发送给客户端;
  • 四、客户端收到响应报文以后从Set-Cookie首部中取出全部Cookie信息,而后把它保存到本地,客户端有时候会收到不止一个Set-Cookie首部,若是有多个,每一个Set-Cookie首部中的Cookie信息都要保存;
  • 五、客户端以后对同一个服务端进行请求时都会从本地取出Cookie信息,这时能够校验Cookie的有效期、路径、域名等信息,而后取出其中的Cookie值放入请求报文的Cookie首部字段,若是有多个Cookie值,Cookie首部中就用 ; 分隔,而后把这个请求报文发送给服务端;
  • 六、服务器收到请求后,从Cookie首部中取出Cookie,从Cookie中取出Session ID,而后用Session ID从内存或数据库取出用户信息,恢复用户以前的操做状态。

下面是我登录掘金时在响应报文找到的Set-Cookie首部,以下:

HTTP/1.1 200 OK
//...省略不少首部
Set-Cookie: ab={}; path=/; expires=Fri, 15 Jan 2021 11:13:21 GMT; secure; httponly
Set-Cookie: auth.sig=nl1rsPof1lOURBJ1F81MyhGsoxs; path=/; expires=Thu, 23 Jan 2020 11:13:21 GMT; secure; httponly
Set-Cookie: QINGCLOUDELB=8015b18e7b6ee1bafcfd11812d999975a4db71eff5b47ab5974a1647066247c5|XiBFV|XiBFO; path=/; HttpOnly
Set-Cookie: auth=eyJ0b2tlbiI6ImV5SmhZMk5sYzNOZmRHOXJaVzRpT2lKdVNYTkJVVzlOWldwMWNuSkJjamQ2SWl3aWNtVm1jbVZ6YUY5MGIydGxiaUk2SWpNMWNYZzVhME52V21wMFNuUXdVbTRpTENKMGIydGxibDkwZVhCbElqb2liV0ZqSWl3aVpYaHdhWEpsWDJsdUlqb3lOVGt5TURBd2ZRPT0iLCJjbGllbnRJZCI6MTU3OTE3MTcxNTI0OCwidXNlcklkIjoiNWI0MzcxNzNlNTFkNDUxOTFkNzljMjdhIn0=; path=/; expires=Thu, 23 Jan 2020 11:13:21 GMT; secure; httponly
复制代码

能够看到它发送了4个Cookie给我,这个4个Cookie分别为ab=XX、_auth.sig=XX、_QINGCLOUDELB=XX、auth=XX,后面的一些path=XX、expires=XX、secure、httponly都是Cookie的附加信息,待会解释。

我随便点开几篇文章,它的请求报文里的Cookie首部都会携带上面的Cookie,以下:

GET /user/5b437173e51d45191d79c27a/posts HTTP/1.1
//...省略不少首部
Cookie: ab={};auth=eyJ0b2tlbiI6ImV5SmhZMk5sYzNOZmRHOXJaVzRpT2lKdVNYTkJVVzlOWldwMWNuSkJjamQ2SWl3aWNtVm1jbVZ6YUY5MGIydGxiaUk2SWpNMWNYZzVhME52V21wMFNuUXdVbTRpTENKMGIydGxibDkwZVhCbElqb2liV0ZqSWl3aVpYaHdhWEpsWDJsdUlqb3lOVGt5TURBd2ZRPT0iLCJjbGllbnRJZCI6MTU3OTE3MTcxNTI0OCwidXNlcklkIjoiNWI0MzcxNzNlNTFkNDUxOTFkNzljMjdhIn0=; auth.sig=nl1rsPof1lOURBJ1F81MyhGsoxs;QINGCLOUDELB=7526744c262201bf8ae89c7035a8ce8c9eb2c663a78c233d245e9356cc89386b|XiBG2|XiBG2;//省略了一些其余Cookie值
复制代码

能够看到Cookie首部都携带上了ab=XX、_auth.sig=XX、_QINGCLOUDELB=XX、auth=XX这4个Cookie。

挑一个Set-Cookie值解释一下它里面每一个属性的含义,以下:

Set-Cookie: ab={}; path=/; expires=Fri, 15 Jan 2021 11:13:21 GMT; secure; httponly
复制代码

能够看到服务器端返回的Set-Cookie首部值中,每一个属性用分号 ; 分隔,这些属性的解释以下:

属性 解释
NAME=VALUE 表示Cookie的名称和值,上面已经说过了,它是name=value形式的,在这里Cookie为ab={},ab就是名称,{}就是值,每个Set-Cookie首部都必需含有这个,在客户端发送请求时,Cookie会放在Cookie首部
path=路径 Path属性指定了服务端下的哪些路径能够接受Cookie值,以斜杠**/** 做为路径分隔符,子路径也会被匹配,在这里path=/,表示根目录包括根目录下的全部子路径均可以接受这个Cookie值
domain=域名 虽然上面举的例子里没有domain属性,可是domain属性经常和path属性一块儿指定Cookie的做用域, domain属性指定了哪些域名的服务端能够接受Cookie,若是指定了domain属性,子域名也会包含,例如设置 domain=.example.com,则 子域名www2.example.com也可使用这个Cookie,若是不指定,默认为当前服务端,但不包含子域名
expires=过时时间 expires属性表示Cookie的有效期,在服务端发送Cookie给客户端时,能够设定Cookie的过时时间,当省略expires属性时,Cookie的有效期仅维持到浏览器关闭以前,携带过时的Cookie给服务端是无效的,服务端发送过来的新的Cookie能够覆盖过时的Cookie
secure 含有secure属性表示仅在进行HTTPS链接时,才容许发送这个Cookie
httponly 含有httponly属性表示这个Cookie不能被JavaScript脚本调用,由于跨站脚本攻击 (XSS) 经常使用 JavaScript 的 document.cookie api窃取用户的 Cookie 信息,而Cookie附加了httponly属性后,document.cookie这个api就没法访问Cookie信息,从而避免了XSS,可是在Web页面内仍是能够对Cookie进行读取操做

跨站脚本攻击 (XSS): 是指攻击者诱用户进入圈套,由用户在不知情的状况下执行攻击代码,攻击者事先编写脚本植入到用户的浏览器页面,用户在运行这些页面时就会触发脚本,发起攻击,常见的攻击有:利用脚本窃取用户的Cookie值、利用虚假输入表单骗取用户我的信息、显示伪造的图片或文章等。

7、HTTPS是什么

一、HTTP的问题

讲到HTTP不得不讲HTTPS,HTTPS并不是一种新的协议,HTTPS就是安全版的HTTP,因为HTTP设计简单,使用简单,致使了它存在了大量安全问题,主要体如今如下三个方面:

  • 一、HTTP通讯双方使用不加密的明文,内容可能会被窃听:HTTP是使用明文在网络上进行报文的传输,而在网络上进行传输的任何内容,都有可能被截获,例如经过一些Wireshark、Fiddler等抓包工具就能够抓取HTTP的报文,从而查看报文中的内容,而报文中的内容是未通过加密的明文,那么一些重要的信息就被别人窃取到了;
  • 二、HTTP没法验证报文的完整性,因此报文有可能遭到篡改:没法验证报文的完整性是指通讯方收到这个报文时,没法证实这个报文没有通过中间人的篡改,没法判断报文中的信息是否正确,由于HTTP在发出请求到接收响应的这段时间内,有可能被其余中间人拦截报文,中间人拦截后可能会把报文中的信息作了一些恶意的修改后才发送给通讯双方,这样通讯方收到报文后,就没法得知报文内容的正确性,虽然HTTP有消息摘要校验方法,可是不可靠;
  • 三、HTTP通讯不验证通讯方的身份,所以有可能遇到假装的通讯方:HTTP是基于请求/响应的方式工做,只要客户端发出请求,服务端就要返回响应,在这个过程HTTP不会验证通讯双方的身份,因此颇有可能客户端会遇到假装的服务端,服务端会遇到假装的客户端,这样就会把一些重要的信息发送给假装者。

因此,为了解决以上3个安全问题,就出现了HTTPS。

二、HTTPS的解决办法

HTTPS使用加密 + 完整性保护 + 认证的方法解决上述3个问题,经过在HTTP的应用层与运输层之间加了一层SSL/TLS,以下:

HTTP协议运行在TCP之上,HTTPS协议运行在SSL/TLS之上,SSL/TLS协议运行在TCP之上,使用HTTPS,全部传输的内容都要经过SSL/TLS层,加密 + 完整性保护 + 认证的工做就在SSL/TLS层中进行,换句话说HTTPS = HTTP + SSL/TLS

SSL(Secure Socket Layer)与TLS(Transport Layer Security)都是安全性协议,TLS是以SSL为原型开发的协议,因此TLS是基于SSL,有时会把SSL和TLS统称为TLS,目前的主流使用是TLS1.二、TLS1.3。

下面简单讲解一下加密、完整性保护、认证的实现方式:

2.一、采用混合加密机制进行加密

为了防止报文内容被窃听,HTTPS采用了对称加密 + 非对称加密的混合加密机制。

  • 对称加密:算法是公开的,在对称加密算法中,加密和解密都是使用的同一个密钥,所以对称加密算法要保证安全性的话,密钥要作好保密,只能让使用的人知道,不能对外公开;

  • 非对称加密:算法是公开的,在非对称加密算法中,加密使用的密钥和解密使用的密钥是不相同的,用来加密的密钥叫作公钥,用来解密的密钥叫作私钥,公钥是公开的,全部人均可以得到,私钥就须要作好保密,只能让使用的人知道,不能对外公开,非对称密钥除了用来加密,还能够用来进行签名,由于私钥没法被其余人获取,所以通讯发送方使用其私钥进行签名(加密),通讯接收方使用发送方的公钥对签名进行解密,就能判断这个签名是否正确.

HTTPS在通讯的时候使用对称加密,可是使用对称加密就有一个问题,如何把密钥安全的发送给对方?若是简单的经过HTTP把密钥发送给对方,就有可能被中间人截获,这样对称加密就没有意义了,因此HTTPS采用了非对称加密来发送对称加密的密钥,这个过程以下:

一、首先服务端经过非对称加密算法生成一对密钥:公钥和私钥;

二、服务端把公钥发送给客户端,私钥本身保存;

三、客户端收到公钥后,利用公钥对对称加密使用的密钥S进行加密获得T,而后再发送给服务端;

四、服务端收到T后,利用私钥解密T,获得密钥S;

五、这样客户端和服务端都拥有了对称加密使用的密钥S,在以后的通讯过程当中就使用对称加密进行。

在这个过程当中,就算中间人获得了T和公钥,想要经过公钥把T破解获得密钥S是很是困难的,以目前的技术来讲,是几乎不可能实现,因此这样比直接发送密钥安全了不少。

综上所述,混合加密使得通讯过程的安全获得保证,上述是为了讲解方便,在实际中,对称密钥不会只在客户端生成的,它同时会在服务端生成,这在后面的HTTPS的通讯过程当中讲到。

既然非对称加密破解困难,安全,为何通讯时不一直使用? 首先非对称加密的运算比对称加密的运算复杂不少,运算速度慢,因此不可能一直使用非对称加密来通讯,而对称加密的运算速度比非对称加密快,效率高,因此,HTTPS就充分利用二者的优缺点,结合使用,在交换密钥时使用非对称加密保证安全,在通讯时使用对称加密保证安全和效率。

2.二、采用数字签名进行进行完整性保护

在讲解数字签名校验以前,先来说一下HTTP的消息摘要校验,又称散列值校验。

  • 消息摘要(Message Digest):原文经过MD五、SHA-1等散列值生成算法计算出的散列值就称为消息摘要,不管输入的消息有多长,它的输出长度老是固定的,而且输出值是随机的,消息摘要生成函数是单向函数,即没法经过消息摘要恢复到原文,消息摘要普遍应用于数字签名中。

HTTP的消息摘要校验过程是这样的:

一、服务端在发送报文以前,先用散列值生成算法生成报文的消息摘要,而后把报文和消息摘要一并发送给客户端;

二、客户端接收到报文和消息摘要后,就用相同散列值生成算法(已经协商过了)从新计算报文的消息摘要,若是从新计算的消息摘与发送来的消息摘要相同,就说明报文在中途没有被篡改过,不然被篡改过;

为何HTTP的消息摘要校验是不可靠的?假设中间人拦截了上述过程的报文,首先经过穷举法找出你所用的散列值生成算法,修改报文后,用散列值生成算法从新计算报文的消息摘要,而后替换掉本来的消息摘要,而后把修改后的报文和从新计算的消息摘要一并发给客户端,客户端按照上述相同的验证流程,会得出报文没有被篡改过的结论,但其实报文已经被被篡改过了,因此HTTP的消息摘要校验是不可靠的,HTTP的消息摘要校验不可靠主要在于中间人能够从新生成篡改后报文的消息摘要。

因此为了解决HTTP消息摘要校验的缺点,HTTPS采用了数字签名进行完整性保护,其中签名使用到了非对称加密的公钥和私钥。

  • 数字签名(Digital Signature):用私钥对原文进行加密后生成的密文称为数字签名,数字签名能够经过公钥进行验证,把数字签名经过公钥解密后,若是和原文相同,就说明原文是完整的,没有被篡改过。

因此采用了数字签名后,校验过程是这样的:

一、服务端在发送报文以前,先用散列值生成算法生成报文的消息摘要,而后再用私钥加密消息摘要生成数字签名,把数字签名与报文一块儿发送给客户端;

二、客户端接收到报文和数字签名后,先用相同的散列值生成算法从新计算报文的消息摘要,而后再用公钥解密数字签名获得报文的消息摘要,而后比较两份消息摘要是否相同,若是相同,说明报文在中途没有被篡改过,不然被篡改过;

HTTPS的数字签名是如何保证可靠性的?假设中间人截获了报文,把报文修改后从新生成消息摘要,可是中间人没有私钥对生成的消息摘要进行签名,由于私钥是保密的,这样他就没法从新生成新的数字签名,因为中间人没有办法生成修改后报文的数字签名,因此这就保证数字签名的可靠性,接收方收到数字签名和报文后,经过数字签名的校验流程,就能判断出报文的正确性。

综上所述,数字签名使得消息的完整性获得保证,在HTTPS中,数字签名通常会用到数字证书的传递上,下面会讲。

为何HTTPS要生成报文的消息摘后,再对消息摘要进行签名,而不对报文直接签名? 这是由于报文内容通常都很长,而报文的消息摘要输出的长度是固定,比报文长度短,这样经过私钥进行加密的运算量就大大减小,提升效率,因此当非对称加密与消息摘要结合使用后,便造成了一种高效又安全的数字签名方案。

2.三、采用数字证书进行身份认证

你们有没有发现,前面所讲的数字签名和混合加密技术,客户端都必须事先知道服务端的公钥,若是一开始公钥就被中间人篡改了,那么坏人就会被你当成好人,你就会拿着这把假的公钥和假的服务端通讯,因此如何保证公钥是真正的服务端颁发,又是另一个问题,为了保证公钥的安全可信,HTTPS经过数字证书来解决服务端的身份认证问题。

  • 数字证书(Digital Certificate):数字证书是由数字认证机构(Certificate Authority, 简称CA)颁发的公开密钥证书,它里面大概包含以下信息:

    一、发布机构(Issuer): 表示该证书是由哪一个机构(CA)颁发的;

    二、有效期(Validity): 表示证书的使用期限,过了有效期,证书就失效了

    三、名称(Subject):表示证书全部人的名字,这个证书是发给谁的,通常是某我的或者某个公司名称、机构的名称、公司网站的网址等;

    四、公钥(Public-Key): 表示证书全部人想要公布出去的公钥;

    五、签名算法(Signature algorithm): 表示证书的数字签名所使用的加密算法,这样就可使用证书发布机构的证书里面的公钥,根据这个算法对数字签名进行解密;

    六、数字签名(Digital Signature):表示证书发行者CA对该证书的数字签名,用于保证数字证书的完整性,确保证书没有被修改过.

数字认证机构是处于客户端和服务端双方都信赖的第三方机构,由CA颁发的数字证书必定是可靠、可信的,下面来简单介绍一下服务端向CA申请数字证书的流程:

一、服务端的运营人员向CA提交本身的公钥、组织信息、域名等信息,而后CA会经过各类渠道、各类手段来判断服务端的身份是否真实,是否合法等(在这里就能够杜绝中间人非法申请证书);

二、服务端的身份审核经过后,CA就会把服务端的公钥和证书的其余信息经过散列值算法生成一个消息摘要,而后用CA的私钥对消息摘要进行签名生成数字签名,而后把数字签名放入证书中,而后把这个证书颁发给服务端,因此数字证书最终包含服务端公钥 + 证书的数字签名 + 证书的其余信息,以下:

如今服务端拿到了数字证书,客户端第一次请求服务端时,服务端就会把这个数字证书发送给客户端,客户端收到数字证书后,就会用CA的公钥对数字证书进行数字签名的验证,若是验证经过,说明数字证书中途没有被篡改过,是可靠的,从而知道数字证书中的公钥也是可靠的,因此客户端就放心的取出数字证书中的公钥进行之后的HTTPS通讯。

在对数字证书的数字签名进行验证以前,必须先知道CA的公钥,由于数字证书的数字签名是由CA的私钥进行签名的,因此CA的公钥必须安全的转交给客户端,如何安全的转交又是一个困难的问题,因此,大多数浏览器开发商发布版本时,会事先在内部植入经常使用的CA机构的根证书, 这些根证书中会包含CA的公钥,也就是说CA的公钥已经内置在浏览器中了。

综上所述,数字证书能够确认服务端的身份,能够解决公钥的安全发放问题,同时数字证书也是经过数字签名来验证的。

浏览器内置的CA都是经常使用的、信任的CA机构,因此若是服务端发来的数字证书的相关CA机构恰好不在浏览器的内置CA列表中,浏览器就会找不到该数字证书的CA公钥,就会断定该数字证书是非法,这时浏览器会提示你手动安装该数字证书的CA机构的根证书,这个时候你就要本身承担风险了,颇有可能这个网站是不可信任的,安装了根证书后就能够拿到CA的公钥进行数字证书的验证,验证经过后就能与服务端通讯。

打开一个由HTTPS链接 (地址栏上有一个锁的标志) 的网站,经过如下方式查看它的数字证书,以下:

三、HTTPS的通讯过程

在进行HTTPS通讯前,必须先进行TCP三次握手创建TCP链接,而后进行TLS握手,进行完TLS握手后才会开始加密的HTTPS通讯,在TLS握手的过程当中主要进行密钥交换(对称加密使用的密钥)、身份认证等步骤,根据密钥交换时使用的算法不一样,TLS握手能够分为RSA握手和DH握手,目前主流的是DH握手,并且RSA握手因为它没有向前保密,已经在TLS1.3中被淘汰了,关于这两个握手算法的主要细节与区别能够查看下面文章,限于篇幅,本文不展开讨论:

Keyless SSL: The Nitty Gritty Technical Details

HTTPS篇之SSL握手过程详解

我经过抓取各大主流网站的TLS包发现,目前HTTPS使用的TLS版本几乎都是TLS1.2TLS1.3版本,下面的分析都是基于TLS1.2的DH握手过程,下面是我打开第一次打开csdn博客时抓取的TLS包(通过过滤后),以下:

其中info栏的信息表示TLS握手过程当中客户端和服务端之间交互时发送的TLS包的名称,有Server Key Exchange包表示它本次的握手类型是DH握手,上面的TLS握手过程能够用下图表示,以下:

上图省略了New Session Ticket包,New Session Ticket包是用于会话复用,并非必要的,省略它并不会影响对TLS握手过程的理解,在TLS握手完成以前,报文的传输都是明文,TLS握手过程的每一个步骤的解释以下:

  • 步骤1:客户端发送Client Hello报文给服务端,表示开始TLS握手,Client Hello报文中包含客户端支持的TLS版本(Version)、支持的加密组件列表(Cipher Suites)、客户端生成的随机数(Random)等信息;
  • 步骤2:服务端收到Client Hello报文后,若是能够开始进行通讯,就会发送Server Hello报文给客户端做为回应,Server Hello报文中包含支持的TLS版本(Version)、从加密组件列表中选择的加密组件(Cipher Suite)、服务端生成的随机数(Random)等信息,其中加密组件用于告诉客户端接下来身份认证、密钥交换、对称加密等过程使用的算法;
  • 步骤3:紧接着服务端就会发送Certificate报文,报文中包含服务端的数字证书,即公钥证书,客户端收到证书后,就会对服务端进行身份认证,身份认证使用的算法就是在步骤2协商好的认证算法,通常会使用RSA;
  • 步骤4:接着服务端就会发送Server Key Exchange报文,Server Key Exchange报文中包含服务端根据相应的DH算法生成DH参数(PubKey),这个DH算法就是在步骤2协商好的密钥交换算法;
  • 步骤5: 最后服务端发送Server Hello Done报文通知客户端它完成了TLS握手的一半,服务端到目前为止向客户端发送了服务端的随机数、证书、服务端的DH参数;
  • 步骤6:接下来客户端向服务端发送Client Key Exchange报文,Client Key Exchange报文中包含客户端根据相应的DH算法生成的DH参数(PubKey),这个DH算法一样是在步骤2协商好的密钥交换算法;
  • 步骤7:紧接着客户端就会使用在步骤1本身生成的随机数、在步骤2收到的服务端随机数、在步骤4收到的服务端DH参数、在步骤6本身生成的DH参数这四个参数,经过在步骤2协商好的对称加密算法来生成之后通讯过程当中使用的密钥,这里记为S,而后客户端就会发送Change Cipher Spec报文通知服务端对称加密使用的密钥生成完毕,接下来客户端向服务端发送的数据都会通过密钥加密;
  • 步骤8:最后客户端发送Encrypted Handshake Message报文通知服务端它完成了TLS握手的全部内容,Encrypted Handshake Message报文包含至今全部报文的总体校验值,并用*S加密,本次握手可否成功,取决于服务端可否解密这个报文,Encrypted Handshake Message报文下面的两个Application Data报文就是客户端通过加密后发给服务端的数据,客户端到目前为止向服务端发送了客户端的随机数、客户端的DH参数;
  • 步骤9:紧接着服务端就会使用在步骤2本身生成的随机数、在步骤1收到的客户端随机数、在步骤6收到的客户端DH参数、在步骤4本身生成的DH参数这四个参数,经过在步骤2协商好的对称加密算法来生成之后通讯过程当中使用的密钥,这里记为T,因为DH算法的保证:T == S,这样客户端和服务端都拥有了通讯加密使用的密钥,而后服务端就会发送Change Cipher Spec报文通知客户端对称加密使用的密钥生成完毕,接下来服务端向客户端发送的数据都会通过密钥加密;
  • 步骤10:最后服务端发送Encrypted Handshake Message报文通知客户端它完成了TLS握手的全部内容,Encrypted Handshake Message报文包含至今全部报文的总体校验值,并用*T加密,本次握手可否成功,取决于客户端可否解密这个报文。

若是客户端和服务端都成功解密了最后那个Encrypted Handshake Message报文,证实客户端和服务端的对称密钥生成完毕,TLS握手都所有完成,接下来双方均可以经过对称密钥进行加密通讯,Application Data报文中的数据就是加密后的HTTP报文,当HTTPS通讯结束后,由客户端主动发出Client Close Notify报文断开链接。

由上面DH握手过程能够看出,对称密钥是根据一些参数在各端生成,并非在客户端生成后经过公钥加密传输给服务端,这样作是为了保证服务端的私钥不和对称密钥有关联,什么意思呢?若是在客户端生成密钥经过公钥加密传输给服务端,服务端能够由私钥解密出密钥,这样私钥就参与了对称密钥的解密,到也就是说,只要我拥有服务端的私钥,我就能够解密出密钥,因此若是中间人把你TLS握手过程当中的全部报文拦截、保存,直到某一天服务端的私钥泄漏了,中间人就可使用私钥在保存的报文中解密出密钥,这样,中间人就轻松的解密出客户端和服务端之后的通讯内容,而经过DH参数的交换就能够避免这个漏洞,为何DH交换就能够? 这归根究竟是一个数学问题,你们能够自行查找资料。

你们只须要知道在TLS握手中,对称密钥是服务端和客户端各自生成的,服务端公钥和私钥的功能被削弱到用来进行身份认证或者签名验证,这么作的目的都是为了保证通讯的向前保密、安全。

HTTPS这么安全,为何不全部网站都使用? 一、效率问题:与HTTP的明文通讯相比,加密通讯须要消耗更多的CPU资源与内存; 二、部署问题:使用HTTPS须要有权威CA的证书颁发,从证书的选择、购买到部署都是一个耗时耗力的过程; 三、成本问题:购买证书也是一笔开销.

结语

网络请求已经成为了一个应用最基本的部分,因此熟悉HTTP对于咱们开发很重要,咱们不只会用开发环境提供给咱们的API,还要属性它的原理,本文从发展历史、工做特色、报文格式、状态码、常见首部、HTTPS这几个方面总结了一番HTTP,固然,HTTP确定不止这一些,一篇文章是没法讲完的,限于篇幅,还有HTTP的缓存机制没有讲,这也是很重要的内容,掌握以上这些足够日常使用了。

以上就是本文所有内容,但愿你们有所收获。

参考资料:

图解HTTP

HTTP1.0、HTTP1.1 和 HTTP2.0 的区别

深度解密 HTTP 通讯细节

HTTP/1.x 的链接管理

深刻理解https工做原理

SSL中的RSA、DHE、ECDHE、ECDH流程与区别

Cookie/Session的机制与安全

相关文章
相关标签/搜索