文章参考自知乎用户:flyhero / 似水年华 / 噜噜呀
文章参考自掘金用户:椰子不上树
子曰:知之为不知,不知为不知,太菜也!
- 目录
HTTP(超文本传输协议)是应用层上的一种客户端/服务端模型
的通信协议
,它由请求和响应构成,且是无状态
的。(暂不介绍HTTP2)
- 协议
协议规定了通信双方必须遵循的数据传输格式,这样通信双方按照约定的格式才能准确的通信。 - 无状态 无状态是指两次连接通信之间是没有任何关系的,每次都是一个新的连接,服务端不会记录前后的请求信息。
- 客户端/服务端模型
客户端发送一个HTTP请求到服务端的格式:
服务端响应客户端格式:
HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP状态码共分为5种类型
更详细的状态码可查看 HTTP状态码
截止到HTTP1.1共有下面几种方法:
请求和响应常见通用头
注意
Content-Type,内容类型,一般是指网页中存在的Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件。
常见的媒体格式类型如下:
以application开头的媒体格式类型:
常见请求头
常见响应头
HTTPS实际上就是HTTP穿上了SSL/TLS的外套,我们都知道HTTP属于应用层的协议,是离程序员比较近的,而SSL(安全套接字)与TLS(运输层安全)都属于运输层协议。其实SSL与TLS都是上个世纪的产物,最新版本的TLS建立在SSL 3.0协议规范之上。
HTTPS涉及到加密,先简单了解一下有关密码学的知识。
HTTP协议是明文传输的,明文就是未被加密过的原始数据。
通常是一个字符串或数字,进行加密/解密算法时使用。公钥和私钥都是密钥,只不过一般公钥是对外开放的,加密时使用;私钥是不公开的,解密时使用。
有RSA、DSA/DSS、Elgamal、Rabin、D-H、ECC等。在客户端与服务器相互验证的过程中用的就是非对称加密算法 RSA密码体制就是公钥密码体制,RSA的一对公钥和私钥都可以用来加密和解密。 比如公钥加密后只能由私钥解密;私钥加密后只能由公钥解密。且一方加密的内容只能由对方进行解密。
有AES、DES、3DES、TDEA、Blowfish、RC4、RC5、IDEA等。加密使用的密钥和解密使用的密钥是同一个密钥。由于加密算法是公开的,若要保证安全性,密钥不能对外公开。通常用来加密消息体。
有MD5,SHA1,SHA256。用来确认信息没有被篡改。主要用来生成签名,签名是加在信息后面的,可以证明信息没有被修改过。一般对信息先做hash计算得到一个hash值,然后用私钥加密(这个加密一般是非对称加密)作为一个签名和信息一起发送。接收方收到信息后重新计算信息的hash值,且和信息所附带的hash值解密后进行对比。如果一样则认为没有被修改,反之则认为修改过,不做处理。可能有一种情况,黑客修改了信息并把hash值也改了,从而让他们相匹配。所以hash值一般都是加密后(生成签名)再和信息一起发送,确保hash值不会被修改。
主要包含证书发布机构,证书有效期,公钥,证书所有者,签名使用的算法,指纹以及指纹算法。数字证书可以保证里面的公钥一定是证书持有者的。
将明文通过Hash算法加密生成摘要,再将消息体摘要用私钥加密后就是签名了。当下一级证书或客户端需要时就返回这个整体。数字签名主要作用就是配合Hash算法保证信息没有被篡改。当https验证通过后,一般会改用对称加密方式通信,因为RSA公钥体制比较耗性能。所以数字签名只存在于验证阶段
证书是分级的,证书链由多个证书一级一级组成,拿到上级证书的公钥才能解密本级证书。只有最底层的证书是自签名的,自己颁发给自己。
这一部分看的比较多,主要归纳了一下,分5条。
1)客户端发起一个http请求,连接到服务器的443端口。
2)服务端把自己的信息以数字证书的形式返回给客户端(证书内容有密钥公钥,网站地址,证书颁发机构,失效日期等)。证书中有一个公钥来加密信息,私钥由服务器持有。
3)验证证书的合法性
客户端收到服务器的响应后会先验证证书的合法性(证书中包含的地址与正在访问的地址是否一致,证书是否过期)。
4)生成随机密码(RSA签名)
如果验证通过,或用户接受了不受信任的证书,浏览器就会生成一个随机的对称密钥(session key)并用公钥加密,让服务端用私钥解密,解密后就用这个对称密钥进行传输了,并且能够说明服务端确实是私钥的持有者。
5)生成对称加密算法
验证完服务端身份后,客户端生成一个对称加密的算法和对应密钥,以公钥加密之后发送给服务端。此时被黑客截获也没用,因为只有服务端的私钥才可以对其进行解密。之后客户端与服务端可以用这个对称加密算法来加密和解密通信内容了。
我们可以通过4个问题彻底理解HTTPS的运行原理,首先要从数字证书开始说起。
先来看看数字证书都有哪些内容
字段 | 含义 | 说明 |
---|---|---|
Issuer | 证书的发布机构 | 发布证书的机构,指明证书是哪个公司创建的(并不是指使用证书的公司)。 出了问题具体的颁发机构是要负责的 |
Valid from Valid to |
证书的有效期 | 证书的使用期限。过了这个期限证书就会作废,不能使用。 |
Public key | 公钥 | 用于对消息加密 |
Subject | 主题 | 证书是颁发给谁了,一般是个人或公司名称或机构名称或公司网站的网址。 |
Signature algorithm | 签名所使用的算法 | 数字证书的数字签名所使用的加密算法,根据这个算法可以对指纹解密。指纹加密的结果就是数字签名。 |
Thumbprint Thumbprint algorithm |
指纹以及指纹算法 (一种HASH算法) |
指纹和指纹算法会使用证书机构的私钥加密后和证书放在一起。主要用来保证证书的完整性,确保证书没有修改过。 使用者在打开证书时根据指纹算法计算证书的hash值,和刚开始的值一样,则表示没有被修改过 |
绕了一大圈,问题回来了。
首先应用程序读取证书中的Issuer(发布机构),然后会在操作系统或浏览器内置的受信任的发布机构中去找该机构的证书(为什么操作系统会有受信任机构的证书? 先看完这个流程再来回答)。如果找不到就说明证书是水货,证书有问题,程序给错误信息。 如果找到了,或用户确认使用该证书。就会拿上级证书的公钥,解密本级证书,得到数字指纹。 然后对本级证书的公钥进行数字摘要算法(证书中提供的指纹加密算法)计算结果,与解密得到的指纹对比。 如果一样,说明证书没有被修改过。公钥可以放心使用,可以开始握手通信了。
其实证书发布机构除了给别人发布证书外,自己也有自己的证书。在操作系统安装好时,受信任的证书发布机构的数字证书就已经被微软安装在操作系统中了,根据一些权威安全机构的评估,选取一些信誉很好并且通过一定安全认证的证书发布机构,把这些证书默认安装在操作系统中并设为信任的数字证书。发布机构持有与自己数字证书对应的私钥,会用这个私钥加密所有他发布的证书及指纹整体作为数字签名。
服务端并不是真的加密这个字符串,而是把字符串进行hash计算后再进行加密后发送给客户端。客户端收到后再解密这个hash值与原来字符串的hash值对比,从而确定对方是否持有私钥。
给通信的内容加版本号或随机值,如果接收到版本号或随机值不相同的信息,双方立刻停止通信。若一直捣乱就无法正常通信,因为有人控制了你的路由器,可以针对你。所以一些对于安全性较强的部门来说就不使用公网,而是内部网络,一般不会被破环通信。
HTTP协议到现在为止总共经历了3个版本的演化,第一个HTTP协议诞生于1989年3月
HTTP 0.9是第一个版本的HTTP协议,已过时。它的组成极其简单,只允许客户端发送GET这一种请求,且不支持请求头。由于没有协议头,造成了HTTP 0.9协议只支持一种内容,即纯文本。不过网页仍然支持用HTML语言格式化,同时无法插入图片。
HTTP 0.9具有典型的无状态性,每个事务独立进行处理,事务结束时就释放这个连接。由此可见,HTTP协议的无状态特点在其第一个版本0.9中已经成型。一次HTTP 0.9的传输首先要建立一个由客户端到Web服务器的TCP连接,由客户端发起一个请求,然后由Web服务器返回页面内容,然后连接会关闭。如果请求的页面不存在,也不会返回任何错误码。
HTTP协议的第二个版本,第一个在通讯中指定版本号的HTTP协议版本,至今仍被广泛采用。相对于HTTP 0.9 增加了如下主要特性:
- 请求与响应支持头域
- 响应对象以一个响应状态行开始
- 响应对象不只限于超文本
- 开始支持客户端通过POST方法向Web服务器提交数据,支持GET、HEAD、POST方法
- (短连接)每一个请求建立一个TCP连接,请求完成后立马断开连接。这将会导致2个问题:连接无法复用,head of line blocking。连接无法复用会导致每次请求都经历三次握手和慢启动。三次握手在高延迟的场景下影响较明显,慢启动则对文件类请求影响较大。head of line blocking会导致带宽无法被充分利用,以及后续健康请求被阻塞。
HTTP协议的第三个版本是HTTP 1.1,是目前使用最广泛的协议版本 。HTTP 1.1是目前主流的HTTP协议版本,因此这里就多花一些笔墨介绍一下HTTP 1.1的特性。
HTTP 1.1引入了许多关键性能优化:keepalive连接,chunked编码传输,字节范围请求,请求流水线等
- Persistent Connection(keepalive连接):允许HTTP设备在事务处理结束之后将TCP连接保持在打开的状态,以便未来的HTTP请求重用现在的连接,直到客户端或服务器端决定将其关闭为止。在HTTP1.0中使用长连接需要添加请求头 Connection: Keep-Alive,而在HTTP 1.1 所有的连接默认都是长连接,除非特殊声明不支持( HTTP请求报文首部加上Connection: close )。服务器端按照FIFO原则来处理不同的Request。
- chunked编码传输:该编码将实体分块传送并逐块标明长度,直到长度为0块表示传输结束,这在实体长度未知时特别有用(比如由数据库动态产生的数据)
- 字节范围请求:HTTP1.1支持传送内容的一部分。比方说,当客户端已经有内容的一部分,为了节省带宽,可以只向服务器请求一部分。该功能通过在请求消息中引入了range头域来实现,它允许只请求资源的某个部分。在响应消息中Content-Range头域声明了返回的这部分对象的偏移值和长度。如果服务器相应地返回了对象所请求范围的内容,则响应码206(Partial Content)
- Pipelining(请求流水线) 另外,HTTP 1.1还新增了如下特性:
- 请求消息和响应消息都支持Host头域:在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。因此,Host头的引入就很有必要了。
- 新增了一批Request method:HTTP1.1增加了OPTIONS,PUT, DELETE, TRACE, CONNECT方法
- 缓存处理:HTTP/1.1在1.0的基础上加入了一些cache的新特性,引入了实体标签,一般被称为e-tags,新增更为强大的Cache-Control头。
HTTP 2.0是下一代HTTP协议,HTTP 2.0最大的特点:不会改动HTTP 的语义,HTTP 方法、状态码、URI 及首部字段,等等这些核心概念上一如往常,却能致力于突破上一代标准的性能限制,改进传输性能,实现低延迟和高吞吐量。而之所以叫2.0,是在于新增的二进制分帧层。目前应用还非常少。主要特点有:
- 二进制分帧。在二进制分帧层上, HTTP 2.0 会将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码 ,其中HTTP1.x的首部信息会被封装到Headers帧,而我们的request body则封装到Data帧里面。原先我们是以HTTP报文为单位传输的,现在HTTP报文被拆成了多个帧的形式,并且这些帧可以乱序发送,我们只需根据每个帧首部的流标识符就可以重新完成组装。这样极大提升了HTTP的性能。
- 多路复用。多路复用允许同时通过单一的 TCP 连接 连接发起多重的请求-响应消息。在 HTTP/1.1 协议中 客户端在同一时间,针对同一域名下的请求有一定数量限制。超过限制数目的请求会被阻塞。针对这一个情况,2.0中采用了多路复用的机制,通过单一的 HTTP/2 连接可以发起多重的请求-响应报文,这样就不用依赖多个TCP连接了。
- HTTP 2.0 通信都在一个连接上完成,这个连接可以承载任意数量的双向数据流。相应地,每个数据流以消息的形式发送,而消息由一或多个帧组成,这些帧可以乱序发送,然后再根据每个帧首部的流标识符重新组装。
- 头部压缩:每次HTTP请求都会有一个请求首部,这个首部放到一些重要信息,比如Cookie、User Agent之类的字段,这些字段每次请求都是一样的,但还必须要带上。这就造成了一些不必要的浪费。2.0中就优化这一点,引入首部压缩机制,客户端和服务端会维护同样一张首部信息表,每次请求只要发送索引号就可以了,不必带上请求首部上冗余的key-value,极大地减少了不必要的浪费。
- 随时复位:HTTP1.1一个缺点是当HTTP信息有一定长度大小数据传输时,你不能方便地随时停止它,中断TCP连接的代价是昂贵的。使用HTTP2的RST_STREAM将能方便停止一个信息传输,启动新的信息,在不中断连接的情况下提高带宽利用效率。
- 服务器端推流:在2.0之前的版本中,服务端是属于被动一方,只有客户端发送请求,服务端才能发送资源。2.0协议中,服务端可以主动地向客户端发送资源。例如:客户端请求一个html,里面所需要的js和css完全不需要客户端解析完html之后再去请求这些内容那么麻烦,服务端可以在客户端请求html的时候一起回传过来。
- 优先权和依赖:每个流都有自己的优先级别,会表明哪个流是最重要的,客户端会指定哪个流是最重要的,有一些依赖参数,这样一个流可以依赖另外一个流。优先级别可以在运行时动态改变,当用户滚动页面时,可以告诉浏览器哪个图像是最重要的,你也可以在一组流中进行优先筛选,能够突然抓住重点流。