目录
一、HTTP基本概念
二、GET 与 POST
2.1、GET 与 POST 有什么区别?
2.2、GET 和 POST 方法都是安全和幂等的吗?
三、HTTP 缓存
3.1、强制缓存:
3.2、协商缓存
四、HTTP 特性
4.1、HTTP/1.1
4.1.1、HTTP/1.1 的优点
4.1.2、HTTP/1.1 的缺点
4.1.3、HTTP/1.1 的性能
五、HTTP 与 HTTPS
5.1、HTTP 与 HTTPS 的区别
5.2、HTTPS 解决了 HTTP 的哪些问题呢?
5.3、HTTPS 是如何建立连接的?
5.4、HTTPS 的应用数据是如何保证完整性的?
5.5、HTTPS 就一定安全可靠吗?
5.6、为什么抓包工具能够截取 HTTPS 数据?
六、HTTP/1.1、HTTP/2、HTTP/3 的演变
6.1、HTTP/1.1 相比 HTTP/1.0 提高了什么性能?
6.2、HTTP/2 的优化
6.3、HTTP/2 的缺陷
6.4、HTTP/3 做了哪些优化?
七、HTTP/1.1 如何优化?
7.1、避免发送 HTTP 请求
7.2、如何减少 HTTP 请求次数?
7.2.1、减少重定向次数:
7.2.2、和并请求
7.2.3、延迟发送请求
7.3、如何减少 HTTP 响应的数据大小
八、HTTPS RSA 握手解析
RSA 握手握手过程:
TLS 第一次握手:
TLS 第二次握手:
TLS 第三次握手:
TLS 第四次握手
RSA 算法的缺陷
九、优化 HTTPS
HTTP(HyperText Transfer Protocol):是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范。
HTTP常见的状态码有:
HTTP 常见的字段:
安全和幂等的概念:
如果从规范定义来看:
避免发送 HTTP 请求的方法就是通过缓存技术,HTTP 设计者早在之前就考虑到了这点,因此 HTTP 协议的头部有不少是针对缓存的字段,HTTP 缓存有两种实现方式,分别是强制缓存和协商缓存。
强缓存是指只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在浏览器这边。
强缓存是依赖下面两个 HTTP 响应头部(Response Header)字段实现的,都用来表示资源在客户端缓存的有效期:
如果 HTTP 响应头部同时有 Cache-Control 和 Expires 字段的话,Cache-Control 的优先级高于 Expires。
Cache-Control 选项更多一些,设置更加精密,所以建议使用 Cache-Control 来实现强缓存,流程如下:
当我们在浏览器使用开发者工具时,可能会看到某些请求的响应码是 304 ,这个是告诉浏览器可以使用本地缓存的资源,通常这种通过服务端告知客户端是否可以使用缓存的方式被称为协商缓存。
协商缓存可以基于两种头部来实现:
第一种:请求头部的 If-Modified-Since 字段与响应头部中的 Last-Modified 字段实现,这两个字段的意思是:
响应头部中的 Last-Modified :标示这个响应资源的最后修改时间
请求头部中的 If-Modified-Since :当资源过期了,发现响应头中具有 Last-Modified 声明,则再次发起请求的时候带上 Last-Modified 的时间,服务器收到请求后发现有 If-Modified-Since 则与被请求资源的最后修改时间进行对比(Last-Modified),如果最后修改时间较新(大),说明资源又被修改过,则返回最新资源,HTTP 200 OK;如果最后修改时间较旧(小),说明资源无新修改,响应 HTTP 304 走缓存。
第二种:请求头部中的 If-None-Match 字段与响应头部中的 ETag 字段,这两个字段的意思是:
响应头部中 ETag :唯一标识响应资源
请求头部中的 If-None-Match:当资源过期时,浏览器发现响应头中有 ETag,则再次向服务器发起请求时,会将请求头 If-None-Match 值设置为 ETag 的值。服务器收到请求后进行比对,如果资源没有变化返回 304,如果资源变化了返回 200。
第一种方式是基于时间实现的,第二种方式是基于一个唯一标识实现的,相对于后者可以更加准确地判断文件内容是否被修改,避免由于时间篡改导致的不可靠的问题。
如果第一次请求资源的时候,服务端返回的 HTTP 响应头部同时有 ETag 和 Last-Modified 字段,那么客户端再下一次请求的时候,如果带上了 ETag 和 Last-Modified 字段信息给服务端,这时 ETag 的优先级更高,也就是服务端会判断 ETag 是否变化了,如果 ETag 有变化则不用在判断 Last-Modified 了,如果 ETag 没有变化,然后再看 Last-Modified。
为什么 ETag 的优先级更高呢?这是因为它主要能解决 Last-Modified 几个比较难的问题:
注意:协商缓存这两个字段都需要配合强制缓存中 Cache-Control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。
当使用 ETag 字段实现的协商缓存的过程:
①、简单
HTTP 基本的报文格式就是 header + body ,头部信息也是 key-value 简单文本的形式,易于理解,降低了学习和使用的门槛
②、灵活和易于拓展
HTTP 协议中的各类请求方法、URI/URL 、状态码、头字段等每个组成要求都没有被固定死,都允许开发人员自定义和扩充。同时由于 HTTP 是工作在应用层,则它下层可以随意变化,比如:
HTTPS 就是在 HTTP 与 TCP 层之间增加了 SSL/TLS 安全传输层
HTTP/1.1 和 HTTP/2.0 传输协议使用的是 TCP 协议,而到了 HTTP/3.0传输协议改用了 UDP 协议
③、应用广泛和跨平台
①、无状态双刃剑
无状态的好处就是服务器不会记忆 HTTP 的状态,所以不需要额外的资源来记录状态信息,这能减轻服务器的负担,能够把更多的 CPU 和内存用来对外提供服务。
坏处就是,既然服务器没有记忆能力,它在完成有关联性的操作时会非常麻烦,每操作一次就要验证一次,对于无状态的问题,解决方法比较简单的方式就有 Cookie 技术。Cookie 通过在请求和响应报文中写入 Cookie 信息来控制客户端的状态,相当于,在客户端第一次请求之后,服务器会发下一个装有客户信息的【小贴纸】,后续客户端请求服务器的时候,带上【小贴纸】,服务器就能够认得了。
②、明文传输双刃剑
明文传输意味着在传输过程中的信息,是可方便阅读的,比如抓包都可以直接肉眼查看,为我们调式工作带来了极大的遍历。但正因为如此,HTTP 的所有信息都暴露在外,相当于信息裸奔。在传输的过程之中,信息的内容都毫无隐私可言,很容易被窃取。
③、不安全
HTTP 协议是基于 TCP/IP ,并且使用了【请求-应答】的通信模式,所以性能的关键就在此处。
长连接:早期 HTTP/1.0 性能上的很大问题就是,没法起一个请求就要新建一次 TCP 连接,而且是串航请求,做了所谓的 TCP 连接建立和断开,增加了通信的开销。HTTP/1.1 提出了长连接的通信方式,也叫持久连接,好处在于减少了 TCP 连接的重复建立和断开所造成的额外开销,减轻了服务端的负载
管道网络传输:即可在同一个 TCP 连接里,客户端可以发起多个请求,只要第一个请求发送出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。但是服务器必须按照接受请求的顺序发送对这些管道化请求的响应。所以 HTTP /1.1 管道解决了请求的队头阻塞,但是没有解决响应的队头阻塞
队头阻塞:当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一同被阻塞了,会招致客户端一直请求不到数据,这就是【队头阻塞】
如何解决的呢?
具体的实现方法:
混合加密:
HTTPS 采用的是对称加密和非对称加密结合的【混合加密】方式:
在通信建立前采用非对称加密的方式交换【会话密钥】,后续就不再使用非对称加密
在通信过程中全部使用对称加密的【会话密钥】的方式加密明文数据
采用混合加密的方式的原因:
摘要算法 + 数字签名:
在计算机里使用摘要算法(哈希函数)来计算出内容的哈希值,也就是内容的【指纹】,这个哈希值是唯一的,且无法通过哈希值推导出内容。
通过哈希算法可以确保内容不被篡改,但是并不能保证【内容 + 哈希值】不会被中间人替换,因为这里缺少对客户端收到的信息是否来源于服务端的证明。
为了避免这种情况,计算机会采用非对称加密算法来解决:
这两个密钥可以双向加解密的,比如可以用公钥加密内容,私钥解密,也可以用私钥加密内容,公钥加密内容。
流程不同意味着目的也不同:
一般我们不会用非对称加密来加密实际的传输内容,因为非对称加密的计算比较耗费性能的。
所以非对称加密的用途主要是在于通过【私钥加密,公钥解密】的方式,来确认消息的身份,我们常说的数字签名算法就是这种方式,不过私钥加密的内容不是内容本身,而是对内容的哈希值加密,私钥由服务器保管,然后服务器向客户端颁发对应的公钥。如果客户端收到的信息,能被公钥解密,就说明该信息是由服务器发送的。
数字证书
前面我们知道:可以通过哈希算法来保证消息的完整性,可以通过数字签名来保证消息的来源可靠性。但是还远远不够,缺少了身份验证的环节,万一公钥是伪造的呢?
举个:
拿请假的例子,虽然你爸爸持有私钥,老师通过是否能用公钥解密来确认这个请假条是不是来源你父亲的。
但是我们还可以自己伪造出一对公私钥啊!
你找了个夜晚,偷偷把老师桌面上和你爸爸配对的公钥,换成了你的公钥,那么下次你在请假的时候,你继续模仿你爸爸的字迹写了个请假条,然后用你的私钥做个了「数字签名」。
但是老师并不知道自己的公钥被你替换过了,所以他还是按照往常一样用公钥解密,由于这个公钥和你的私钥是配对的,老师当然能用这个被替换的公钥解密出来,并且确认了内容的完整性,于是老师就会以为是你父亲写的请假条,又允许你请假了。
好家伙,为了一个请假,真的是斗智斗勇。
后面你的老师和父亲发现了你伪造公私钥的事情后,决定重新商量一个对策来应对你这个臭家伙。
正所谓魔高一丈,道高一尺。
既然伪造公私钥那么随意,所以你爸把他的公钥注册到警察局,警察局用他们自己的私钥对你父亲的公钥做了个数字签名,然后把你爸爸的「个人信息 + 公钥 + 数字签名」打包成一个数字证书,也就是说这个数字证书包含你爸爸的公钥。
这样,你爸爸如果因为家里确实有事要向老师帮你请假的时候,不仅会用自己的私钥对内容进行签名,还会把数字证书给到老师。
老师拿到了数字证书后,首先会去警察局验证这个数字证书是否合法,因为数字证书里有警察局的数字签名,警察局要验证证书合法性的时候,用自己的公钥解密,如果能解密成功,就说明这个数字证书是在警察局注册过的,就认为该数字证书是合法的,然后就会把数字证书里头的公钥(你爸爸的)给到老师。
由于通过警察局验证了数字证书是合法的,那么就能证明这个公钥就是你父亲的,于是老师就可以安心的用这个公钥解密出请假条,如果能解密出,就证明是你爸爸写的请假条。
正是通过了一个权威的机构来证明你爸爸的身份,所以你的伪造公私钥这个小伎俩就没用了。
在计算机里,这个权威的机构就是 CA(数字证书认证机构),将服务器公钥放在数字证书中,只要证书是可信的,公钥就是可信的。
SSL/TLS 协议基本流程:
........................
TLS 在实现上分为握手协议和记录协议两层:
具体过程如下:
记录协议完成后,最终的报文数据将传递到传输控制协议(TCP)层进行传输
如果有假基站起了转发全部信息的作用,这样是不是假基站就获取到全部信息了,从而造成数据泄露?
这个场景就是:客户端通过浏览器向服务端发起 HTTPS 请求时,被【假基站】转发到了一个【中间人服务器】,于是客户端是和【中间人服务器】完成了 TLS 握手,然后这个【中间人服务器】再与真正的服务器完成 TLS 握手
具体过程如下:
从客户端的角度看,其实并不知道网络中存在中间人服务器这个角色。那么中间人就可以解开浏览器发起的 HTTPS 请求里的数据,也可以解开服务端响应给浏览器的 HTTPS 响应数据。相当于中间人能够偷看浏览器与服务端之间的 HTTPS 请求与响应数据
但是这是有前提的,前提是用户必须点击接受了中间人服务器的证书。
中间人服务器与客户端在 TLS 握手的过程中实际上发送了自己为造册证书给浏览器,而这个伪造的证书是能被浏览器(客户端)识别出是非法的,于是会提醒用户该证书存在问题。如果用户执意点击【继续浏览此网站】,相当于接受了中间人伪造的证书,那么后续整个 HTTPS 通信都能被中间人监听了。另外,如果你的电脑中毒了,被恶意导入了中间人的根证书,那么在验证中间人的证书的时候,由于你的操作系统信任了中间人的根证书,那么等同于中间人的证书是合法的,这种情况下,浏览器是不会弹出任何存在问题的风险提示的。
很多抓包工具之所以可以明文看到 HTTPS 数据,工作原理与中间人一致
对于 HTTPS 连接来说,中间人要满足以下两点,才能实现真正的明文代理:
中间人要拿到私钥只能通过如下方式:
很显然只能通过第三种取得中间人的身份,使用抓包工具进行 HTTPS 抓包的时候,需要在客户端安装 Fiddler 的根证书,这里实际上起到认证中心(CA)的作用。抓包工具能够抓包的关键是客户端会往系统受信任的根证书列表中导入抓包工具生成的证书,而这个证书会被浏览器信任,也就是抓包工具自己创建了一个认证中心CA,客户端拿着中间人签发的证书去中间人自己的 CA 去认证,当然认为这个证书是有效的。
如何避免被中间人抓取信息呢?
首先我们要保证自己电脑的安全,不要被病毒侵入,而且也不要点击任何证书非法的网站,这样 HTTPS 数据就不会被中间人截取到了,当然还可以通过 HTTPS 双向认证的方式来避免这种问题,一般我们的 HTTPS 都是单向认证,客户端只会验证了服务端的身份,但是服务端不会验证客户端的身份,如果服务端检测到了客户端是不可信任的,服务端就拒绝通信,客户端如果发现服务端也是不可信任的,也终止通信。
HTTP/1.1 相比 HTTP/1.0 性能上的改进:
但 HTTP/1.1 还是有性能瓶颈的:
HTTP/2 是基于 HTTPS 的,所以 HTTP/2 的安全性也是由保证的
HTTP/2 相比 HTTP/1.1 性能上的优化:
头部压缩:如果你同时发出多个请求,它们的头部是一样的或者类似的,那么协议会帮你消除重复的部分这就是【HPACK】算法:在客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样的字段了,只发送索引号,就能提高速度了
二进制格式:不再像 HTTP/1.1 里的纯文本形式的报文,而是全面采用了二进制格式,头信息和数据体都是二进制,并且统称为帧:头信息帧和数据帧。虽然对人不太友好,但是对计算机非常好,收到报文之后,无需再将明文的报文转化成二进制,而是直接解析二进制报文,这增加了数据的传输效率。
并发传输:我们都知道 HTTP/1.1 是基于【请求-响应】模型的,同一个连接中,HTTP 完成一个事务,才能处理下一个事务,也就是说发出请求等待响应的过程中,是没办法做其他事情的,如果响应迟迟下不来,那么后续的请求是无法被发送的,也就造成了队头堵塞的问题。而 2.0 引入了 Stream 的概念。多个 Stream 复用在一条 TCP 连接上,Stream 中可以包含多个 message ,一个message 中包含多个 Frame ,Frame 是 2.0 的最小单位,以二进制压缩格式存放HTTP/1 的内容。针对不同的 HTTP 请求用独一无二的 Stream ID 来区分,接收端可以通过 Stream ID 有序组装成 HTTP 消息,不同的 Stream 的帧是可以乱序发送的,因此可以并发不同的 Stream ,也就是 HTTP/2 可以并行交错发送请求和响应,服务端收到后会根据相同的 Stream ID 有序组装成 HTTP 消息。
服务器主动推送资源:服务器不再是被动地响应,可以主动的向客户端发送消息,客户端和服务端都可以发送建立 Stream ,Stream ID 号是有区别的,客户端建立的 Stream 必须是奇数号,而服务器建立的 Stream 必须是偶数号。比如,客户端通过 请求从服务器获取到了 html 文件,而 html文件还需要 css 文件渲染,这时客户端还要再次发起获取 css 文件的请求,需要消息往返两次,如果是HTTP/2 服务器可以直接主动推送 css 文件,减少了消息传递的次数。
HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的,这样内核才会将缓冲区里的数据返回给 HTTP 应用,那么当【前一个字节数据】没有到达时,后收到的字节数据只能存放在内核缓冲区中,只有等到这一个字节数据到达时,HTTP/2 应用层才能从内核拿到数据,这就是 HTTP/2 队头阻塞的问题。所以,一旦出现了丢包现象,就会触发 TCP 的重传机制,这样在一个 TCP 连接中的所有 hTTP 请求都必须等待这个丢了的包被重传过来。
HTTP/1.1 和 HTTP/2 都有队头阻塞的问题:
HTTP/1.1 中的管道虽然解决了请求的队头阻塞,但是没有解决响应的队头阻塞,因为服务端需要按顺序响应收到的请求,如果服务端处理某个请求消耗的时间比较长,那么只能等待响应完这个请求后,才能处理下一个请求,这属于 HTTP 层队头阻塞。
HTTP/2 虽然通过多个请求复用一个 TCP 连接解决了 HTTP 的队头阻塞,但是一旦发生丢包,就会阻塞住所有的 HTTP 请求,这属于 TCP 层队头阻塞。
HTTP/3 是如何解决的呢?
HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP 协议!
UDP 传输协议是不管发送顺序、丢包的,所以不会出现像 HTTP/2 队头阻塞的问题。但基于 UDP 的 QUIC 协议,可以实现类似 TCP 的可靠传输。
QUIC 的 3 特点:
从三个优化思路来优化 HTTP/1.1协议:
对于一些具有重复性的 HTTP 请求,比如每次请求的数据都是相同的,我们可以把这对【请求-响应】的数据都缓存在本地,那么下次就直接读取本地的数据,不必在通过网络获取服务器的响应。
从这几个方面入手:
什么是重定向:服务器上的一个资源可能由于迁移等原因从 url1 移至 url2 后,客户端不知情,还是继续请求 url1,这是服务器不能暴力返回错误,而是通过 302 响应码和 Location 头部,告诉客户端该资源已经迁移至 url2 了,于是客户端需要再发送 url2 请求以获得服务器的资源。
如果重定向请求越多,那么客户端就要多次发起 HTTP 请求,每一次的 HTTP 请求都得经过网络,这无疑会降低网络性能。
另外,服务端这一方往往不只有一台服务器,比如源服务器上一级是代理服务器,然后代理服务器与客户端通信,这时客户端重定向就会导致客户端与代理服务器之间需要 2 次消息传递,如果将重定向的工作交由代理服务器完成就能减少 HTTP 请求的次数啦:
把多个访问小文件的请求合并成一个大的请求,虽然传输的总资源还是一样的,但是减少请求,也就意味着减少了重复发送的 HTTP 头部。
例如可以将多个小图片的请求合并成一个大图片来减少 HTTP 请求的次数,从而减少网络的开销。合并请求的方式就是合并资源,以一个大资源的请求替换多个小资源的请求。
但是这样会带来新的问题,当大资源中的某一个小资源发生变化后,客户端必须重新下载整个完整的大资源文件,这显然会带来额外的网络消耗。
一般 HTML 里会含有很多 HTTP 的 URL ,当前不需要的资源,我们没必要获取过来,于是可以通过按需获取的方式,来减少第一时间的 HTTP 请求次数。
请求网页的时候,没必要把全部的资源都获取到,而是只获取当前用户所看到的页面资源,当用户向下滑动的时候,再向服务器获取接下来的资源,这样就达到了延迟发送请求的效果。
对于 HTTP 的请求和响应,通常 HTTP 的响应数据大小会比较大,也就是服务器返回的资源会比较大。于是我们可以考虑对响应的资源进行压缩,这样就可以减少响应的数据大小,从而提高网络传输的效率。
传统的 TLS 握手基本都是使用 RSA 算法来实现密钥交换的,在将 TLS 证书部署服务端时,证书文件其实就是服务端的公钥,会在 TLS 握手阶段传递给客户端,而服务端的私钥则一直留在服务端,一定要确保私钥不能被窃取。
在 RSA 密钥协商算法中,客户端会生成随机密钥,并使用服务端的公钥加密后再传给服务端。根据非对称算法,公钥加密的消息仅能通过私钥解密,这样服务端解密后,双方就获取了相同的密钥,再用它加密应用信息。
客户端首先会发一个【Client Hello】消息,这是跟服务器【打招呼】,消息里面有客户端使用的 TLS 版本号,支持的密码套件列表,以及生成的【随机数(Client Random)】,这个随机数会被服务端保留,它是生成对称加密密码的材料之一。
当服务端收到客户端的【Client Hello】消息后,会确认 TLS 版本号是否支持,和从密码套件列表中选择一个密码套件,以及生成随机数(Server Random)。
接着返回【Server Hello】消息,消息里面有服务器确认的 TLS 版本号,也给出了随机数(Server Hello),然后从客户端的密码套件列表选择了一个合适的密码套件。
密码套件形式基本是【密码交换算法 + 签名算法 + 对称加密算法 + 摘要算法】。
就前面这两个客户端和服务端相互【打招呼】的过程,客户端和服务端就已经确认了 TLS 版本和使用的密码套件,而且你可能发现客户端和服务端都会各自生成一个随机数,并且还会把随机数传递给对方。这个随机数的作用就是为后续作为生成【会话密钥】的条件,所谓的会话密钥就是数据传输时,所使用的对称加密密钥。
然后服务端为了证明自己的身份,就会发送【Server Certificate】给客户端,这个消息里有数字证书,随后,服务端发了【Server Hello Done】消息,目的是告诉客户端,我已经把该给你的东西都给你了。
客户端验证完第二次握手发送来的证书之后,认为可信则继续。
接着,客户端会生成一个新的随机数(pre-master),用服务器的 RSA 公钥加密该随机数,通过【Client Key Exchange】消息传递给服务端。
服务端收到后,用 RSA 私钥解密,得到客户端发来的随机数(pre-master)。
至此,客户端和服务端双方都共享了三个随机数,分别是 Client Random,Server Random,pre-master。于是,双方根据已经得到得三个随机数,生成会话密钥(Master Secret),它是对称密钥,用于后续的 HTTP 请求/响应的数据加解密.然后客户端再发送一个【Encrypted Handshake Message(Finshd)】消息,把之前所有发送的数据做个摘要,再用会话密钥(master secret)加密一下,让服务器做个验证,验证加密通信是否可用和【之前握手信息是否有被中途篡改过】,可以发现,【Change Cipher Spec】之前传输的 TLS 握手数据都是明文,之后都是对称加密密钥的密文。
服务器也是同样的操作,发【Change Cipher Spec】和【Encrypted Handshake Message】消息,如果双方都验证加密和解密没问题,那么握手正式完成。最后,就用【会话加密】加解密 HTTP 请求和响应了
使用 RSA 密钥协商算法的最大问题是不支持前置保密,因为客户端传递随机数给服务端时使用的是公钥加密的,服务端收到后,会用私钥解密得到随机数。所以一旦服务端的私钥泄露了,过去被第三方捕获的所有 TLS 通讯密文都会被破解
硬件优化:HTTPS 协议是计算密集型,而不是 IO 密集型,所以可以升级性能更好的 CPU 或者选择可以支持 AES-NI 特性的 CPU,因为这款 CPU 在指令级别优化了 AES 算法,加速了加解密时间。
密钥交换算法优化:使用 RSA 密钥交换算法的 TLS 握手过程不仅慢,而且安全性也不高,如果可以尽量使用 ECDHE 密钥交换算法替换 RSA 算法。可以将 TLS 握手的消息往返由 2 RTT 减少到 1 RTT,而且安全性高,具备前向安全性
TLS 升级:直接把 TLS 的版本升级,大幅度减少握手的步骤,完成 TLS 握手只要 1 RTT,而且安全性更高
证书传递优化:减少证书的大小,可以节省带宽,减少客户的运算量。对于服务器的证书应该选择椭圆曲线证书(ECDSA)证书,而不是 RSA 证书,因为在相同安全强度下,ECC密钥长度比 RSA 要短得多
会话复用:会话复用分为两种一种是 Session ID,另外一种是 Session Ticket。
Session ID:客户端与服务端首次 TLS 握手连接后,双方会在内存缓存会话密钥用唯一的 Session ID 来标识,再次连接时,Hello 消息里就会带上 Session ID,服务器收到后就会在内存中找,如果找到就直接使用该会话密钥回复会话状态,跳过其余的过程,只用一个消息往返就可以建立安全通信。
缺点:
Session Ticket:服务器不再缓存每个客户端的会话密钥,而是把缓存的工作交给了客户端,类似于 HTTP 中的 Cookie,但是要注意的是需要对会话密钥设定一个合理的过期时间避免重放攻击。
重放攻击:
假设 A 想向 B 证明自己的身份。B 要求 A 的密码作为身份证明,A 应尽全力提供。与此同时 E 窃听了对话并保留了密码。
交换结束后,E 冒充 A 连接到 B ,当被要求提供身份证明时,E 发送从 B 接受的最后一个会话中读取的 A 的密码从而授予 E 访问权限。
重放攻击的危险之处在于,如果中间人截获了某个客户端的 Session ID 或 Session Ticket 以及 POST 报文,而一般的 POST 请求会改变数据库的数据,中间人就可以利用此截获的报文,不断地向服务器发送该报文,这样就会导致数据库的数据被中间人改变了,而客户是不知情的。