计算机网络之HTTP、HTTPS、HTTP2
GitHub:https://github.com/JDawnF
一、HTTP
HTTP 协议,是 Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。
HTTP 是一个无状态的协议。无状态是指客户机(Web 浏览器)和服务器之间不需要建立持久的连接,这意味着当一个客户端向服务器端发出请求,然后服务器返回响应(response),连接就被关闭了,在服务器端不保留连接的有关信息。HTTP 遵循请求(Request)/应答(Response)模型。客户机(浏览器)向服务器发送请求,服务器处理请求并返回适当的应答。所有 HTTP 连接都被构造成一套请求和应答。
主要特点如下:
-
简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有 GET、HEAD、POST 等等。每种方法规定了客户与服务器联系的类型不同。由于 HTTP 协议简单,使得 HTTP 服务器的程序规模小,因而通信速度很快。
-
数据格式灵活:HTTP 允许传输任意类型的数据对象。正在传输的类型由Content-Type 加以标记。
-
无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
主要指的是不使用 Keep-Alive 机制的情况下。
-
无状态:HTTP 协议是无状态协议。无状态,是指协议对于事务处理没有记忆能力。无状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
无状态,所以更容易做服务的扩容,支撑更大的访问量。
-
支持 B/S 及 C/S 模式。
另外,HTTP 协议已经不仅仅使用在浏览器上。在前后端分离的架构中,又或者微服务架构的内部通信中,HTTP 因为其数据格式的通用性,和语言无关,被大规模使用。
HTTP 基本格式
? HTTP 请求格式
-
请求行:用来说明请求类型,要访问的资源以及所使用的 HTTP 版本。
-
请求头部:紧接着请求行(即第一行)之后的部分,用来说明服务器要使用的附加信息从第二行起为请求头部。
-
HOST ,将指出请求的目的地。
-
User-Agent ,服务器端和客户端脚本都能访问它,它是浏览器类型检测逻辑的重要基础。该信息由你的浏览器来定义,并且在每个请求中自动发送等等
-
-
空行:请求头部后面的空行是必须的。
-
请求数据:也叫主体,可以添加任意的其他数据。
HTTP 响应格式
-
状态行:由 HTTP 协议版本号、状态码、状态消息三部分组成。
-
消息报头:用来说明客户端要使用的一些附加信息。
-
空行:消息报头后面的空行是必须的。
-
响应正文:服务器返回给客户端的文本信息。
URI 和 URL 的区别
1. URI
Web上可用的每种资源如HTML文档、图像、视频片段、程序等都是一个来URI来定位的; URI一般由三部组成:
①访问资源的命名机制 ②存放资源的主机名 ③资源自身的名称,由路径表示,着重强调于资源。
2. URL
URL是Internet上用来描述信息资源的字符串,主要用在各种WWW客户程序和服务器程序上,特别是著名的Mosaic。 采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。 URL一般由三部组成
①协议(或称为服务方式) ②存有该资源的主机IP地址(有时也包括端口号) ③主机资源的具体地址。如目录和文件名等
见 《URI 和 URL 的区别》 文章。
HTTP 协议请求方法
-
GET: 对服务器资源的简单请求。
-
POST: 用于发送包含用户提交数据的请求。
-
HEAD:类似于 GET 请求,不过返回的响应中没有具体内容,用于获取报头。
-
PUT:传说中请求文档的一个版本。
-
DELETE:发出一个删除指定文档的请求。
-
TRACE:发送一个请求副本,以跟踪其处理进程。
-
OPTIONS:返回所有可用的方法,检查服务器支持哪些方法。
-
CONNECT:用于 SSL 隧道的基于代理的请求。
GET 和 POST 的区别
请求方式 | 数据位置 | 明文密文 | 数据安全 | 长度限制 | 应用场景 |
---|---|---|---|---|---|
GET | HTTP 请求的 path 中 | 明文 | 不安全 | 长度较小,一般 2k | 查询数据 |
POST | HTTP 请求 body 中 | 可明可密 | 安全 | 支持较大数据传输 | 修改数据 |
-
GET在浏览器回退时是无害的,而POST会再次提交请求。
-
GET产生的URL地址可以被添加到书签,而POST不可以。
-
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
-
GET请求只能进行url编码,而POST支持多种编码方式。
-
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
-
GET请求在URL中传送的参数是有长度限制的,而POST没有。
-
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
-
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
-
GET参数通过URL传递,POST放在Request body中。
-
GET 请求可被缓存;POST 请求不会被缓存。
-
GET 请求可被收藏为书签;POST 不能被收藏为书签。
-
参见 《99%的人理解错 HTTP 中 GET 与 POST 的区别》
-
对于 GET 方式的请求,浏览器会把 HTTP header 和 data 一并发送出去,服务器响应 200(返回数据)。
-
而对于 POST,浏览器先发送 header ,服务器响应 100 continue ,浏览器再发送 data ,服务器响应 200 ok(返回数据)。
-
本质上来说:get和post本质上都是基于TCP/IP的HTTP协议的请求方式,也就是说这两者本质上TCP连接。此外,要注意:GET产生一个TCP数据包;POST产生两个TCP数据包。
也就是说,GET 只需要汽车跑一趟就把货送到了,而 POST得跑两趟,第一趟,先去和服务器打个招呼“嗨,我等下要送一批货来,你们打开门迎接我”,然后再回头把货送过去。
ps:不过要注意,POST 具体发几次,也和浏览器的实现有关系。例如:Firefox 只发一次。 ps2:据研究,在网络环境好的情况下,发一次包的时间和发两次包的时间差别基本可以无视。而在网络环境差的情况下,两次包的 TCP 在验证数据包完整性上,有非常大的优点。
-
HTTP相关状态码
-
1×× : 请求处理中,请求已被接受,正在处理
-
2×× : 请求成功,请求被成功处理
-
200 OK // 客户端请求成功
-
-
3×× : 重定向,要完成请求必须进行进一步处理
-
301 Moved Permanently // 永久重定向,使用域名跳转
-
302 Found // 临时重定向,未登陆的用户访问用户中心重定向到登录页面
-
-
4×× : 客户端错误,请求不合法
-
400 Bad Request // 客户端请求有语法错误,不能被服务器所理解
-
401 Unauthorized // 请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用
-
403 Forbidden // 服务器收到请求,但是拒绝提供服务
-
404 Not Found // 请求资源不存在,eg:输入了错误的 URL
-
-
5×× : 服务器端错误,服务器不能处理合法请求
完整的状态码列表,可以看看 《HTTP 状态码》 文章。
forward 和 redirect 的区别
forward(转发):
是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器。浏览器根本不知道服务器发送的内容从哪里来的,因为这个跳转过程实在服务器实现的,并不是在客户端实现的所以客户端并不知道这个跳转动作,所以它的地址栏还是原来的地址.
redirect(重定向):
是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.
转发是服务器行为,重定向是客户端行为。
区别
-
从地址栏显示来说 forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址.
redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.
-
从数据共享来说 forward:转发页面和转发到的页面可以共享request里面的数据. redirect:不能共享数据.
-
从运用地方来说 forward:一般用于用户登陆的时候,根据角色转发到相应的模块. redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等
-
从效率来说 forward:高. redirect:低.
本质区别:
转发过程:
客户浏览器发送http请求----》web服务器接受此请求--》调用内部的一个方法在容器内部完成请求处理和转发动作----》将目标资源发送给客户;在这里,转发的路径必须是同一个web容器下的url,其不能转向到其他的web路径上去,中间传递的是自己的容器内的request。在客户浏览器路径栏显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。转发行为是浏览器只做了一次访问请求。
重定向过程:
客户浏览器发送http请求----》web服务器接受后发送302状态码响应及对应新的location给客户浏览器--》客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location地址----》服务器根据此请求寻找资源并发送给客户。在这里 location可以重定向到任意URL,既然是浏览器重新发出了请求,则就没有什么request传递的概念了。在客户浏览器路径栏显示的是其重定向的路径,客户可以观察到地址的变化的。重定向行为是浏览器做了至少两次的访问请求的。
重定向,其实是两次request: 第一次,客户端request A,服务器响应,并response回来,告诉浏览器,你应该去B。这个时候IE可以看到地址变了,而且历史的回退按钮也亮了。重定向可以访问自己web应用以外的资源。在重定向的过程中,传输的信息会被丢失。
详细的,请看 《请求转发(Forward)和重定向(Redirect)的区别》 。
状态码301 与 302 的区别
301,302 都是 HTTP 状态的编码,都代表着某个 URL 发生了转移,不同之处在于:
-
301 redirect: 301 代表永久性转移(Permanently Moved)。
-
302 redirect: 302 代表暂时性转移(Temporarily Moved)。
详细的,请看 《HTTP 返回码中 301 与 302 的区别》 文章。
HTTP、TCP、Socket 的关系
-
TCP/IP 代表传输控制协议/网际协议,指的是一系列协议族。
-
HTTP 本身就是一个协议,是从 Web 服务器传输超文本到本地浏览器的传送协议。
-
Socket 是 TCP/IP 网络的 API ,其实就是一个门面模式,它把复杂的 TCP/IP 协议族隐藏在 Socket 接口后面。对用户来说,一组简单的接口就是全部,让 Socket 去组织数据,以符合指定的协议。
综上所述:
-
需要 IP 协议来连接网络
-
TCP 是一种允许我们安全传输数据的机制,使用 TCP 协议来传输数据的 HTTP 是 Web 服务器和客户端使用的特殊协议。
-
HTTP 基于 TCP 协议,所以可以使用 Socket 去建立一个 TCP 连接。
Cookies 和 Session 的区别
-
Session 在服务器端,Cookie 在客户端(浏览器)。
Session 默认被存在在服务器的一个文件里(不是内存)。
-
Session 的运行依赖 sessionid ,而 sessionid 是存在 Cookie 中的,也就是说,如果浏览器禁用了 Cookie ,同时 session 也会失效。但是,可以通过其它方式实现,比如在 url 参数中传递 sessionid 。
-
Session 可以放在文件、数据库、或内存中都可以。
-
【关键】用户验证这种场合一般会用 Session 。
参照:https://blog.csdn.net/striveb/article/details/82469253#Session%E4%B8%8ECookie%E5%8C%BA%E5%88%AB
一次完整的 HTTP 请求所经历的步骤
这里的客户端,更多指的是浏览器。
-
1、DNS 解析(通过访问的域名找出其 IP 地址,递归搜索)。
如用客户端浏览器请求这个页面:http://localhost.com:8080/index.htm 从中分解出协议名、主机名、 端口、对象路径等部分,对于我们的这个地址,解析得到的结果如下:
协议名:http
主机名:localhost.com
端口:8080
对象路径:/index.htm
在这一步,需要域名系统 DNS 解析域名 localhost.com,得主机的 IP 地址。
-
2、HTTP 请求,当输入一个请求时,建立一个 Socket 连接发起 TCP的 3 次握手。
把以上部分结合本机自己的信息,封装成一个 HTTP 请求数据包。
如果是 HTTPS 请求,会略微有不同。
-
3、客户端发送请求
-
3.1 客户端向服务器发送请求命令(一般是 GET 或 POST 请求)。
客户端的网络层不用关心应用层或者传输层的东西,主要做的是通过查找路由表确定如何到达服务器,期间可能经过多个路由器,这些都是由路由器来完成的工作,无非就是通过查找路由表决定通过那个路径到达服务器。
客户端的链路层,包通过链路层发送到路由器,通过邻居协议查找给定 IP 地址的 MAC 地址,然后发送 ARP 请求查找目的地址,如果得到回应后就可以使用 ARP 的请求应答交换的 IP 数据包现在就可以传输了,然后发送 IP 数据包到达服务器的地址。
客户机发送请求命令:建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资源标识符(URL)、协议版本号,后边是 MIME 信息包括请求修饰符、客户机信息和可内容。
-
3.2客户端发送请求头信息和数据。
-
-
4.1、服务器发送应答头信息。
服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是 MIME 信息包括服务器信息、实体信息和可能的内容。
-
4.2、服务器向客户端发送数据。
-
5、服务器关闭 TCP 连接(4次挥手)。
这里是否关闭 TCP 连接,也根据 HTTP Keep-Alive 机制有关。同时,客户端也可以主动发起关闭 TCP 连接。
如果浏览器或者服务器在其头信息加入了这行代码 Connection:keep-alive,TCP 连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。
-
6、客户端根据返回的 HTML、CSS、JS 进行渲染。
如下是《图解HTTP》提供的图片:
HTTP1.0 和 HTTP1.1的区别
主要是如下 8 点:
-
1、可扩展性
-
2、缓存
-
3、带宽优化
带来了分块传输
HTTP/1.1中在请求消息中引入了range头域,它允许只请求资源的某个部分。在响应消息中Content-Range头域声明了返回的这部分对象的偏移值和长度。如果服务器相应地返回了对象所请求范围的内容,则响应码为206(Partial Content),它可以防止Cache将响应误以为是完整的一个对象。
HTTP/1.1加入了一个新的状态码100(Continue)。客户端事先发送一个只带头域的请求,如果服务器因为权限拒绝了请求,就回送响应码401(Unauthorized);如果服务器接收此请求就回送响应码100,客户端就可以继续发送带实体的完整请求了。注意,HTTP/1.0的客户端不支持100响应码。但可以让客户端在请求消息中加入Expect头域,并将它的值设置为100-continue。
-
4、长连接
HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟。例如:一个包含有许多图像的网页文件的多个请求和应答可以在一个连接中传输,但每个单独的网页文件的请求和应答仍然需要使用各自的连接。
HTTP 1.1还允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能够区分出每次请求的响应内容,这样也显著地减少了整个下载过程所需要的时间。
在HTTP/1.0中,要建立长连接,可以在请求消息中包含Connection: Keep-Alive头域,如果服务器愿意维持这条连接,在响应消息中也会包含一个Connection: Keep-Alive的头域。同时,可以加入一些指令描述该长连接的属性,如max,timeout等。
-
5、消息传递
-
6、Host 头域
-
7、错误提示
-
8、内容协商
详细的每一点的说明,可以看 《HTTP1.0 与 HTTP1.1 的区别》 文章,特别是第 4 点【长连接】。
HTTP1.1 支持长连接(PersistentConnection)和请求的流水线(Pipelining)。
长连接(PersistentConnection):处理在一个 TCP 连接上可以传送多个 HTTP 请求和响应,减少了建立和关闭连接的消耗和延迟。在 HTTP1.1中 默认开启
Connection:keep-alive
,一定程度上弥补了 HTTP1.0 每次请求都要创建连接的缺点。请求的流水线(Pipelining):HTTP1.1 还允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能够区分出每次请求的响应内容,这样也显著地减少了整个下载过程所需要的时间。
推荐,在看看 《HTTP Keep-Alive 是什么?如何工作?》 文章。
关于这一点,可能演变的问题有:
HTTP 的长连接是什么意思?
HTTP Keep-Alive 机制是什么?
HTTP Keep-Alive 机制和 TCP Keep-Alive 有什么区别?
SPDY 是什么?
HTTP Working-Group 最终决定以 SPDY/2 为基础,开发 HTTP/2 。
2012 年,Google 如一声惊雷提出了 SPDY 的方案,优化了 HTTP1.X 的请求延迟,解决了 HTTP1.X 的安全性,具体如下:
-
1、降低延迟
针对 HTTP 高延迟的问题,SPDY 优雅的采取了多路复用(multiplexing)。多路复用通过多个请求 Stream 共享一个 Tcp连 接的方式,解决了 HOL blocking 的问题,降低了延迟同时提高了带宽的利用率。
-
2、请求优先级(request prioritization)
多路复用带来一个新的问题是,在连接共享的基础之上有可能会导致关键请求被阻塞。SPDY 允许给每个 request 设置优先级,这样重要的请求就会优先得到响应。
比如浏览器加载首页,首页的 html 内容应该优先展示,之后才是各种静态资源文件,脚本文件等加载,这样可以保证用户能第一时间看到网页内容。
-
3、header 压缩
前面提到 HTTP1.x 的 header 很多时候都是重复多余的。选择合适的压缩算法可以减小包的大小和数量。
-
4、基于 HTTPS 的加密协议传输
大大提高了传输数据的安全性。
-
5、服务端推送(server push)
采用了 SPDY 的网页,例如我的网页有一个
sytle.css
的请求,在客户端收到sytle.css
数据的同时,服务端会将sytle.js
的文件推送给客户端。当客户端再次尝试获取sytle.js
时就可以直接从缓存中获取到,不用再发请求了。和我们理解的服务端推送,有点(非常)不一样哈。
SPDY 构成图如下:
-
SPDY 位于 HTTP 之下,TCP 和 SSL 之上,这样可以轻松兼容老版本的 HTTP 协议(将 HTTP1.x 的内容封装成一种新的 frame 格式),同时可以使用已有的 SSL 功能。
二、HTTPS
简述
HTTPS ,实际就是在 TCP 层与 HTTP 层之间加入了 SSL/TLS 来为上层的安全保驾护航,主要用到对称加密、非对称加密、证书,等技术进行客户端与服务器的数据加密传输,最终达到保证整个通信的安全性。
一句话概括:HTTP + 加密 + 认证 + 完整性保护 = HTTPS 。
SSL和TLS
官方定义,SSL 是安全套接层(secure sockets layer);TLS 是 SSL 的继任者,叫传输层安全(transport layer security)。
它们存在的唯一目的就是保证上层通讯安全的一套机制。它的发展依次经历了下面几个时期,像手机软件升级一样,每次更新都添加或去除功能,比如引进新的加密算法,修改握手方式等。
-
SSL1.0: 已废除
-
SSL2.0: RFC6176 ,已废除
-
SSL3.0: RFC6101 ,基本废除
-
TLS1.0: RFC2246 ,目前大都采用此种方式
-
TLS1.1: RFC4346
-
TLS1.2: RFC5246 ,没有广泛使用
-
TLS1.3: IETF 正在酝酿中
为了下面描述方便,统一先叫 SSL 。
SSL/TLS 协议作用
-
认证用户和服务器,确保数据发送到正确的客户机和服务器。
客户端必须避免中间人攻击,即除了真正的服务器,任何第三方都无法冒充服务器。
-
加密数据以防止数据中途被窃取。
-
维护数据的完整性,确保数据在传输过程中不被改变。
HTTPS实现的过程
1.建立连接获取证书
SSL 客户端通过 TCP 和服务器建立连接之后(443 端口),并且在一般的 tcp 连接协商(握 手)过程中请求证书。即客户端发出一个消息给服务器,这个消息里面包含了自己可实现的算法列表和其它一些需要的消息,SSL 的服务器端会回应一个数据包,这里面确定了这次通信所需要的算法,然后服务器向客户端返回证书。(证书里面包含了服务器信息:域名,申请证书 的公司,公共秘钥)。
2.证书验证
Client 在收到服务器返回的证书后,判断签发这个证书的公共签发机构,并使用这个机构的公 共秘钥确认签名是否有效,客户端还会确保证书中列出的域名就是它正在连接的域名。
3.数据加密和传输
如果确认证书有效,那么生成对称秘钥并使用服务器的公共秘钥进行加密。然后发送给服务器,服务器使用它的私钥对它进行解密,这样两台计算机可以开始进行对称加密进行通信。
HTTP 和 HTTPS 的区别
-
端口不同:HTTP 与 HTTPS 使用不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
-
资源消耗:和 HTTP 通信相比,HTTPS 通信会由于加解密处理消耗更多的 CPU 和内存资源。
-
开销:HTTPS 通信需要证书,而证书一般需要向认证机构申请免费或者付费购买。
HTTPS 可以有效的防止运营商劫持,解决了防劫持的一个大问题。
SSL 加密方式
对称密钥加密,是指加密和解密使用同一个密钥的方式,这种方式存在的最大问题就是密钥发送问题,即如何安全地将密钥发给对方。
非对称加密,指使用一对非对称密钥,即公钥和私钥,公钥可以随意发布,但私钥只有自己知道。发送密文的一方使用对方的公钥进行加密处理,对方接收到加密信息后,使用自己的私钥进行解密。
SSL 协议,即用到了对称加密也用到了非对称加密,如下图所示:
-
在建立传输链路时,SSL 首先对对称加密的密钥使用公钥进行非对称加密。
注意,这里 Server 返回给 Client 的不是公钥(
server.pub
),而是server.crt
。Client 需要使用ca.key
从server.crt
中解密出公钥(server.pub
) 。 -
链路建立好之后,SSL 对传输内容使用公钥(
server.pub
)对称加密。
公钥传输的步骤
1.对公钥加密
每一个使用 HTTPS 的服务器都必须去专门的证书机构注册一个证书,证书中存储了用权威机构私钥加密的公钥。这样客户端用权威机构的公钥解密就可以了。
现在 HTTPS 协议的握手阶段变成了四步:
-
客户端: 你好,我要发起一个 HTTPS 请求,请给我公钥
-
服务器: 好的,这是我的证书,里面有加密后的公钥
-
客户端: 解密成功以后告诉服务器: 这是我的 (用公钥加密后的) 对称秘钥。
-
服务器: 好的,我知道你的秘钥了,后续就用它传输。
2.权威机构的公钥的传输
可以存在电脑里,这个公钥不用传输,会直接内置在各大操作系统(或者浏览器)的出厂设置里。之所以不把每个服务器的公钥内置在电脑里,一方面是因为服务器太多,存不过来。另一方面操作系统也不信任你,凭什么你说你这个就是百度/淘宝的证书呢?
所以各个公司要先去权威机构认证,申请证书,然后操作系统只会存储权威机构的公钥。因为权威机构数量有限,所以操作系统厂商相对来说容易管理。如果这个权威机构不够权威,乱发证书,就会取消他的资格,比如可怜的沃通。
3. 将信息 hash 值随着信息一起传递
哈希算法的特点是它可以压缩数据,如果从函数角度来看,不管多复杂的数据(定义域可以非常大)经过哈希算法都会得到一个值,而且这个值处在某个特定(远小于定义域的范围)值域内。相同数据的哈希结果一定相同,不相同数据的哈希结果一般不同,不过也有小概率会重复,这叫哈希冲突。
为了确保原始证书没有被篡改,我们可以在传递证书的同时传递证书的哈希值。由于第三者无法解析数据,只能乱改,那么修改后的数据在解密后,就不可能通过哈希。
比如说公钥就是之前的例子
Hello
,我们假设哈希算法是获取字符串的最后一个字符,那么Hello
的哈希值就是o
,所以加密字符串是Ifmmpp
。虽然公钥已知,每个人都可以解密,解密完也可以篡改,但是因为没有私钥, 所以无法正确的加密。所以它再返回给客户端的数据是无效数据,用公钥解析后会得到乱码。即使攻击者通过多次尝试碰巧能够解析,也无法通过哈希校验。
4.可以防止第三方冒充服务器
首先真正的服务器下发的内容,无法被别人篡改。他们有权威机构的公钥,所以可以解密,但是因为没有私钥,所以解密以后的信息无法加密。没有加密或者错误加密的信息被客户端用公钥解密以后,必然无法通过哈希校验。
但是,如果你一开始请求的就不是真的服务器,而是一个攻击者,此时的他完全有机会进行中间人攻击。我们知道第一次握手的时候服务器会下发用于证明自己身份的证书,这个证书会用预设在设备上的公钥来解密。所以要么是经过认证的证书用权威机构的私钥加密,再用权威机构解密,要么是用非权威机构的私钥加密,然后找不到公钥解密。
所以如果不小心安装过非权威机构的根证书,比如黑客提供的恶意证书,这时候设备上就多了一个预设的公钥,那么用恶意私钥加密的证书就能被正常解析出来。所以千万不要随便装根证书,这等于是为那些恶意证书留了一扇门。
当然,凡是都有两面性。我们知道 Charles 可以调试 HTTPS 通信,它的原理就是需要用户安装 Charles 的根证书,然后我们的请求会被代理到 Charles 服务器,它下发的 Charles 证书才能被正确解析。另一方面,Charles 会作为客户端,从真正的服务器哪里拿到正确的 https 证书并用于后续通信。幸好 Charles 不是流氓软件,或者它的私钥一旦泄露,对用户都会造成很大的影响。
也就是说,通过 CA 来保证。至于 server.crt
证书是怎么申请的呢?请看 《SSL/TLS 双向认证(一) – SSL/TLS工作原理》 文章的 「CA 的证书 ca.crt 和 SSL Server 的证书 server.crt 是什么关系呢? 」 问题的解答。
单向认证、双向认证
-
单向认证,指的是只有一个对象校验对端的证书合法性。
通常都是 Client 来校验服务器的合法性。那么 Client 需要一个
ca.crt
,服务器需要server.crt
和server.key
。 -
双向认证,指的是相互校验,Server 需要校验每个 Client ,Client 也需要校验服务器。
-
Server 需要
server.key
、server.crt
、ca.crt
。 -
Client 需要
client.key
、client.crt
、ca.crt
。
-
1)单向认证的过程
-
1、客户端向服务端发送 SSL 协议版本号、加密算法种类、随机数等信息。
-
2、服务端给客户端返回 SSL 协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书。
-
3、客户端使用服务端返回的信息验证服务器的合法性,包括:
-
证书是否过期。
-
发行服务器证书的 CA 是否可靠。
-
返回的公钥是否能正确解开返回证书中的数字签名。
-
服务器证书上的域名是否和服务器的实际域名相匹配
验证通过后,将继续进行通信;否则,终止通信。
4、客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择。
5、服务器端在客户端提供的加密方案中选择加密程度最高的加密方式。
-
-
6、服务器将选择好的加密方案通过明文方式返回给客户端。
-
7、客户端接收到服务端返回的加密方式后,使用该加密方式生成产生随机码,用作通信过程中对称加密的密钥,使用服务端返回的公钥进行加密,将加密后的随机码发送至服务器。
-
8、服务器收到客户端返回的加密信息后,使用自己的私钥进行解密,获取对称加密密钥。
在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全。
2)双向认证的过程
双向认证和单向认证原理基本差不多,只是除了客户端需要认证服务端以外,增加了服务端对客户端的认证,具体过程如下:
-
1、客户端向服务端发送 SSL 协议版本号、加密算法种类、随机数等信息。
-
2、服务端给客户端返回 SSL 协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书。
-
3、客户端使用服务端返回的信息验证服务器的合法性,包括:
-
证书是否过期。
-
发型服务器证书的 CA 是否可靠。
-
返回的公钥是否能正确解开返回证书中的数字签名。
-
服务器证书上的域名是否和服务器的实际域名相匹配
验证通过后,将继续进行通信;否则,终止通信。
-
【新增】4、服务端要求客户端发送客户端的证书,客户端会将自己的证书发送至服务端。
-
【新增】5、验证客户端的证书,通过验证后,会获得客户端的公钥。
-
6、客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择。
-
7、服务器端在客户端提供的加密方案中选择加密程度最高的加密方式。
-
-
8、服务器将选择好的加密方案通过明文方式返回给客户端。
-
9、客户端接收到服务端返回的加密方式后,使用该加密方式生成产生随机码,用作通信过程中对称加密的密钥,使用服务端返回的公钥进行加密,将加密后的随机码发送至服务器。
-
10、服务器收到客户端返回的加密信息后,使用自己的私钥进行解密,获取对称加密密钥。
在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全。
如何选择单向认证还是双向认证
-
一般一个站点很多用户访问就用单向认证。
-
企业接口对接就用双向认证。
如果想要提高 APP 的安全级别,也可以考虑双向认证。因为,APP 天然方便放入客户端证书,从而提高安全级别。
为什么抓包工具还能抓到 HTTPS 数据包并解密成功呢
不是说HTTPS在网络中传输的是密文吗?这个问题就是中间者攻击(man in zhe middle)。
-
解决办法,就是 HTTPS 单向验证。在客户端中内置服务器公钥,在第三步服务器返回的公钥,除了验证公钥的有效性之外,再比对公钥是不是和内置的公钥一样,不一样说明被中间者攻击了,就断开链接不在请求了。
-
这个原理的前提是服务器的私钥没有泄露,客户端的代码不会被破解,道高一尺魔高一丈。信息安全就是在合理的范围内,选择比较合适的加密方法,没有绝对论,只有相对论。在某个范围内比较安全。
HTTPS 握手对性能的影响
TCP 有三次握手,再加上 HTTPS 的四次握手,影响肯定有,但是可以接受。
-
首先,HTTPS 肯定会更慢一点,时间主要花费在两组 SSL 之间的耗时和证书的读取验证上,对称算法的加解密时间几乎可以忽略不计。
-
而且如果不是首次握手,后续的请求并不需要完整的握手过程。客户端可以把上次的加密情况直接发送给服务器从而快速恢复,具体细节可以参考 《图解 SSL/TLS 协议》 。
-
除此以外,SSL 握手的时间并不是只能用来传递加密信息,还可以承担起客户端和服务器沟通 HTTP2 兼容情况的任务。因此从 HTTPS 切换到 HTTP2.0 不会有任何性能上的开销,反倒是得益于 HTTP2.0 的多路复用等技术,后续可以节约大量时间。
-
如果把 HTTPS2.0 当做目标,那么 HTTPS 的性能损耗就更小了,远远比不上它带来的安全性提升。
八、HTTP2
HTTP2.0简述
HTTP2.0 ,可以说是SPDY的升级版(其实原本也是基于SPDY设计的),但是,HTTP2.0 跟 SPDY 仍有不同的地方,如下:
HTTP2.0 和 HTTP1.X 相比的新特性
-
1、新的二进制格式(Binary Format)
HTTP1.x 的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认 0 和 1 的组合。基于这种考虑 HTTP2.0 的协议解析决定采用二进制格式,实现方便且健壮。
-
同 SPDY 对 HTTP1.1 的改进。
-
2、降低延迟
-
3、多路复用(MultiPlexing)
-
4、header 压缩
-
5、服务端推送(server push)
-
总的区别可以理解为:
-
HTTP/2采用二进制格式而非文本格式
-
HTTP/2是完全多路复用的,而非有序并阻塞的——只需一个连接即可实现并行
-
使用报头压缩,HTTP/2降低了开销
-
HTTP/2让服务器可以将响应主动“推送”到客户端缓存中
Nginx 怎么做 HTTP2.0 的升级改造?
-
1、虽然 HTTP2.0 其实可以支持非 HTTPS 的,但是现在主流的浏览器像 Chrome,Firefox 表示还是只支持基于 TLS 部署的 HTTP2.0协议,所以要想升级成 HTTP2.0 还是先升级 HTTPS 为好。
-
2、当你的网站已经升级 HTTPS 之后,那么升级 HTTP2.0 就简单很多,如果你使用 NGINX ,只要在配置文件中启动相应的协议就可以了,可以参考 NGINX白皮书,NGINX配置HTTP2.0官方指南 。
-
3、使用了 HTTP2.0 那么,原本的 HTTP1.x 怎么办?这个问题其实不用担心,HTTP2.0 完全兼容 HTTP1.x 的语义,对于不支持 HTTP2.0 的浏览器,NGINX 会自动向下兼容的。
在我们内部的微服务 API 接口,也可以做 HTTP2 的改造,可以参考如下文章:
HTTP2.0 的多路复用和 HTTP1.X 中的长连接复用区别
-
HTTP/1.0:一次请求-响应,建立一个连接,用完关闭;每一个请求都要建立一个连接。
-
HTTP/1.1:Pipeling(流水线) 解决方式为,若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会。一旦有某请求超时等,后续请求只能被阻塞,毫无办法,也就是人们常说的线头阻塞。
-
HTTP/2:多个请求可同时在一个连接上并行执行。某个请求任务耗时严重,不会影响到其它连接的正常执行。
如下图所示:
HTTP2.0 多路复用优点
HTTP 性能优化的关键并不在于高带宽,而是低延迟。TCP 连接会随着时间进行自我「调谐」,起初会限制连接的最大速度,如果数据成功传输,会随着时间的推移提高传输的速度。这种调谐则被称为 TCP 慢启动。由于这种原因,让原本就具有突发性和短时性的 HTTP 连接变的十分低效。
HTTP/2 通过让所有数据流共用同一个连接,可以更有效地使用 TCP 连接,让高带宽也能真正的服务于 HTTP 的性能提升。
服务器推送
服务端推送能把客户端所需要的资源伴随着 index.html
一起发送到客户端,省去了客户端重复请求的步骤。正因为没有发起请求,建立连接等操作,所以静态资源通过服务端推送的方式可以极大地提升速度。具体如下:
-
普通的客户端请求过程:
-
服务端推送的过程:
为什么需要头部(header)压缩?
假定一个页面有 100 个资源需要加载(这个数量对于今天的 Web 而言还是挺保守的),而每一次请求都有 1kb 的消息头(这同样也并不少见,因为 Cookie 和引用等东西的存在),则至少需要多消耗 100kb 来获取这些消息头。HTTP2.0 可以维护一个字典,差量更新 HTTP 头部,大大降低因头部传输产生的流量。
具体参考:《HTTP/2 头部压缩技术介绍》 文章。
-
维护一份相同的静态字典(Static Table),包含常见的头部名称,以及特别常见的头部名称与值的组合。
-
维护一份相同的动态字典(Dynamic Table),可以动态地添加内容。
-
支持基于静态哈夫曼码表的哈夫曼编码(Huffman Coding)。
参考与推荐如下文章: