《图解HTTP》核心知识总结

1,619 阅读28分钟

HTTP协议的简介

HTTP是超文本传输协议,用于客户端和服务器端之间的通信,属于TCP/IP中的应用层。

HTTP协议的基础知识

客户端和服务器端

客户端是服务请求方,服务器端是服务提供方。

URI和URL

URI:URI是统一资源标识符;

URL:是统一资源定位器;

URI的格式(了解即可)
[scheme:][//user:password@]host[:port][/path][?query][#fragment]
如上是URI的具体格式,下面介绍其意义:

  • scheme::是协议方案,比如http:,https:,file:等,此项可选可不选
  • [//[user:password@]:指定用户名和密码作为从服务器获取资源时必要的登陆信息,此项是可选项
  • host:服务器地址,例如www.runoob.com
  • [:port]:服务器端口号,例如:8080,此项是可选项
  • [/path]:指定服务器上的文件路径来定位特指的资源
  • [?query]:查询字符串,例如?id=123&pas=123
  • [#fragment]:片段标识符

DNS

DNS基础知识

HTTP的特点

HTTP通过请求和响应来达成通信

如图:

HTTP 是无状态协议

HTTP 是无状态协议,它不对之前发生过的请求和响应的状态进行管理。也就是说,无法根据之前的状态进行本次的请求处理。

假设要求登录认证的 Web 页面本身无法进行状态的管理(不记录已 登录的状态),那么每次跳转新页面不是要再次登录,就是要在每次 请求报文中附加参数来管理登录状态。

HTTP使用 Cookie 的状态管理,Cookie 技术通过在请求和响应报文中写入 Cookie 信 息来控制客户端的状态。

Cookie 会根据从服务器端发送的响应报文内的一个叫做 Set-Cookie 的首部字段信息,通知客户端保存Cookie。当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入 Cookie 值后发送出 去。服务器端发现客户端发送过来的 Cookie 后,会去检查究竟是从哪一 个客户端发来的连接请求,然后对比服务器上的记录,最后得到之前 的状态信息。

如下图:

HTTP报文

HTTP报文是HTTP请求和响应的单位。用于请求的报文叫做请求报文,而用于响应的报文叫做 响应报文

报文的结构如图

报文主体和实体主体的差异 :
实体作为请求或响应的有效载荷数据(补充项)被传输,其内容由实体首部和实体主体组成。HTTP 报文的主体用于传输请求或响应的实体主体。 通常,报文主体等于实体主体。只有当传输中进行编码操作时,实体 主体的内容发生变化,才导致它和报文主体产生差异

HTTP首部字段的结构

首部字段名: 字段值

如果有多个值,则首部字段名: 字段值1, 字段值2

如果HTTP首部字段重复了会如何?
当HTTP报文首部中出现中出现了两个或两个以上具有相同首部字段名时会怎么样?这种情况 在规范中尚未明确,根据浏览器内部处理逻辑的不同,结果可能并不一致。

HTTP首部字段分为四个部分:

  • 通用首部字段:请求报文和响应报文两方都会使用的首部字段
  • 请求首部字段:从客户端向服务器端发送请求报文时使用的首部。补充了请求的附加内容、客户端信息、响应内容相关优先级等信息。
  • 响应首部字段:从服务器端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会为客户端附加额外的内容信息
  • 实体首部字段:针对请求报文和响应报文的实体部分使用的首部。补充了资源内容的更新时间等与实体有关的信息

实例分析

现在以请求菜鸟教程的报文为例来进行分析:

请求报文

GET /HTTP/1.1        //请求行
Host: www.runoob.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Referer: https://cn.bing.com/
Connection: keep-alive
Cookie: Hm_lvt_3eec0b7da6548cf07db3bc477ea905ee=1554627142,1556799533; _ga=GA1.2.579069872.1554627144; Hm_lpvt_3eec0b7da6548cf07db3bc477ea905ee=1556799533; _gid=GA1.2.1514513796.1556799533; _gat_gtag_UA_84264393_2=1
Upgrade-Insecure-Requests: 1 
Cache-Control: max-age=0

响应报文

HTTP/1.1 200 OK      //状态行
Server: Tengine
Content-Type: text/html
Content-Length: 150124
Connection: keep-alive
Date: Thu, 02 May 2019 09:27:08 GMT
Content-Encoding: gzip
Vary: Accept-Encoding
X-M-Log: QNM:xs446;QNM3:1
X-M-Reqid: jVAAADsHtCKO05oV
X-Powered-By: HHVM/3.28.1
X-Qnm-Cache: Hit
Ali-Swift-Global-Savetime: 1556270140
Via: cache16.l2cn1807[0,200-0,H], cache37.l2cn1807[1,0], cache9.cn1066[0,200-0,H], cache5.cn1066[1,0]
Age: 10328
X-Cache: HIT TCP_MEM_HIT dirn:11:466942761
X-Swift-SaveTime: Thu, 02 May 2019 10:36:54 GMT
X-Swift-CacheTime: 86400
Timing-Allow-Origin: *
EagleId: db971b1915567995564074785e

请求行和状态行

请求行:请求行中包含用于请求的方法,请求的URI和HTTP版本
状态行:状态行包含响应结果的状态码,原因短语和HTTP版本

在请求报文中GET /HTTP/1.1是请求行,其中GET代表请求的方法,/HTTP/1.1代表HTTP版本,在这个请求中未出现请求的URI

在响应报文中HTTP/1.1 200 OK是状态行,其中HTTP/1.1是请求的版本,200是响应结果的状态码,而OK 则是原因短语。

请求的方法

GET:GET方法用来访问以被URI识别的资源。指定的资源经服务器解析后返回响应的内容。如下图

POST: POST方法用来传输实体的主体。如下图

其他方法如PUT HEAD DELETE OPTIONS TRACE CONNECT一般不使用。下面简单介绍一下:

方法 作用 不使用的原因
PUT 用来传输文件 PUT方法不采用任何验证机制,存在安全问题
HEAD 和GET方法一样,不过只返回响应首部 ---
DELETE 用来删除文件 DELETE不采用任何验证机制,存在安全问题
OPTIONS 查询针对请求URI指定的资源支持的方法 ----
TRACE 让WEB服务器端将之前的请求通信返回给客户端 容易引发跨站追踪(XST)攻击
CONNECT 要求在与代理服务器通信时建立隧道,实现用隧道协议进行TCP通信 ----

状态码

2XX

200 ok

表示从客户端发来的请求在服务器端被正常处理了

204 Not Content

该状态码代表服务器接收的请求已经被成功处理,但是返回的响应报文中不包含实体的主体部分

206 Partial Content

该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的GET请求

3XX

301 Moved Permanently

永久性重定向,该状态码表示请求的资源已被分配到新的URI,以后应该 使用现在所指的URI。

302 Found

临时重定向。该状态码表明请求的资源已被分配了新的URI,希望用户本次能使用新的URI访问。

303 See Other

该状态码表示由于请求资源存在另一个URI,应该使用GET方法定向获取请求的资源

304 Not Modified

该状态码表示客户端发送附带条件请求时,服务器端允许请求访问资源,但因为请求未满足条件的情况后, 直接返回304.

307 Temporary Redirect

临时重定向,和302相似。但是307不会从Post变成GET

4XX

400 Bad Request

该状态码表示请求报文中存在语法错误。当错误发生时,需要修改请求的内容后再次发送请求

401 Unauthorized

该状态码表示发送的请求需要通过HTTP认证的认证信息。另外若之前已经进行过一次请求,则表示用户认证失败

403 Forbidden

该状态码表明对请求资源的访问被服务器拒绝了

404 Not Found

该状态码表明服务器上无法找到请求的资源

5XX

500 Internal Server Error

该主题码表示服务器在执行请求时发生了错误

503 Service Unavailable

该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。

HTTP所有的首部字段

HTTP/1.1定义了如下47种首部地段,如下

通用首部字段:

请求首部字段:

响应首部字段:

实体首部字段:

非HTTP/1.1首部字段(不属于47种中的字段):CookieSet-CookieContent-Disposition等。

端到端首部和逐跳首部

HTTP将使用 缓存代理非缓存代理 的首部字段分成两种类型:端到端首部(End-to-end Header)、逐跳首部(Hop-by-hop Header)

缓存代理
代理转发响应时,缓存代理(Caching Proxy)会预先将资源的副本 (缓存)保存在代理服务器上。 当代理再次接收到对相同资源的请求时,就可以不从源服务器那里获 取资源,而是将之前缓存的资源作为响应返回。
透明代理
转发请求或响应时,不对报文做任何加工的代理类型被称为透明代理 (Transparent Proxy)。反之,对报文内容进行加工的代理被称为非 透明代理。

注意:这里的非缓存代理不等于透明代理;它们划分的标准不一样。`缓存代理`和`非缓存代理`是通过是否使用缓存来划分的;而`透明代理`和`非透明代理`是通过是否会修改报文来划分。

端到端首部:分在此类别中的首部会转发给请求/响应对应的最终接收目标(即全程有效),且必须保存在由缓存生成的响应中,另外规定它必须被转发

逐跳首部:分在此类别的首部只对单次转发有效,会因为通过缓存或代理而不再转发。在HTTP/1.1和以后版本中,如果要使用逐跳首部,需要通过Connection首部字段

逐跳首部字段为:

  • Connection
  • Keep-Alive(新增字段,可忽略)
  • Proxy-Authenticate
  • Proxy-Authorization
  • Trailer
  • TE
  • Transfer-Encoding
  • Upgrade

其他字段都为端到端首部

通用首部字段

在实例的请求报文中出现的通用首部

Connection: keep-alive
Cache-Control: max-age=0

在实例的响应报文中出现的通用首部

Connection: keep-alive
Date: Thu, 02 May 2019 09:27:08 GMT
Via: cache16.l2cn1807[0,200-0,H], cache37.l2cn1807[1,0], cache9.cn1066[0,200-0,H], cache5.cn1066[1,0]

Cache-Control

通过指定首部字段Cathe-Control的指令,就可以操作缓存的工作机制,如图:

请求报文中Cache-Control: max-age=0表示缓存服务器通常需要将请求转发给源服务器。

Connection

Connection的作用:

  1. 控制不再转发给代理的首部字段
  2. 管理持久化连接
控制不再转发给代理的首部字段

代理服务器的基本行为就是接收客户端发送的请求后转发给其他服务器。代理不改变请求 URI,会直接发送给前方持有资源的目标服务器。上面介绍的缓存代理是代理服务器作用的一种。

管理持久化连接
Connection: close //表明服务器想断开连接
Connection: Keep-Alive //保持持久化连接(默认)

Via

用来追踪客户端与服务器端之间的请求和响应报文的传输路径。
Via: cache16.l2cn1807[0,200-0,H], cache37.l2cn1807[1,0], cache9.cn1066[0,200-0,H], cache5.cn1066[1,0]

Date

首部字段Date表明创建HTTP报文的时间,如Date: Thu, 02 May 2019 09:27:08 GMT就表示创建报文的时间为2019年5月2日,星期二。

Pragma

Pragma是历史遗留字段,仅作为与HTTP/1.0的向后兼容而定义。

Trailer

用来说明在报文主体后记录了哪些首部字段

Transfer-Encoding

规定传输报文主体时采用的编码方式(仅对分块传输编码有效)

Upgrade

用来检测HTTP协议及其他协议是否可使用更高的版本进行通信。

Warning

告诉用户一些与缓存有关的问题的警告

请求首部字段

请求报文(去除了通用首部字段)

Host: www.runoob.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Referer: https://cn.bing.com/
Cookie: Hm_lvt_3eec0b7da6548cf07db3bc477ea905ee=1554627142,1556799533; _ga=GA1.2.579069872.1554627144; Hm_lpvt_3eec0b7da6548cf07db3bc477ea905ee=1556799533; _gid=GA1.2.1514513796.1556799533; _gat_gtag_UA_84264393_2=1
Upgrade-Insecure-Requests: 1 
Cache-Control: max-age=0

Host

告诉服务器请求的资源所处的互联网主机名和端口号,如Host: www.runoob.comHost是唯一必须包含在请求内的首部字段

User-Agent

用来将创建请求的浏览器和用户代理名称等信息传达给服务器。

例如上面的请求首部:
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0

Accept

通知服务器可以处理的媒体类型及媒体类型的相对优先级

例如Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

媒体类型

文本文件

text/html, text/plain, text/css ... application/xhtml+xml, application/xml ...

图片文件

image/jpeg, image/gif, image/png ...

视频文件

video/mpeg, video/quicktime ...

应用程序使用的二进制文件

application/octet-stream, application/zip

优先级

使用q=来额外表示权重值,用;进行分隔。权重值的范围是0~1(可精确到小数点后3位),且1为最大值。不指定 权重值时,默认权重为q=1.0.当服务器提供多个内容时会首先返回权重值最高的媒体类型。

Accept-Charset

Accept-Charset首部字段可用来通知服务器用户代理支持的字符集及字符集的相对优先顺序。另外可一次性指定多种字符集。与首部字段 Accept相同的可用权重q值来表示相对优先级

Accept-Encoding

Accept-Encoding首部字段用来告知服务器用户代理支持的内容编码及内容编码的优先级顺序。可一次性指定多种内容编码,可用权重q来指定优先级 例如Accept-Encoding: gzip, deflate, br

Accept-Language

首部字段Accept-Language用来告诉服务器用户代理能够处理的语言,可以指定多个语言,可以使用q来决定优先级。 例如Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2

Authorization

用来告诉服务器,用户代理的认证信息

Expect

告知服务器期望出现某种特定的行为

From

告诉服务器使用用户代理的用户的电子邮箱地址

If-Match

告诉服务器匹配资源所用的实体标记(ETag)值,服务器会对比If-Match的字段值和资源的ETag值,仅 当两者一致时才执行请求.反之则返回状码412

If-Modified-Since

告诉服务器若If-Modified-Since字段值早于资源更新的时间,则希望能处理该请求。 反之如果在If-Modified-Since指定的时间日期之后,如果请求的资源都没有更新,则 返回的状态码 304

If-None-Match

与If-Match相反

If-Range

告诉服务器若指定的If-Range字段值(ETag值或者时间)和请求资源的ETag值或时间相一致时,则作为范围请求处理。 反之,则返回全体资源。如图:

If-Unmodified-Since

与If-Modified-Since作用相反

Range

对于只需获取部分资源的范围请求,包含首部字段Range即可告知服务器资源的指定范围。 接收到附带Range首部字段请求的服务器,会在处理请求之后返回206.无法处理该范围的 请求时,则会返回200的响应及全部资源。

Referer

告诉服务器请求的原始URI

例如:Referer: https://cn.bing.com/说明我是从微软必应请求的

Upgrade-Insecure-Requests

Upgrade-Insecure-Requests是一个请求首部,用来向服务器端发送信号,表示客户端优先选择加密及带有身份验证的响应。不属于47种报文首部字段。

TE

告诉服务器,客户端能够处理的传输编码方式及相对优先级

Transfer-Encoding,TE,Content-Encoding,Accept-Encoding四个首部字段的区别

  • Transfer-Encoding:用于指定传输报文主体时使用的编码方式,属于逐跳首部,即只在两个节点间有效。
  • TE:用于告知服务器客户端能够处理的编码方式和相对优先级,属于逐跳首部,即只在两个节点间有效。
  • Content-Encoding:用于指定报文主体已经采用的编码方式,属于端到端首部,即在整个传输过程中有效。
  • Accept-Encoding:用于告知服务器客户端能够处理的编码方式和相对优先级,属于端到端首部,即在整个传输过程中有效。

很显然,Transfer-EncodingTE是一组,Content-EncodingAccept-Encoding是一组。 根本区别在于,Content-EncodingAccept-Encoding限制的是报文主体在整个传输过程中使用的编码方式,全局有效;Transfer-EncodingTE限制的是报文主体在两个节点间(源服务器和代理服务器之间、代理服务器和客户端之间等)传输时使用的编码方式,只在两节点间有效。

转自区分Transfer-Encoding,TE,Content-Encoding,Accept-Encoding四个首部字段

响应首部字段

响应报文

Server: Tengine
Vary: Accept-Encoding
X-M-Log: QNM:xs446;QNM3:1
X-M-Reqid: jVAAADsHtCKO05oV
X-Powered-By: HHVM/3.28.1
X-Qnm-Cache: Hit
Ali-Swift-Global-Savetime: 1556270140
Age: 10328
X-Cache: HIT TCP_MEM_HIT dirn:11:466942761
X-Swift-SaveTime: Thu, 02 May 2019 10:36:54 GMT
X-Swift-CacheTime: 86400
Timing-Allow-Origin: *
EagleId: db971b1915567995564074785e

Accept-Ranges

首部字段Accept-Ranges是用来告诉客户端服务器是否能处理范围请求,以指定获取服务器端 某个部分的资源。可以指定的值为bytes(表示接受范围请求)和none(表示不接受范围请求).

Age

告诉客户端,源服务器在多久前创建了响应。字段值的单位为秒。

ETag

主要用于检验缓存是否改变。它告诉客户端实体标识,是一种可将资源以字符串的形式做唯一标识的方式。服务器会为每份资源分配对应的ETag值

另外当资源更新时,ETag值也需要更新。当资源被缓存时,就会被分配唯一的标识。若在下载过程中 出现连接的中断,再连接的情况,都会依照ETag值来指定资源。

ETag中有强ETag值和弱ETag值

强ETag值,无论实体发生多么细微的变化都会改变其值。

弱ETag值,只用于提示资源是否相同。只有资源发生了根本改变,产生差异时才会改变ETag值。这时, 会在字段值最开始处附加 W/

Location

将响应接受方引领到某个与请求URI位置不同的资源。基本上,该字段会配合3XX的响应,提供重定向的URI。

Proxy-Authenticate

会把由代理服务器所要求的认证信息发生给客户端

Retry-After

告诉客户端应该在多久之后再发送请求。主要配合状态码503响应或3xx响应一起使用。字段值可以指定为具体的日期时间,也可以是创建响应后的秒数

Server

告诉客户端当前服务器上安装的HTTP服务器应用程序的信息

Vary

对缓存进行控制。具体见这里

WWW-Authenticate

用于HTTP访问认证

实体首部字段

Allow

告诉客户端支持的请求方法

Content-Encoding

告知客户端服务器对实体的主体部分选用的内容编码方式。内容编码是指在不丢失实体信息的前提下所进行的压缩

主要采用以下4种内容编码的方式

  • gzip
  • compress
  • deflate
  • identity

Content-Language

告诉客户端,实体使用的语言

Content-Length

表明实体主体部分的大小,单位是字节。对实体主体进行内容编码传输时,不能再使用Content-Length 首部字段

Content-Location

给出报文主体部分相对应的URI。和首部字段Location不同,Content-Location表示的是报文主体返回资源对应的URI

Content-MD5

首部字段 Content-MD5 是一串由 MD5 算法生成的值,其目的在于检 查报文主体在传输过程中是否保持完整,以及确认传输到达。

Content-Range

针对范围请求,返回响应时使用的首部字段Content-Range,能告诉客户端作为响应返回的实体的哪个部分 符合范围请求。字段值以字节为单位,表示当前发送部分及整个实体大小。

Content-Type

说明实体主体内对象的媒体类型,和首部字段Accept一样,字段值用type/subtype形式赋值

Http Header里的Content-Type一般有这三种:

  • application/x-www-form-urlencoded:数据被编码为名称/值对(这是标准的编码格式)。
  • multipart/form-data: 数据被编码为一条消息,页上的每个控件对应消息中的一个部分。
  • text/plain: 数据以纯文本形式(text/json/xml/html)进行编码,其中不含任何控件或格式字符(postman软件里标的是RAW)

form的enctype属性为编码方式,常用有两种:application/x-www-form-urlencodedmultipart/form-data,默认为application/x-www-form-urlencoded
actionget时候,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1&name2=value2...),然后把这个字串追加到url后面,用?分割,加载这个新的url。
actionpost时候,浏览器把form数据封装到http body中,然后发送到server。 如果没有type=file的控件,用默认的application/x-www-form-urlencoded就可以了。 但是如果有type=file的话,就要用到multipart/form-data了。
actionpostContent-Type类型是multipart/form-data,浏览器会把整个表单以控件为单位分割,并为每个部分加上Content-Disposition(form-data或者file),Content-Type(默认为text/plain),name(控件name)等信息,并加上分割符。

转自Http Header里的Content-Type

Expires

会将资源失效的日期告诉客户端

Last-Modified

指明资源最终修改的时间

为Cookie服务的首部字段

Set-Cookie

开始状态管理所使用的Cookie信息(响应首部字段)

Cookie

告诉服务器,当客户端想获取HTTP状态管理支持时,就会在请求中包含从服务器接受到的Cookie。接收到多个 Cookie时,同时可以以多个Cookie形式发送

其他首部字段

HTTP首部字段是可以自行扩展的。所以在WEB服务器和浏览器应用上,会出现各种非标准的首部字段

X-Frame-Options

属于响应首部,用于控制网站内容在其他web网站的Frame标签内的显示问题。其主要目的是为了防止 点击劫持攻击

有两个可指定的字段值 DENY:拒绝 SAMEORIGIN:仅在同源域名下的页面匹配时许可

X-XSS-Protection

属于响应首部,它是针对跨站脚本攻击(XSS)的一种对策,用于控制浏览器XSS防护机制开关。

字段值: 0:将XSS过滤设置为无效状态 1:将XSS过滤设置为有效状态

DNT

属于请求字段,意味拒绝个人信息被采集,是表示拒绝被精准广告追踪的一种方法

字段值 0:同意被追踪 1:拒绝被追踪

P3P

属于响应首部,通过利用 P3P(The Platform for Privacy Preferences,在线隐私偏好平台)技术,可以让 Web 网站上 的个人隐私变成一种仅供程序可理解的形式,以达到保护用户隐私的 目的。

协议中对X-前缀的废除

在HTTP等多种协议中,通过给非标准参数加上前缀X-,来区别于标准参数,并使那些非标准参数作为扩展变成可能(如上面的响应首部)。但是这种简单粗暴的做法没有任何好处,因此被提议停止。然而对已经在使用中的X-前缀来说,不应该要求其变更。

HTTP的缺点

  • 通信使用明文(不加密),内容可能被窃听
  • 不验证通信方的身份,因此有可能遭受伪装
  • 无法证明报文的完整性,所以内容可能被篡改

HTTP+ 加密 + 认证 + 完整性保护 =HTTPS

HTTPS 并非是应用层的一种新协议。只是 HTTP 通信接口部分用 SSL(Secure Socket Layer)和 TLS(Transport Layer Security)协议代 替而已。 通常,HTTP 直接和 TCP 通信。当使用 SSL 时,则演变成先和 SSL 通 信,再由 SSL 和 TCP 通信了。简言之,所谓 HTTPS,其实就是身披 SSL 协议这层外壳的 HTTP

在采用 SSL 后,HTTP 就拥有了 HTTPS 的加密、证书和完整性保护 这些功能。

SSL 是独立于 HTTP 的协议,所以不光是 HTTP 协议,其他运行在应 用层的 SMTP 和 Telnet 等协议均可配合 SSL 协议使用。可以说 SSL 是 当今世界上应用最为广泛的网络安全技术。

加密

加密和解密同用一个密钥的方式称为共享密钥加密(Common key crypto system),也被叫做对称密钥加密

共享密钥加密的困境

以共享密钥方式加密时必须将密钥也发给对方。可究竟怎样才能 安全地转交?在互联网上转发密钥时,如果通信被监听那么密钥 就可会落入攻击者之手,同时也就失去了加密的意义。另外还得 设法安全地保管接收到的密钥。

公开密钥加密使用一对非对称的密钥。一把叫做私有密钥 (private key),另一把叫做公开密钥(public key)。顾名思 义,私有密钥不能让其他任何人知道,而公开密钥则可以随意发 布,任何人都可以获得。

HTTPS 采用混合加密机制

HTTPS 采用共享密钥加密和公开密钥加密两者并用的混合加密 机制。若密钥能够实现安全交换,那么有可能会考虑仅使用公开 密钥加密来通信。

但是公开密钥加密与共享密钥加密相比,其处 理速度要慢。 所以应充分利用两者各自的优势,将多种方法组合起来用于通 信。在交换密钥环节使用公开密钥加密方式,之后的建立通信交 换报文阶段则使用共享密钥加密方式。

证明公开密钥正确性的证书

遗憾的是,公开密钥加密方式还是存在一些问题的。那就是无法证明 公开密钥本身就是货真价实的公开密钥。比如,正准备和某台服务器 建立公开密钥加密方式下的通信时,如何证明收到的公开密钥就是原 本预想的那台服务器发行的公开密钥。或许在公开密钥传输途中,真 正的公开密钥已经被攻击者替换掉了。

为了解决上述问题,可以使用由数字证书认证机构(CA,Certificate Authority)和其相关机关颁发的公开密钥证书

服务器会将这份由数字证书认证机构颁发的公钥证书发送给客户端, 以进行公开密钥加密方式通信。

公钥证书也可叫做数字证书或直接称 为证书。 接到证书的客户端可使用数字证书认证机构的公开密钥,对那张证书 上的数字签名进行验证,一旦验证通过,客户端便可明确两件事:

  • 认证服务器的公开密钥的是真实有效的数字证书认证机构。
  • 服务器的公开密钥是值得信赖的。

此处认证机关的公开密钥必须安全地转交给客户端。使用通信方式 时,如何安全转交是一件很困难的事,因此,多数浏览器开发商发布 版本时,会事先在内部植入常用认证机关的公开密钥。

HTTPS 的通信步骤

  • 步骤 1: 客户端通过发送 Client Hello 报文开始 SSL 通信。报文中包 含客户端支持的 SSL 的指定版本、加密组件(Cipher Suite)列表(所 使用的加密算法及密钥长度等)。
  • 步骤 2: 服务器可进行 SSL 通信时,会以 Server Hello 报文作为应 答。和客户端一样,在报文中包含 SSL 版本以及加密组件。服务器的 加密组件内容是从接收到的客户端加密组件内筛选出来的。
  • 步骤 3: 之后服务器发送 Certificate 报文。报文中包含公开密钥证 书。
  • 步骤 4: 最后服务器发送 Server Hello Done 报文通知客户端,最初阶 段的 SSL 握手协商部分结束。
  • 步骤 5: SSL 第一次握手结束之后,客户端以 Client Key Exchange 报 文作为回应。报文中包含通信加密中使用的一种被称为 Pre-master secret 的随机密码串。该报文已用步骤 3 中的公开密钥进行加密。
  • 步骤 6: 接着客户端继续发送 Change Cipher Spec 报文。该报文会提 示服务器,在此报文之后的通信会采用 Pre-master secret 密钥加密。
  • 步骤 7: 客户端发送 Finished 报文。该报文包含连接至今全部报文的 整体校验值。这次握手协商是否能够成功,要以服务器是否能够正确 解密该报文作为判定标准。
  • 步骤 8: 服务器同样发送 Change Cipher Spec 报文。
  • 步骤 9: 服务器同样发送 Finished 报文。
  • 步骤 10: 服务器和客户端的 Finished 报文交换完毕之后,SSL 连接 就算建立完成。当然,通信会受到 SSL 的保护。从此处开始进行应用 层协议的通信,即发送 HTTP 请求。
  • 步骤 11: 应用层协议通信,即发送 HTTP 响应。
  • 步骤 12: 最后由客户端断开连接。断开连接时,发送 close_notify 报 文。上图做了一些省略,这步之后再发送 TCP FIN 报文来关闭与 TCP 的通信。 在以上流程中,应用层发送数据时会附加一种叫做 MAC(Message Authentication Code)的报文摘要。MAC 能够查知报文是否遭到篡 改,从而保护报文的完整性。

SSL 和 TLS HTTPS 使用 SSL(Secure Socket Layer) 和 TLS(Transport Layer Security)这两个协议。 SSL 技术最初是由浏览器开发商网景通信公司率先倡导的,开发 过 SSL3.0 之前的版本。目前主导权已转移到 IETF(Internet Engineering Task Force,Internet 工程任务组)的手中。 IETF 以 SSL3.0 为基准,后又制定了 TLS1.0、TLS1.1 和 TLS1.2。TSL 是以 SSL 为原型开发的协议,有时会统一称该协议 为 SSL。当前主流的版本是 SSL3.0 和 TLS1.0。 由于 SSL1.0 协议在设计之初被发现出了问题,就没有实际投入 使用。SSL2.0 也被发现存在问题,所以很多浏览器直接废除了 该协议版本。