HTTP全称Hyper Text Transfer Protocol
,即超文本传输协议。HTTP是一个应用层协议,可视为一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范。面试
咱们这里就直接以一个常见的面试题引入啦。算法
在浏览器中输入 www.baidu.com 后会发生什么?数据库
当一个用户在浏览器里输入 www.baidu.com
这个 URL 时,将会发生不少操做。首先它会请求 DNS 把这个域名解析成对应的 IP 地址,而后根据这个 IP 地址在互联网上找到对应的服务器,向这个服务器发起一个GET 请求,由这个服务器决定返回默认的数据资源给访问用户。在服务器端实际上还有很复杂的逻辑:服务器可能有好多台,到底指定哪台服务器来处理请求,这须要一个负载均衡设备来平均分配全部用户的请求;还有请求的数据是存储在分布式缓存里仍是一个静态文件中,或是在数据库里;当数据返回浏览器时,浏览器解析数据发现还有一些静态资源(如 CSS、JS 或者图片)时又会发起另外的 HTTP 请求,而这些请求有可能会在 CDN 上,那么 CDN 服务器又会处理这个用户的请求,大致上一个用户请求会涉及这么多操做。每个细节都会影响这个请求最终是否会成功。后端
咱们不去涉及其中过多的知识,单说HTTP的请求流程便可,从上面咱们知道,HTTP协议是由客户端发起的,由请求和响应构成,是一个标准的客户端服务器模型(C/S),它的具体流程以下:浏览器
地址解析。域名系统DNS解析域名获得主机的IP地址;缓存
封装HTTP请求数据包。封装的内容有以上部分结合本机本身的信息;安全
封装成TCP包,创建TCP链接(TCP的三次握手);服务器
客户机发送请求命令。 创建链接后,客户机向服务器发送一个请求;markdown
服务器响应。服务器接到请求后,给予相应的响应信息;网络
服务器关闭TCP链接。通常Web服务器向浏览器发送了请求数据,它要关闭TCP链接;
客户端解析报文。客户端接收到响应报文后解析HTML代码,并渲染。
HTTP常见的状态码分为五大类,以下表所示:
状态码类别 | 具体含义 | 常见状态码 |
---|---|---|
1xx | 提示信息,表示目前是协议处理的中间状态,还须要后续的操做 | |
2xx | 成功,报文已经收到并被正确处理 | 200、20四、206 |
3xx | 重定向,资源位置发生变更,须要客户端从新发送请求 | 30一、30二、304 |
4xx | 客户端错误,请求报文有误,服务器没法处理; | 400、40三、404 |
5xx | 服务器错误,服务器在处理请求时内部发生了错误。 | 500、50一、50二、503 |
1xx:1xx
类状态码属于提示信息,是协议处理中的一种中间状态,实际用到的比较少。
2xx:2xx
类状态码表示成功处理了客户端需求,也是咱们浏览器发起请求时常见的状态:
HEAD
请求,服务器返回的响应头都会有 body 数据;3xx:3xx
类状态码表示客户端请求的资源发生了变更,须要客户端用新的 URL 从新发送请求获取资源,也就是重定向:
注:301 和 302 都会在响应头里使用Location
,指明后续要跳转的 URL,浏览器会自动重定向新的 URL。
4xx:4xx
类状态码表示客户端发送的报文有误,服务器没法处理,也就是错误码的含义:
5xx:5xx
类状态码表示客户端请求报文正确,可是服务器处理时内部发生了错误,属于服务器端的错误码:
首先咱们了解一下HTTP的报文结构,大概以下:
这是常见的请求报文,固然还有响应报文,二者之间并不彻底一致,这里只简单说起一下请求报文的格式。
首先是请求方法,常见的请求方法有 GET和POST两种,以后跟着的是URL,即要访问的地址,再后面跟着的就是协议版本,如:HTTP/1.1。
咱们主要讲解以后跟着的字段,即请求头,请求头的字段常以key-value
的形式,即”属性名:属性值“的形式传递若干数据,服务端据此获取客户端的信息。接下来咱们就来了解常见的字段:
Accept
字段与Content-type
字段:Accept字段用于客户端向服务器发送报文时表示本身可接收的响应内容类型,如:Accept:text/plain
(文本类型);
相似的字段还有Accept-Charset
表示可接收的字符集;Accept-Encoding
表示可接受的响应内容的压缩方式 ;Accept-Language
表示可接受的响应内容语言列表; Accept-Datetime
表示可接受的按照时间来表示的响应内容版本。
Content-Type字段用于服务器回应时,告诉客户端,本次数据的格式是什么。
相似的字段还有Content-Encoding
字段表示数据的压缩方法,表示服务器返回的数据使用什么压缩格式。
Host
字段
Host字段用于客户端发送请求时,用来指定服务器的域名。例如:Host:www.baidu.com
。这里须要与报文中的请求行的 URL 区分,Host字段与 URL 组成完整的请求URL,例如请求行中的URL为/getPerson
,而Host字段为www.baidu.com
,那么二者结合起来就是www.baidu.com/getPerson
。
Connection
字段
Connection字段最经常使用于客户端要求服务器使用 TCP 持久链接,以便其余请求复用。
Connection: keep-alive
扩展:
HTTP是无状态的面向链接的协议,无状态并不表明HTTP不能保持TCP链接,HTTP使用的不是UDP(无链接);
HTTP/1.1 版本的默认链接都是持久链接,但为了兼容老版本的 HTTP,须要指定Connection
首部字段的值为Keep-Alive
。简单的说,当一个网页打开完成后,客户端和服务器之间用于传输的 HTTP 数据的 TCP 链接不会马上关闭,若是客户端再次访问这个服务器上的网页,会继续使用这一条已经创建的链接;
Keep-Alive不会永久保持链接,它有一个保持时间,能够在不一样的服务器软件(如Apache)中设定这个时间。
Content-Length
字段
服务器在返回数据时,会有Content-Length
字段,代表本次回应的数据长度。例如:Content-Length: 1000
,这代表了服务器本次回应的数据长度是1000个字节,后面的字节就属于下一个回应了。
在 HTTP/1.0 中有很大的性能问题,每次发起一个HTTP请求,都须要去创建一次TCP链接,并且仍是串行请求,这使得 HTTP 在 TCP 的链接创建上花费了大量的开销。对于这种问题,HTTP/1.1 中提出了长链接的通讯方式,也叫持久链接。这种链接的好处在于减小了 TCP 链接的重复创建和断开所形成的额外开销,减轻了服务器端的负载:
HTTP/1.1 采用了长链接的方式,这使得管道(Pipeline)网络传输成为了可能。便可在同一个 TCP 链接里面,客户端能够发起多个请求,只要第一个请求发出去了,没必要等其回来,就能够发第二个请求出去,能够减小总体的响应时间。
可是服务器仍是按照顺序,先回应第一个请求,完成后再回应第二个请求,以此类推。要是前面的请求回应得特别慢,后面就会有许多请求阻塞着,这就是所谓的【队头阻塞】。
因此 HTTP/1.0 或是 HTTP/1.1 性能都不是很完美,因此后续会有其余增强。
HTTP的内容是明文传输的,明文数据会通过中间代理服务器、路由器、WIFI热点、通讯服务运行商等多个物理节点,若是信息在传输过程当中被劫持,传输的内容久彻底暴露了,劫持者还能够篡改传输的信息且不被双方察觉,这就是中间人攻击。
总结一下,HTTP在安全方面有如下三个问题:
针对上面咱们提到的HTTP的安全问题,HTTPS 在 HTTP 的基础上增长了加密处理、认证机制和完整性保护,咱们能够将 HTTPS = HTTP + 加密 + 认证 + 完整性保护;
由于 HTTP 使用明文传输,中间会通过多个物理节点,可能会被劫持窃听,针对这一问题,HTTPS 采用了加密的方式解决。最容易理解的就是对称加密。
对称加密好理解,就是咱们拥有一个密钥,它能够用来对一段内容进行加密,一样的,在内容被进行加密后,须要用同一个密钥对加密内容进行解密,才能看到本来的内容,能够看做咱们平常生活中的钥匙。
HTTP 能够直接使用对称加密吗?
固然不能够。若是通讯双方各自持有同一个密钥,且没有第三方知晓,那么这两方之间的通讯安全是能够被保证的(毕竟密钥被破解可能性不大)。问题是”如何使得这个密钥可让传输的双方知晓,同时不被别人知道“?
假如咱们如今浏览器生成一个密钥而后发送到服务端,告诉服务端咱们双方用这个密钥来加密传输文件。或者是放过来,由服务器生成密钥而后发送给浏览器。很明显这就不现实,咱们知道 HTTP 传输时中间是须要通过许多个中间节点的,在通过中间节点时这个密钥被劫持下来是一件十分容易的事,因此这种方式不可取。由此引入非对称加密。
非对称加密有两把密钥,一般一把叫作公钥,另一把叫作私钥。用公钥加密的内容必须用私钥才能解开,一样的,私钥加密的内容须要用公钥才能解开。
HTTP 能够直接使用非对称加密吗?
仍是不能够。鉴于非对称加密的性质,咱们可能会有这种思路:服务器先把公钥直接明文传输给浏览器,以后浏览器向服务器传数据前都先用这个公钥加密好再传输,这条数据彷佛能够保障了,由于只有服务器端的相应私钥能解开这条数据。可是这样仍是有问题,密钥仍是能够被劫持的。
若是服务器用它的的私钥加密数据传给浏览器,那么浏览器用公钥能够解密它,而这个公钥是一开始经过明文传输给浏览器的,若是这个公钥被谁劫持到的话,他也能用该公钥解密服务器传来的信息了。因此这种方式的实现仍是会有问题,彷佛只能保证由浏览器传输数据时的安全性(其实还有漏洞)。
经过一组公钥、私钥已经能保证单个方向传输的安全性,那用两组公钥私钥是否是就能保证双向传输都安全了,如下面流程为例:
这种实现方式理论上确实可行,抛开这里面仍有的漏洞不谈(下文再述),HTTPS 的加密却没有使用这种方案,为何?
最主要的缘由是非对称加密算法很是耗时,特别是加密解密一些较大数据的时候有些力不从心。相比之下,对称加密就要快不少,那能不能同时运用对称加密与非对称加密的性质来实现对 HTTP 的加密呢?
既然非对称加密耗时,那么就用“对称加密 + 非对称加密”结合的形式来实现对 HTTP 的加密,并且还得尽可能减小非堆成加密的次数 ,这样是否能实现呢?
这种方式是能够实现的,并且非对称加密、解密各只须要用一次便可。请看如下过程:
HTTPS 基本上就是采用了这种方案了,固然这种方法仍是有漏洞,咱们接着往下讲。
根据上面的混合加密过程,中间人确实没法拥有浏览器生成的对称密钥 X,这个密钥自己就被公钥 A 给加密了,只有服务器才能经过私钥 A‘ 对其进行解密。然而在这个过程当中中间人彻底不须要获取到密钥 A’ 就能进行攻击了。以下流程所示:
这样在双方都不会发生异常的状况下,中间人获得了密钥 X,这其中的根本缘由就是浏览器没法确认本身收到的公钥是否是网站的。那么接下来就是要解决这一问题。
如何证实浏览器收到的公钥必定是该网站的公钥?这里就须要有一个公信机构给网站颁发一个“身份证”了。网站在使用 HTTPS 前,须要向“CA机构”申请颁发一份数字证书,数字证书里有证书持有者、证书持有者的公钥等信息,服务器把证书传输给浏览器,浏览器从证书里取公钥就好了,证书就如同身份证同样,能够证实“该公钥对应该网站”。
然而到这里仍是有一个问题,如何保证证书在传输的过程不会被篡改,身份证自己有防伪的技术,那么如何保证证书的防伪呢?
如何保证证书不被篡改?
咱们把证书内容生成一份“签名”,比对证书内容和签名是否一致就能察觉是否被修改,这种技术就称为数字签名;
数字签名的制做过程?
将明文和数字签名共同组成数字证书,这样一份证书就能够颁发给网站了。
浏览器获得证书后如何验证这份证书的真实性?
浏览器如何获得权威机构的公钥?
上面提到,如何要对服务器发过来的证书进行解密,那么就须要到CA的公钥,由于其被CA的私钥给加密了。那么浏览器是如何拥有CA的公钥呢?
实际上权威机构的公钥并不须要传输,由于权威机构会和主流的浏览器或操做系统合做,将他们的公钥内置在浏览器或操做系统环境中。客户端收到证书以后,只须要从证书中找到权威机构的信息,并从本地环境中找到权威机构的公钥,就能正确解密A公钥。固然实际状况要比这个复杂得多,这里简单介绍就行。
中间人有可能篡改证书吗?
上面咱们提到,权威机构的公钥是可能在浏览器或操做系统中的,那么中间人劫持到证书后是能够解密获得原文的。相应的,他也能够去篡改证书的原文,可是因为他没有 CA 机构的私钥,没法相应地篡改签名。因此浏览器收到证书后会发现原文和解密后的值不一致,说明证书已经被篡改,证书不可信了,因此中间人不可能去篡改证书了。
client key
,即客户端密钥,这样在概念上和服务器端的密钥容易进行区分。而后用服务器的公钥对客户端密钥进行非对称加密,这样客户端密钥就变成密文了,至此,HTTPS中的第一次HTTP请求结束;文章内容绝大数来源网络,我只是个搬运工,如有哪里出错,请评论区指出。
参考资料: