HTTP的那些事儿

news/2024/11/26 15:59:38/

超文本传输协议(Hyper Text Transfer Protocol,HTTP),它是在计算机世界中的两个点之间传递文本,图片,多媒体等超文本文件的协议。HTTP处在数据链路层,网络层,传输层,应用层中的应用层,基于TCP之上。

HTTP的特点

  1. 应用广泛,各大网站,APP都离不开HTTP的身影
  2. 无状态,和TCP不同,HTTP是无状态的,第一次对话后第二次对话服务端还是不认识客户端
  3. 请求应答。HTTP协议是双向的,一问一答
  4. 可靠传输。HTTP因为是基于TCP的所以不会丢包
  5. 明文传输。早期的HTTP是明文传输的

HTTP的缺点

  1. 随着时代的发展HTTP的性能渐渐达不到要求
  2. 原本明文传输的HTTP不具有安全性
  3. 无状态的特点导致需要通过Cookie为HTTP添加状态

HTTP的优点

  1. 简单,方便扩展。使用扩展出来的Cookie轻松解决无状态问题。
  2. 应用广泛,环境成熟

HTTP在性能上做的努力

在上古时期,HTTP0.9这个版本发送一个HTTP请求就会断开TCP连接,再次发起HTTP请求需要重新建立TCP连接。我们知道一个TCP链接需要3次握手和4次挥手,至少需要3RTT。而一个HTTP请求是2RTT(请求 + ACK确认 + 响应 + ACK确认),一共是5RTT而一次HTTP请求有3 / 5是浪费在TCP上的,造成的时间浪费触目惊心。为了优化这个问题HTTP1.0提供了Connection: Keep-Alive,可以让一个TCP链接排队发送多个HTTP请求。这样多个HTTP请求均摊了TCP链接建立需要的时间,从一定程度上优化了HTTP的性能。

现在的网站需要发送的请求数量和以前不在一个数量级,如果浏览器只能建立一个TCP链接,在这一个TCP链接上排队发送请求,那太慢了,所以浏览器允许针对同一个域名建立6个左右的TCP链接,并发请求网站需要的资源。但是随着时代的发展在一些情况下一个域名并发6个TCP也不太够,所以可以通过域名分片的方式来解决的这个问题,例如jd.com这个域名并发6个,可以将一些静态资源放在static.jd.com这样两个加一起可以并发到12个左右。(浏览器对于TCP并发的限制我理解是防止服务器扛不住)

上面说到一个TCP链接里HTTP请求只能排着队,一个一个请求。我认为这是以下两个原因导致的:

  1. HTTP是请求 - 应答模式的
  2. HTTP是明文的,文本格式的,也就是说只能通过顺序才能识别出响应和请求的对应关系

这个问题就是著名的队头阻塞,请求必须排着队一个一个来,队头处理时间长了那么后面的都得等着。

为了解决这个问题,提升HTTP传输的速度,经过google的努力推出了HTTP2。HTTP2在性能上我理解主要做了两件事:

  • 一个是改变了HTTP文本传输的现状,改成了二进制传输,引入了帧和流的概念,让HTTP的请求和响应可以乱序收发,在很大程度上改善了队头阻塞问题。
  • 另一个是引入了HPACK算法对HTTP头部进行压缩。因为HTTP报文很多都没有实体,而主要的内容是url和对应的query,而头部的字段包括Cookie等信息每次请求都要带上造成了极大的浪费,并且大多数请求过程中这些头部信息都不会修改。为了解决传输过程中HTTP头部过大的问题,HTTP2使用HPACK来对头部内容进行压缩,HPACK引入了动态索引表和静态表的内容,如果头部没有变动,只用传输表中对应的索引,两端根据索引就可以知道传输的头部内容是什么,极大的压缩了HTTP头部的传输数据量,提升传输速度。

到这里HTTP性能已经优化了很多并且一个域名只需要对应一个TCP链接即可。

为什么说HTTP2只是很大程度上解决了队头阻塞问题呢

因为HTTP是基于TCP的,而TCP是可靠传输,在发送一个包之后会再发送一个TCP请求来确认这个包是否传输完成,如果丢了需要重发已确保传输数据的完整性,在网络差的环境下TCP也会因为丢包导致阻塞,TCP需要等待包全都收到之后才会将收到的包一起交给应用层。为了解决这个问题google又推出了HTTP3革了HTTP2的命。HTTP3是基于QUIC的。QUIC是应用层协议,它基于UDP而不是TCP,所以QUIC没有上面说到的阻塞问题,当然QUIC也是在UDP上实现了可靠传输的能力,换句话说QUIC协议取了TCP的精华。为什么不在TCP上直接改呢?我理解应该是改不动,老设备兼容是一个要命的事,所以只能新推出一个协议QUIC

到这里对于协议本身的优化就告一段落了。

除了对于协议本身的优化,还可以通过Content-Encoding: gizp来压缩实体体积,让传输的数据量减少,进一步提升HTTP传输数据的速度。

HTTP在安全上做的努力

HTTP在安全上其实没做啥努力,在努力的其实是背后的SSL/TLS。

什么是安全性

安全性由四大部分组成,分别是机密性、完整性、身份认证和不可否认

HTTP是明文传输的,在传输链路中间,就可能被第三方偷窥(丧失了机密性),篡改(丧失了完整性),发送请求的对象也不知道是谁(丧失了身份认证),无法确保完整和身份认证,那么对方完全可以否认发过这个消息(丧失了不可否认性)。

SSL/TLS实现了HTTP的安全性,所以安全的HTTP被称为HTTPS。

可以考虑下在不受信任的网络环境中怎么才能安全的通信呢?

第一个想到的就是对通信内容进行加密,通过一套加密规则,配合上秘钥对通信内容加密,这样我们在网络中发送的是密文,即使第三方截获也无法破解。但是问题来了,这个秘钥怎么给到对方呢?通过网络吗?那不是被截获之后还是被轻松解密吗?可以再对秘钥加密一下,那用于加密秘钥的秘钥咋弄?所以只用对称加密的方式秘钥交换就成了问题。

机密性

这就轮到另一种加密方式出场了,非对称加密。和加密解密使用同一个秘钥的对称加密不同,非对称加密有两个秘钥,一个公钥(可以给所有人),一个私钥(只能自己持有,需要保密),公钥加密的内容只有私钥可以解密,反过来私钥加密的内容只有公钥可以解密。

有了新工具非对称加密,服务端可以将自己的公钥下发给客户端,这样客户端可以使用公钥将对称加密的秘钥加密给到服务端,服务端使用自己的私钥解密拿到对称加密的公钥开始接下来的加密通信。事情好像完美解决了。

但是话说回来为什么不直接使用非对称加密加密通信内容,而是要加密对称加密的秘钥?

这是因为对称加密和非对称加密的计算速度差了好几个数量级,所以为了提升速度非对称加密只用于交换秘钥。

通过这一套方法实现了HTTP的机密性。但是除了机密性,安全性中还剩下完整性,身份认证和不可否认这三个事情。

完整性

虽然现在实现了HTTP的机密性,但是第三方还是可以截获机密的报文对报文篡改后重新发送给服务端,收集足够多的报文尝试做够多次,可以根据服务器的不同返回值观察总结从而破解出秘钥(具体咋操作我也不清楚)。所以如果服务器可以知道这个报文在中途被篡改过,那么就不响应就大大提升了通信的安全性。

为了增加完整性,需要引入摘要算法,摘要算法可以将任意长度的数据压缩成定长,并且摘要算法具有雪崩效应,对于原文的一点改动生成的摘要则完全不同,同时摘要算法生成的摘要不可逆。

我们可以通过摘要算法生成原始数据的摘要,并附上原始数据一起发送给对方,这样如果被修改过,那么肯定和摘要是对不上的。当然通信必须要建立在机密性之上,否则连原文和摘要一起改那也就束手无策了。

到这里完整性和机密性都具备了,还差身份认证和不可否认。

身份认证和不可否认

为什么有了机密性和完整性本次会话还是不安全的呢?问题出在了通信的两个端点上,到目前为止,客户端只知道服务端的一个公钥,但是这个公钥谁都能拿到,客户端并不知道这个公钥就是公钥所有者给它的。为了证明公钥来自所有者,可以让服务端使用自己的私钥给上面提到的摘要签名,因为私钥是所有者私有的别人不会知道。客户端收到消息之后会进行验签。首先对报文内容生成摘要,再使用公钥解密服务端发送过来的数字签名,两者进行对比,如果一致则表示没问题,认证了公钥和私钥确认配对,同时这个消息确实是这个公钥所有者发出的。同时实现了身份认证和消息的不可否认性。

数字证书和CA

这就完了吗?既然有这个问题那么就说明肯定没完。

公钥的信任问题,客户端怎么知道这个公钥就是jd.com的公钥呢?中间人完全可以使用自己的一套公钥和私钥,给客户端一套自己的公钥完成上面说的流程也完全实现了安全性的四个要求(我理解这就是抓包工具抓取HTTPS包的实现原理)。所以事情还没结束。

服务端的公钥不可信,怎么办?这时需要有三方力量介入,告诉客户端这个公钥确实是jd.com这个域名的。怎么告诉呢?通过给这个公钥颁发数字证书,为这个公钥和jd.com这个域名等其它信息生产摘要,再使用颁发证书这个机构自己的私钥给这个摘要签名,这些信息一起打包生成一个数字证书。

客户端拿到这个证书之后,会使用证书中的公钥验证一下这个证书有没有被篡改过,然后看下jd.com这个域名和他的公钥是否对的上。

问题又来了,这个机构的公钥是不是真的?为什么要相信这个机构办法的证书呢?为了解决这个问题,这个机构需要再找一个机构来帮它证明一下。这么看来这件事没有止境了。所以我们必须要相信有几个机构的证书是可信的,否则这个体系就走不下去了。这些机构颁发的证书就是根证书是信任链的起点。这些根证书是被内置在系统中的,当验证走到这一层时就表示之前获得的证书是可信的。

是可信的吗???没有绝对的安全,比如说这个根证书机构搞错了,受到了欺骗,将自己的证书颁发给了失信机构,这就是不安全的。再比如说这个机构被黑客攻击了随意颁发证书。。。所以针对这两种情况,第一会采取证书吊销的方式规避风险,而第二种则可以将这个机构的根证书从系统中删除,让这个机构颁发的证书都不被信任。

参考

极客时间HTTP透视协议专栏


http://www.ppmy.cn/news/47284.html

相关文章

java 资料地址汇总

1 SpringBoot - 使用 Assert 校验让业务代码更简洁 SpringBoot - 使用 Assert 校验让业务代码更简洁 2 MyBatis-Plus 还手写 Join 联表查询?一个依赖轻松搞定,真香! MyBatis-Plus 还手写 Join 联表查询?一个依赖轻松搞定&#…

中小企业面临怎样的数字化转型局面

当前,我国经济长期向好的基本面没有改变,但承受着“需求收缩、供给冲击、预期减弱”的三重压力,中小企业的数字化转型之路较之以往更加艰难、曲折。为帮助中小企业纾困解难、平稳渡过危机,需进一步优化政策“组合拳”,…

CMake

CMake定义 CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C特性,类似UNIX下的automake。只是 CMake 的组态档取名为 C…

背包问题——01背包|完全背包

目录 前言&背包问题的历史 01背包 1、题目 2、暴力解01背包 Ⅰ、代码 3、动态规划解01背包 Ⅰ、二维dp数组解01背包 1)dp数组的含义 2)递推公式 3)dp数组的初始化 4)遍历顺序的讨论 5、代码 Ⅱ、一维数组解01背包 1&…

[API]集合Collection常用方法集合遍历新循环泛型(三)

什么是集合: 集合和数组一样,可以保存一组数据,并且提供了操作数组元素的相关方法,使用用更加方便 集合框架中的相关接口: java.util.Collection接口:是所有集合的顶级接口,封装了所有集合所…

【理解 C++ 中的头文件和源文件的作用 】

include文件中定义 src文件中声明 头文件中应该只放变量和函数的声明,而不能放它们的定义。 在 C 中,头文件和源文件有着不同的作用。它们共同组成了 C 项目的基本结构。让我们逐个了解它们的作用。 头文件(.h 或 .hpp 文件)&a…

【从零开始学Skynet】实战篇《球球大作战》(十四):agent跨服务器版

至此,我们已完成了《球球大作战》的绝大部分功能,只剩下完 善agent ,让它和 scene 服务联动了。 1、多个模块 一般而言,代理服务会承载很多系统,比如邮件、成就等,此处涉及的代码较多,容易混 乱…

初中级测试工程师,软件测试面试题总结大全(功能/接口/自动化测试)你要的都有...

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 一般软件测试的面…