HTTP

 

在开始Android并发系列文章之前先插入一些文章,后续Android并发系列文章会按照计划发布。本篇文章是来说说HTTP那些事。

HTTP简介

Web 使用一种名为 HTTP ( HyperText Transfer Protocol ,超文本传输协议的协议作为规范,完成从客户端到服务器端等一系列运作流程。本文探讨的是HTTP/1.1版本。这仍然是大多数网站采用的HTTP协议
我们先看一下下面这张广为流传的图。
网路传输的4层结构

那些与HTTP协议密切相关的协议

IP

IP 协议的作用是把各种数据包传送给对方。而要保证确实传送到对方那里,则需要满足各类条件。其中两个重要的条件是 IP 地址和 MAC地址( Media Access Control Address )。IP 地址指明了节点被分配到的地址, MAC 地址是指网卡所属的固定地址。 IP 地址可以和 MAC 地址进行配对。 IP 地址可变换,但 MAC地址基本上不会更改。IP使用 ARP 协议凭借 MAC 地址进行通信

TCP(确保可靠性的协议)

按层次分, TCP 位于传输层,提供可靠的字节流服务。所谓的字节流服务( Byte Stream Service )是指,为了方便传输,将大块数据分割成以报文段( segment )为单位的数据包进行管理。而可靠的传输服务是指,能够把数据准确可靠地传给对方。

TCP连接的3次握手

为了准确无误地将数据送达目标处, TCP 协议采用了三次握手( three-way handshaking )策略。
握手过程中使用了 TCP 的标志( flag ) —— SYN ( synchronize ) 和ACK ( acknowledgement )。发送端首先发送个带 SYN 标志的数据包给对方。接收端收到后,回传一个带有 SYN/ACK 标志的数据包以示传达确认信息。最后,发送端再回传一个带 ACK 标志的数据包,代表 “ 握手 ” 结束。若在握手过程中某个阶段莫名中断, TCP 协议会再次以相同的顺序发送相同的数据包。

整个过程如下图所示
3次握手

为什么需要3次握手

为什么需要3次握手,如果面试中问到了TCP相关知识,那么这个问题也几乎是必问的,为什么是3次,而不是1次,2次或者4次,5次??

首先我们知道不管是客户端或者服务端发送数据都会消耗网络流量,还会造成许多不必要的通信开销,浪费资源,所以我们在保证TCP可靠性的前提下所经历的通信次数自然越少越好。

TCP的可靠性含义我们上面已经说了,那我们就从3次握手分析,如果只有1次握手,客户端只向服务端发送数据,那么就谈不上可靠性了,因为服务端都没有回复,那么我们来看只有2次握手行不行,如果只有2次握手,客户端只向服务端发送数据,服务器也向客户端回复我收到数据了,但是考虑此时如果发送数据的过程中数据丢失了,服务端认为连接建立了(数据我已经发出去了),可是客户端没有收到数据,客户端认为连接没有建立,就会重复请求,而这对与服务端来说就又是一个全新的连接。一言以蔽之:第三次握手是为了防止:如果客户端迟迟没有收到服务器返回确认报文,这时会放弃连接,重新启动一条连接请求,但问题是:服务器不知道客户端没有收到,所以他会收到两个连接,浪费连接开销。如果每次都是这样,就会浪费多个连接开销。

HTTP详解

HTTP的报文结构

用于 HTTP 协议交互的信息被称为 HTTP 报文。请求端(客户端)的HTTP 报文叫做请求报文,响应端(服务器端)的叫做响应报文。HTTP 报文本身是由多行(用 CR+LF 作换行符)数据构成的字符串文本。HTTP 报文大致可分为报文首部和报文主体两块。两者由最初出现的空行( CR+LF )来划分。通常,并不一定要有报文主体。

HTTP的报文结构

HTTP的请求以及响应报文结构

HTTP的请求以及响应报文结构

HTTP的报文头部

下面的是请求某网站时,请求报文以及响应报文的首部信息。

请求报文首部

Host: hackr.jp
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: keep-alive Upgrade-Insecure-Requests: 1

响应报文首部

HTTP/1.1 200 OK
Date: Thu, 23 Aug 2018 08:17:43 GMT
Server: Apache
Last-Modified: Tue, 08 Jan 2013 08:53:29 GMT
ETag: "25e-4d2c3145df440-gzip" Accept-Ranges: bytes Vary: Accept-Encoding,User-Agent Content-Encoding: gzip Content-Length: 379 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/html

由上可知HTTP 首部字段是由首部字段名和字段值构成的,中间用冒号 “:” 分隔。

HTTP的报文头部类型

HTTP 首部字段根据实际用途被分为以下 4 种类型。

通用首部字段( General Header Fields )请求报文和响应报文两方都会使用的首部。
| 首部字段名 | 说明
| ------------- |:-------------:
| Cache-Control|控制缓存的行为
| Connection|逐跳首部、连接的管理
| Date|创建报文的日期时间
| Pragma|报文指令
| Trailer|报文末端的首部一览
| Transfer-Encoding|指定报文主体的传输编码方式
| Upgrade|升级为其他协议
| Via|代理服务器的相关信息
| Warning|错误通知

请求首部字段( Request Header Fields )从客户端向服务器端发送请求报文时使用的首部。补充了请求的附加内容、客户端信息、响应内容相关优先级等信息。
| 首部字段名 | 说明
| ------------- |:-------------:
| Accept| 用户代理可处理的媒体类型
| Accept-Charset| 优先的字符集
| Accept-Encoding| 优先的内容编码
| Accept-Language| 优先的语言(自然语言)
| Authorization| Web 认证信息
| Expect| 期待服务器的特定行为
| From| 用户的电子邮箱地址
| Host| 请求资源所在服务器
| If-Match| 比较实体标记( ETag )
| If-Modified-Since| 比较资源的更新时间
| If-None-Match| 比较实体标记(与 If-Match 相反)
| If-Range| 资源未更新时发送实体 Byte 的范围请求
| If-Unmodified-Since| 比较资源的更新时间(与 If-Modified-Since 相反)
| Max-Forwards| 最大传输逐跳数
| Proxy-Authorization| 代理服务器要求客户端的认证信息
| Range| 实体的字节范围请求
| Referer| 对请求中 URI 的原始获取方
| TE| 传输编码的优先级
| User-Agent| HTTP 客户端程序的信息

响应首部字段( Response Header Fields )从服务器端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会要求客户端附加额外的内容信息。
| 首部字段名 | 说明
| ------------- |:-------------:
| Accept-Ranges| 是否接受字节范围请求
| Age| 推算资源创建经过时间
| ETag| 资源的匹配信息
| Location| 令客户端重定向至指定 URI
| Proxy-Authenticate| 代理服务器对客户端的认证信息
| Retry-After| 对再次发起请求的时机要求
| Server| HTTP 服务器的安装信息
| Vary| 代理服务器缓存的管理信息
| WWW-Authenticate| 服务器对客户端的认证信息

实体首部字段( Entity Header Fields )针对请求报文和响应报文的实体部分使用的首部。补充了资源内容更新时间等与实体有关的信息。
| 首部字段名 | 说明
| ------------- |:-------------:
| Allow| 资源可支持的 HTTP 方法
| Content-Encoding| 实体主体适用的编码方式
| Content-Language| 实体主体的自然语言
| Content-Length| 实体主体的大小(单位:字节)
| Content-Location| 替代对应资源的 URI
| Content-MD5| 实体主体的报文摘要
| Content-Range| 实体主体的位置范围
| Content-Type| 实体主体的媒体类型
| Expires| 实体主体过期的日期时间
| Last-Modified| 资源的最后修改日期时间

HTTP 首部字段将定义成缓存代理和非缓存代理的行为,分成 2 种类型
  1. 端到端首部( End-to-end Header )
    分在此类别中的首部会转发给请求 / 响应对应的最终接收目标,且必须保存在由缓存生成的响应中,另外规定它必须被转发。
  2. 逐跳首部( Hop-by-hop Header )
    分在此类别中的首部只对单次转发有效,会因通过缓存或代理而不再转发。 HTTP/1.1 和之后版本中,如果要使用 hop-by-hop 首部,需提供 Connection 首部字段。

下面列举了 HTTP/1.1 中的逐跳首部字段。除这 8 个首部字段之外,其他所有字段都属于端到端首部

  • Connection
  • Keep-Alive
  • Proxy-Authenticate
  • Proxy-Authorization
  • Trailer
  • TE
  • Transfer-Encoding
  • Upgrade

关于各个首部命令的详细参数可参见HTTP Headers

HTTP进阶

如果这篇文章到上面为止,那跟手册貌似没有什么区别,之前听到过一位大神说的话,掌握一门技术,不仅需要知道这门技术能做到什么,也要知道它不能做到什么,在掌握一门技术的边界之后,便对一门技术游刃有余了,毕竟技术那么多,推陈换代那么快,对于大多数人来说没有精力貌似也不是十分必要去记忆技术的每一个细节(即使记忆了,有许多细节是我们平常用不到的,也就渐渐遗忘了)。在我们掌握边界以后,遇到问题时,我们知道这个问题能依靠该项技术解决,至于怎么解决,那时我们在去查相应手册即可。

那对于本篇的HTTP来说,我们就从以下两方面进行分析

HTTP能做到什么

我们下面结合实际工作中的所遇到的HTTP的应用场景分为两大方面

访问大数据(图片,视频,大文件)时

在访问这些大数据时,我们往往会遇到以下问题
1. 如何请求部分数据?
2. 假设已请求了某资源的部分数据,程序终止了,服务器更新了该资源,客户端如何做,即已缓存的数据是否可信?

我们通常在做下载功能的时候往往需要断点续传甚至多线程断点续传,那么上面的问题就肯定会遇到。下面我们一一解答
1.使用Range来请求某个资源的部分数据

Range: bytes=bytes=200-1000, 2000-6576, 19000- 表示请求获取从第 200 字节至第1000 ,2000-6576,19000之后所有字节的资源。 在一个 Range 首部中,可以一次性请求多个部分,服务器会以 multipart 文件的形式将其返回。 如果服务器返回的是范围响应,需要使用 206 Partial Content 状态码。 假如所请求的范围不合法,那么服务器会返回 416 Range Not Satisfiable 状态码,表示客户端错误。 

2.ETag以及If-Match If-None-Match If-Range

响应首部字段ETag 能告知客户端实体标识。它是一种可将资源以字符串形式做唯一性标识的方式。服务器会为每份资源分配对应的 ETag值。另外,当资源更新时, ETag 值也需要更新。生成 ETag 值时,并没有统一的算法规则,而仅仅是由服务器来分配。

ETag 中有强 ETag 值和弱 ETag 值之分。
强 ETag 值,不论实体发生多么细微的变化都会改变其值。

ETag: "1234"

弱 ETag 值,只用于提示资源是否相同。只有资源发生了根本改变,产生差异时才会改变 ETag 值。这时,会在字段值最开始处附加 W/

ETag: W/"1234"

请求首部字段If-Match If-None-Match If-Range
形如 If-xxx 这种样式的请求首部字段,都可称为条件请求。服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求。
If-Match ,它会告知服务器匹配资源所用的实体标记( ETag )值。这时的服务器无法使用弱 ETag 值。服务器会比对 比If-Match 的字段值和资源的 ETag 值,仅当两者一致时,才会执行请求。反之,则返回状态码 412 Precondition Failed 的响应。还可以使用星号( * )指定 If-Match 的字段值。针对这种情况,服务器将会忽略 ETag 的值,只要资源存在就处理请求。

If-None-Match 只有在 If-None-Match 的字段值与 ETag 值不一致时,可处理该请求。与 If-Match 首部字段的作用相反

If-Range 浏览器告诉 WEB 服务器,如果我请求的对象没有改变,就把我缺少的部分给我,如果对象改变了,就把整个对象给我。浏览器通过发送请求对象的ETag 或者自己所知道的最后修改时间给 WEB 服务器,让其判断对象是否改变了。总是跟 Range 头部一起使用。

使用形式如下

If-Range: Wed, 21 Oct 2015 07:28:00 GMT Range: bytes=bytes=200-1000 
If-Range: "1234"
Range: bytes=bytes=200-1000 

If-Range 头字段通常用于断点续传的下载过程中,用来自从上次中断后,确保下载的资源没有发生改变。

通常情况下的HTTP请求与响应

我们现在的服务器大多是符合RESTFUL规范的,作为客户端(网页、Android、IOS)来说,我们与服务器的通常交互是数据量比较小的操作,增删改查,传递以及解析显示JSON数据。这是我们通常使用HTTP的场景。这种场景下所常用的HTTP头部字段是包含上述访问大数据(图片,视频,大文件)时的请求字段的,这些首部字段各有含义,见HTTP Headers

HTTP不能做到什么(缺陷)

  • 一条连接上只可发送一个请求。
  • 请求只能从客户端开始。客户端不可以接收除响应以外的指令。
  • 请求 / 响应首部未经压缩就发送。首部信息越多延迟越大。
  • 发送冗长的首部。每次互相发送相同的首部造成的浪费较多。

备注:由于上述HTTP/1.1协议的缺陷,SPDY 和 WebSocket 等协议纷纷出现,还有HTTP/2.0版本,这些协议的出现在一定程度上弥补了HTTP/1.1协议的缺陷。感兴趣的同学可以深入了解。

 

 

 

HTTP1.1
HTTP协议是用于从WWW服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。HTTP HTTP协议通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS。默认HTTP的端口号为80,HTTPS的端口号为443。
HTTP协议永远都是客户端发起请求,服务器回送响应。这样就限制了使用HTTP协议,无法实现在客户端没有发起请求的时候,服务器将消息推送给客户端。HTTP协议是一个无状态的协议,同一个客户端的这次请求和上次请求是没有对应关系。

HTTP/1.0于1996年5月公布,该协议至今仍被广泛用在服务器端。
HTTP/1.1于1997年1月公布,是目前主流的HTTP协议版本。
HTTP/2.0正在制定中。

HTTP通信机制
HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤
1. 建立TCP连接 在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该连接是通过TCP来完成的,HTTP是比TCP更高层次的应用层协议,只有低层协议建立之后才能进行更高层协议的连接,因此首先要建立TCP连接。
2. Web浏览器向Web服务器发送请求命令 一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令。例如:GET/sample/hello.jsp HTTP/1.1。
3. Web浏览器发送请求头信息 浏览器发送其请求命令之后,还要以头信息的形式向Web服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。
4. Web服务器应答 客户机向服务器发出请求后,服务器会客户机回送应答, HTTP/1.1 200 OK ,应答的第一部分是协议的版本号和应答状态码。
5. Web服务器发送应答头信息 正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。
6. Web服务器向浏览器发送数据 Web服务器向浏览器发送头信息后,紧接着会发送一个空白行来表示头信息的发送到此为结束,接着,服务器就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据。
7. Web服务器关闭TCP连接 一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码:Connection:keep-alive
TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。

在上图中,可清晰的看到客户端浏览器(ip为192.168.2.33)与服务器的交互过程:
1)No1:浏览器(192.168.2.33)向服务器(220.181.50.118)发出连接请求。此为TCP三次握手第一步,此时从图中可以看出,为SYN,seq:X (x=0)
2)No2:服务器(220.181.50.118)回应了浏览器(192.168.2.33)的请求,并要求确认,此时为:SYN,ACK,此时seq:y(y为0),ACK:x+1(为1)。此为三次握手的第二步;
3)No3:浏览器(192.168.2.33)回应了服务器(220.181.50.118)的确认,连接成功。为:ACK,此时seq:x+1(为1),ACK:y+1(为1)。此为三次握手的第三步;
4)No4:浏览器(192.168.2.33)发出一个页面HTTP请求;
5)No5:服务器(220.181.50.118)确认;
6)No6:服务器(220.181.50.118)发送数据;
7)No7:客户端浏览器(192.168.2.33)确认;
8)No14:客户端(192.168.2.33)发出一个图片HTTP请求;
9)No15:服务器(220.181.50.118)发送状态响应码200 OK
……

TCP/IP通信传输流程(http举例)
首先作为发送端的客户端在应用层(http协议)发出一个想看某个web页面的http请求。接着,为了传输的方便,在传输层(tcp协议)把从应用层处收到的数据(http请求报文)进行分割,并在各个报文上打上标记序号及端口号后转发给网络层。在网络层(ip协议)增加作为通信目的地的MAC地址后转发给链路层。这样,发往网络的通信请求就齐全了。

 

HTTP/1.0 每次请求都需要建立新的TCP连接,连接不能复用。HTTP/1.1 新的请求可以在上次请求建立的TCP连接之上发送,连接可以复用。优点是减少重复进行TCP三次握手的开销,提高效率。在同一个TCP连接中,新的请求需要等上次请求收到响应后,才能发送。
与HTTP协议密切相关的协议/服务:IP,TCP,DNS
IP协议负责数据包的传送,当然,这需要配合IP地址和MAC地址,IP间的通信依赖MAC地址,这就涉及到用以解析地址的ARP协议了。
DNS服务负责解析域名
TCP提供了可靠的字节流服务,对要发送的大块数据进行分割成小数据包以易于传输,并且该协议可确认数据包是否送达到目的方。
1)异步
报文发送和接收是分开的,相互独立的,互不影响。这种方式又分两种情况:
(1)异步双工:接收和发送在同一个程序中,由两个不同的子进程分别负责发送和接收
(2)异步单工:接收和发送是用两个不同的程序来完成。
2)同步
报文发送和接收是同步进行,即报文发送后等待接收返回报文。 同步方式一般需要考虑超时问题,即报文发出去后不能无限等待,需要设定超时时间,超过该时间发送方不再等待读返回报文,直接通知超时返回。
在长连接中一般是没有条件能够判断读写什么时候结束,所以必须要加长度报文头。读函数先是读取报文头的长度,再根据这个长度去读相应长度的报文。

3)TCP三次握手

 

在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接,完成三次握手,客户端与服务器开始传送数据。
(1)第一次握手:建立连接时,客户端A发送SYN包(SYN=j)到服务器B,并进入SYN_SEND状态,等待服务器B确认。
(2)第二次握手:服务器B收到SYN包,必须确认客户A的SYN(ACK=j+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器B进入SYN_RECV状态。
(3)第三次握手:客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ACK=k+1),此包发送完毕,客户端A和服务器B进入ESTABLISHED状态,完成三次握手。

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。采用四次握手释放一个连接,
(1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送(报文段4)。
(2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
(3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A(报文段6)。
(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。
为了释放一个连接,任何一方都可以发送一个设置了FIN位的TCP数据段,这表示它已经没有数据要发送了。当FIN数据段被确认的时候,这个方向上就停止传送新数据。另一个方向上可能还在继续无限制地传送数据。当两个方向都停止的时候,连接才被释放。通常情况下,为了释放一个连接,需要4个TCP数据段:每个方向上一个FIN和一个ACK。然而,第一个ACK和第二个FIN有可能被包含在同一个数据段中,从而将总数降低到3个。

URI(统一资源标识符)和URL(统一资源定位符)
URI:一个用于标识某一互联网资源名称的字符串。组成:主机名(含端口号)+相对路径+标识符
URL:对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。组成:协议+主机名(含端口号)+相对路径
区别:URI表示请求资源在互联网上存在的位置,URL在表示请求资源的位置同时还要说明如何访问到这个资源,URL是URI的一个子集。
通过请求和响应的交换达成通信
请求报文是由请求方法、请求URI、协议版本、可选的请求头部字段和内容实体构成的。

响应报文基本上是由协议版本、状态码、用以解释状态码的原因短语、可选的响应首部字段及实体主体构成。

 


Cookies
HTTP协议用于客户端和服务端之间通过请求和响应的交换所达成的通信,并且它是一种无状态的协议,不会对请求和响应之间的通信状态进行保存(无法根据前一次请求对这次请求做出处理),但为了能够有保存状态的功能,引入了cookies技术。

 


Cookie和Session
Cookie和Session都为了用来保存状态信息,都是保存客户端状态的机制,它们都是为了解决HTTP无状态的问题而所做的努力。
Session可以用Cookie来实现,也可以用URL回写的机制来实现。用Cookie来实现的Session可以认为是对Cookie更高级的应用。

Cookie和Session有以下明显的不同点:
1)Cookie将状态保存在客户端,Session将状态保存在服务器端;
2)Cookies是服务器在本地机器上存储的小段文本并随每一个请求发送至同一个服务器。Cookie最早在RFC2109中实现,后续RFC2965做了增强。网络服务器用HTTP头向客户端发送cookies,在客户终端,浏览器解析这些cookies并将它们保存为一个本地文件,它会自动将同一服务器的任何请求缚上这些cookies。Session并没有在HTTP的协议中定义;
3)Session是针对每一个用户的,变量的值保存在服务器上,用一个sessionID来区分是哪个用户session变量,这个值是通过用户的浏览器在访问的时候返回给服务器,当客户禁用cookie时,这个值也可能设置为由get来返回给服务器;
4)就安全性来说:当你访问一个使用session 的站点,同时在自己机子上建立一个cookie,建议在服务器端的SESSION机制更安全些.因为它不会任意读取客户存储的信息。

Session机制
Session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为 session id,如果已包含一个session id则说明以前已经为此客户端创建过session,服务器就按照session id把这个 session检索出来使用(如果检索不到,可能会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个 session id将被在本次响应中返回给客户端保存。

Session的实现方式
1)使用Cookie来实现
服务器给每个Session分配一个唯一的JSESSIONID,并通过Cookie发送给客户端。
当客户端发起新的请求的时候,将在Cookie头中携带这个JSESSIONID。这样服务器能够找到这个客户端对应的Session。
流程如下图所示:

 

2)使用URL回显来实现
URL回写是指服务器在发送给浏览器页面的所有链接中都携带JSESSIONID的参数,这样客户端点击任何一个链接都会把JSESSIONID带会服务器。
如果直接在浏览器输入服务端资源的url来请求该资源,那么Session是匹配不到的。
Tomcat对Session的实现,是一开始同时使用Cookie和URL回写机制,如果发现客户端支持Cookie,就继续使用Cookie,停止使用URL回写。如果发现Cookie被禁用,就一直使用URL回写。jsp开发处理到Session的时候,对页面中的链接记得使用response.encodeURL() 。
3.1.3在J2EE项目中Session失效的几种情况
1)Session超时:Session在指定时间内失效,例如30分钟,若在30分钟内没有操作,则Session会失效,例如在web.xml中进行了如下设置:
<session-config>
<session-timeout>30</session-timeout> //单位:分钟
</session-config>
2)使用session.invalidate()明确的去掉Session。
3.1.4与Cookie相关的HTTP扩展头
1)Cookie:客户端将服务器设置的Cookie返回到服务器;
2)Set-Cookie:服务器向客户端设置Cookie;
3)Cookie2 (RFC2965)):客户端指示服务器支持Cookie的版本;
4)Set-Cookie2 (RFC2965):服务器向客户端设置Cookie。

Cookie的流程
服务器在响应消息中用Set-Cookie头将Cookie的内容回送给客户端,客户端在新的请求中将相同的内容携带在Cookie头中发送给服务器。从而实现会话的保持。
流程如下图所示:

 

 

 

持久连接
HTTP初始版本时,每进行一次HTTP请求就会断开一次TCP连接,这情况在早期传输文本很小的时候倒也不觉得如何,但是随着时代的进步,所需传输的内容种类越来越多和内容越来越大了,每次连接后都会断开请求就大幅度的增加了通信量的开销了。幸好,自HTTP/1.1和部分HTTP/1.0来,有了持久连接这么个神奇的东西,它规定了只要任何一方没有明确的提出断开连接,那么就保持TCP连接状态。而在维持的TCP连接期间,可以多次进行HTTP请求来传输需要的内容。
得益于持久连接,HTTP实现了管线化,能够做到同时并行发送多个请求,而无需一个接一个的等待响应。

HTTP/1.1默认保持持久连接,在HTTP的头部信息中会有Connection: Keep-alive属性,我们也可以通过浏览器开发工具的NetWork面板查看这个属性的状态及HTTP请求信息:

如何关闭持久连接:在响应头设置Connection属性为close.

HTTP请求的内容结构
HTTP协议交互的信息称为HTTP报文,HTTP报文大致可分为报文首部和报文主体两块,两者有最初出现的空行来划分,通常并不一定要有报文主体。通过下面的图来看看HTTP报文的结构:

除却空行(回车符、换行符),大致分为报文首部和报文主体。报文首部包含请求行(请求的方法、URI、HTTP版本)和状态行(响应状态码、原因短语、HTTP版本),首部字段(请求和响应的条件和属性),其他(未定义的首部)。
请求行:包含用于请求的方法,请求URI和HTTP版本
状态行:包含响应结果的状态码,原因短语和HTTP版本
首部字段:首部字段规定了客户端如何处理请求和服务端如何处理响应,根据用途可分为四种:请求首部(请求报文使用的首部),响应首部(响应报文使用的首部),通用首部(请求和响应通用的首部),实体首部(报文实体部分使用的首部)。
HTTP/1.1首部字段列表
通用首部字段
首部字段名 说明
1 Cache-Control 控制缓存的行为
2 Connection 逐跳首部、连接的管理
3 Date 创建报文的日期时间
4 Pragma 报文指令
5 Trailer 报文末端的首部一览
6 Transfer-Encoding 指定报文主体的传输编码方式
7 Upgrade 升级为其他协议
8 Via 代理服务器的相关信息
9 Warning 错误通知

请求首部字段
首部字段名 说明
1 Accept 用户代理可处理的媒体类型/浏览器可接受的MIME类型
2 Accept-Charset 浏览器可接受的字符集
3 Accept-Encoding 浏览器能够进行解码的数据编码方式,比如gzip。
4 Accept-Language 浏览器所希望的语言种类(如中文)
5 Authorization 授权信息,通常出现在对服务器发送的WWW-Authenticate头的应答中
6 Connection: 表示是否需要持久连接。如果Servlet看到这里的值为“Keep-Alive”,它就是持久连接;
7 Content-Length: 表示请求消息正文的长度;
8 Cookie: 这是最重要的请求头信息之一;
9 Expect 期待服务器的特定行为
10 From 用户的电子邮箱地址
11 Host 初始URL中的主机和端口
12 if-Match 比较实体标记(ETag)
13 if-Modified-Since 比较资源的更新时间
14 if-None-Match 比较实体标记(与if-Match相反)
15 if-Range 资源未更新时发送实体Byte的范围请求
16 if-Unmodified-Since 比较资源的更新时间(与if-Modified-Since相反)
17 Max-Forwards 最大传输逐跳数
18 Proxy-Authorization 代理服务器要求客户端的认证信息
19 Range 实体的字节范围请求
20 Referer 对请求中URI的原始获取方法
21 TE 传输编码的优先级
22 User-Agent HTTP客户端程序的信息

响应首部字段
首部字段名 说明
1 Accept-Ranges 是否接受字节范围请求
2 Age 推算资源创建经过时间
3 ETag 资源的匹配信息
4 Location 令客户端重定向至指定URI
5 Proxy-Authenticate 代理服务器对客户端的认证信息
6 Reter-After 对再次发起请求的时机要求
7 Server HTTP服务器的安装信息
8 Vary 代理服务器缓存的管理信息
9 WWW-Authenticate 服务器对客户端的认证信息

实体首部字段

首部字段名 说明
1 Allow 资源可支持的HTTP方法
2 Content-Encoding 实体主体的适用的编码方式,gzip,见“响应首部”
3 Content-Language 实体主体的内容语言类型,例如:zh-cn
4 Content-Length 实体主体的内容长度,eg:80(单位:字节)
5 Content-Location 替代对应资源的URI
6 Content-MD5 实体主体的报文摘要,用作校验和。发送方和接受方都计算MD5摘要,接受方将其计算的值与此头标中传递的值进行比较
7 Content-Range 实体主体的位置范围,也标明此实体的总长度
8 Content-Type 实体主体的媒体类型
9 Expires 实体主体过期的日期时间,为0证明不缓存
10 Last-Modified 资源的最后修改日期时间


传输编码
HTTP传输数据的时候可以传输原数据,也可以在传输过程中编码以提升传输速率。通过传输时的编码处理,能有效的处理大量的访问请求。常用的内容编码有以下几种
· gzip(GUN zip)
· compress(UNIX系统的标准压缩)
· deflate(zlib)
· identity(不进行编码)
多部分对象集合
HTTP协议中采纳了多部分对象集合,允许发送的报文主体内可含有多类型实体。多用于上传文件或者图片时使用,可以设置Content-Type属性对其进行规定。如以下几种常见的形式:
Text:用于标准化地表示的文本信息,文本消息可以是多种字符集和或者多种格式的
Multipart:用于连接消息体的多个部分构成一个消息,这些部分可以是不同类型的数据
Application:用于传输应用程序数据或者二进制数据
ContentType
用于定义网络文件的类型和网页的编码,决定文件接收方将以什么形式、什么编码读取这个文件。ContentType属性指定响应的 HTTP内容类型。在请求服务器端的响应时, 对于每一种返回类型规范的做法是要在服务端指定response的contentType 的.当然,不指定绝大多数情况下也没什么问题尤其是返回"非xml"的时候。如果未指定 ContentType,默认为TEXT/HTML。

常见的媒体格式类型如下:
Content-Type=text/html :服务端需要返回一段HTML代码给客户端
Content-Type=text/plain :服务端需要返回一段普通文本给客户端
Content-Type=text/xml : 服务端需要返回一段XML代码给客户端
Content-Type= image/gif :gif图片格式
Content-Type=image/jpeg :jpg图片格式
Content-Type=image/png:png图片格式
Content-Type=text/javascript 服务端需要返回一段javascript代码给客户端

以application开头的媒体格式类型:
Content-Type=application/xhtml+xml :XHTML格式
Content-Type=application/xml : XML数据格式
Content-Type=application/atom+xml :Atom XML聚合格式
Content-Type=application/json :服务端需要返回一段json串给客户端
Content-Type=application/pdf :pdf格式
Content-Type=application/msword : Word文档格式
Content-Type=application/octet-stream : 二进制流数据(如常见的文件下载)
Content-Type=application/x-www-form-urlencoded :FORM元素的enctype属性指定了表单数据向服务器提交时所采用的编码类型
Content-Type=application/javascript服务端需要返回一段javascript代码给客户端

范围请求
执行范围请求时,会用到首部字段Range来指定资源的byte范围,如:一份1000字节大小的文件,想取300-3000字节范围内的资源,可以设置Range:bytes=300-3000;想取300-3000字节和5000字节到最后的资源,可以设置Range:bytes=300-3000,5000-
内容协商
内容协商机制是指客户端和服务端就响应资源内容进行交涉,然后提供给客户最为适合的资源,内容协商会以响应资源的语言、字符集、编码方式等作为判断的基准。涉及到以下首部字段:
· Accept
· Accept-Charset
· Accept-Encoding
· Accept-Language
· Content-Language

内容协商技术又分为三种类型
服务器驱动协商:服务端以请求的首部字段作为参考,在服务端处理并且返回对应资源。
客户端驱动协商:用户通过浏览器提供的可选列表进行手动选择,或者利用js脚本在web页面上自行选择。
透明协商:服务器驱动协商和代理驱动协商的结合体,当一个缓存被提供了构成响应的一系列可得的表现形式,并且维度的差异能完全被缓存理解,那么此缓存变得有能力代表源服务器为那个资源的后续请求去执行服务器驱动协商

HTTP方法及状态码
HTTP方法
HTTP中也包含了一些方法,用于指定请求的资源按期望产生某种行为。对于这些方法,其中用的最多的是get和post。
GET方式:是以实体的方式得到由请求URI所指定资源的信息,如果请求URI只是一个数据产生过程,那么最终要在响应实体中返回的是处理过程的结果所指向的资源,而不是处理过程的描述。
POST方式:用来传输实体的主体,向目的服务器发出请求,要求它接受被附在请求后的实体,并把它当作请求队列中请求URI所指定资源的附加新子项,Post被设计成用统一的方法实现下列功能:1:对现有资源的解释;2:向电子公告栏、新闻组、邮件列表或类似讨论组发信息;3:提交数据块;4:通过附加操作来扩展数据库 。

GET方法和POST方法的区别:
1)安全性:GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,参数之间以&相连,参数将明文出现在URL上,容易被他人看到,URL信息也可能会被记录到历史纪录中。POST请求是把提交的数据则放置在是HTTP包的包体中。

2)数据长度:HTTP协议没有对传输的数据和URL长度进行限制, 但特定浏览器和服务器对URL长度有限制, 因此对于GET提交时,传输数据就会受到URL长度的限制(大部分最多只能有1024字节);
由于POST操作不是通过URL传值,理论上数据长度不受限;

3)缓存:GET请求能够被缓存,以GET请求的URL能够保存为浏览器书签,而POST请求则都不能

4)数据获取:Get是向服务器发索取数据的一种请求;而Post是向服务器提交数据的一种请求,要提交的数据位于信息头后面的实体中。

HTTP-GET的处理特征如下:
。将数据添加到URL
。利用一个问号(”?”)代表URL地址的结尾与数据的开端。
。每一个数据的元素以 名称/值 (name/value) 的形式出现。
。利用一个分号(“;”)来区分多个数据元素。
HTTP-POST的处理特征如下:
。将数据包括在HTTP主体中。
。同样的,数据的元素以 名称/值 (name/value) 的形式出现。
。但是每一个数据元素分别占用主体的一行。

以下其他方法均不常用
PUT:传输文件 HEAD:获得报文首部 DELETE:删除文件 OPTUIONS:询问支持的方法 TRACK:追踪路径 CONNECT:要求用隧道协议连接代理

HTTP状态码
HTTP状态码表示客户端HTTP请求的返回结果,通过状态码,用户可以知道HTTP请求是否出现问题,问题出在哪,下面简单罗列一些HTTP状态码:
http的状态响应码

1XX informational(信息性状态码) 接收的请求正在处理
100——客户必须继续发出请求
101——客户要求服务器根据请求转换HTTP协议版本

2XX Success(成功状态码) 请求正常处理完毕
200——交易成功
201——提示知道新文件的URL
202——接受和处理、但处理未完成
203——返回信息不确定或不完整
204——请求收到,但返回信息为空
205——服务器完成了请求,用户代理必须复位当前已经浏览过的文件
206——服务器已经完成了部分用户的GET请求

3XX Redirection(重定向状态码) 需要进行附加操作已完成请求
300——请求的资源可在多处得到
301——删除请求数据
302——在其他地址发现了请求数据
303——建议客户访问其他URL或访问方式
304——客户端已经执行了GET,但文件未变化
305——请求的资源必须从服务器指定的地址得到
306——前一版本HTTP中使用的代码,现行版本中不再使用
307——申明请求的资源临时性删除

4XX Client Error(客户端错误状态码) 服务器无法处理请求
400——错误请求,如语法错误
401——未授权
402——保留有效ChargeTo头响应
403——禁止访问
404——没有发现文件、查询或URl
405——用户在Request-Line字段定义的方法不允许
406——根据用户发送的Accept拖,请求资源不可访问
407——类似401,用户必须首先在代理服务器上得到授权
408——客户端没有在用户指定的饿时间内完成请求
409——对当前资源状态,请求不能完成
410——服务器上不再有此资源且无进一步的参考地址
411——服务器拒绝用户定义的Content-Length属性请求
412——一个或多个请求头字段在当前请求中错误
413——请求的资源大于服务器允许的大小
414——请求的资源URL长于服务器允许的长度
415——请求资源不支持请求项目格式
416——请求中包含Range请求头字段,在当前请求资源范围内没有range指示值,请求也不包含If-Range请求头字段
417——服务器不满足请求Expect头字段指定的期望值,如果是代理服务器,可能是下一级服务器不能满足请求长。

5XX Server Error(服务器端错误状态码) 服务器处理请求出错
HTTP 500 - 内部服务器错误
Error 501 - 未实现
HTTP 502 - 网关错误

HTTP代理及缓存
代理
代理指的是具有转发功能的应用程序,接收客户端的请求转发给服务端,也接收服务端的响应转发给客户端。代理不会改变请求的URI,会直接发送给持有资源的服务器。转发时需要附加Via首部字段以标记出经过的主机信息。
在HTTP通信过程中可以级联多台代理服务器,并且转发时需要附加Via首部字段以标记经过的主机信息。

 


缓存
缓存是代理服务器或客户端本地磁盘内保存的资源副本,利用缓存来减少对源服务器的访问以便于节省通信流量和通信时间,也可以达到更好的交互体验。
请求的资源如果已经被缓存则直接由缓存服务器返回给客户端,或者客户端直接从本地磁盘读取。缓存可以设置有效时间,当判断缓存过期后,客户端/缓存服务器可像源服务器重新请求新资源。
断点续传和多线程下载的实现原理
HTTP协议的GET方法,支持只请求某个资源的某一部分;
Range 请求的资源范围;
Content-Range 响应的资源范围;

断点续传原理:
对资源进行分块,然后分块请求资,
Eg1:Range: bytes=306302- :请求这个资源从306302个字节到末尾的部分;
Eg2:Content-Range: bytes 306302-604047/604048:响应中指示携带的是该资源的第306302-604047的字节,该资源共604048个字节;
客户端通过并发的请求相同资源的不同片段,来实现对某个资源的并发分块下载。

多线程下载的原理:
下载工具开启多个发出HTTP请求的线程;每个http请求只请求资源文件的一部分:Content-Range: bytes 20000-40000/47000;合并每个线程下载的文件。


HTTP的缺点
· 通信使用明文(未经加密),内容可能被窃听
· 不验证通信方的身份,请求/响应会遭伪装
· 无法证明报文的完整性,存在被篡改的可能

针对明文传输这点,也可以对报文主体(传输内容)进行加密处理
针对身份验证这点,可通过在本地安装证书,存储身份认证信息等
针对确保信息完整性,MD5/SHA-1的散列值校验,数字签名等

HTTP不带加密机制,但可以通过和SSL(安全 套接层...标注下阅读时的停顿)或TLS(安全层传输协议)的组合使用,用SSL建立安全通信线路后,就可以在这条线路上欢快的进行HTTP通信了。由于结合了SSL,HTTP升级成为HTTPS(或者 HTTP over SSL),然而这还不能说是个完整的HTTPS。
完整的HTTPS = HTTP + 加密 + 认证 + 完整性保护

HTTP协议中的长连接和短连接
HTTP协议是基于请求/响应模式的,因此只要服务端给了响应,本次HTTP连接就结束了,或者更准确的说,是本次HTTP请求就结束了,根本没有长连接这一说。那么自然也就没有短连接这一说了。之所以说HTTP分为长连接和短连接,其实本质上是说的TCP连接。TCP连接是一个双向的通道,它是可以保持一段时间不关闭的,因此TCP连接才有真正的长连接和短连接这一说。HTTP协议说到底是应用层的协议,而TCP才是真正的传输层协议,只有负责传输的这一层才需要建立连接。“HTTP连接”这个词就不应该出现,它只是一个应用层的协议,根本就没有所谓的连接这一说,就像FTP也是应用层的协议,但是你有听说过FTP连接吗?(其实所谓的FTP连接,严格来说,依旧是TCP连接)。
短链接:连接->传输数据->关闭连接 。HTTP是无状态的,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。 也可以这样说:短连接是指SOCKET连接后发送后接收完数据后马上断开连接。

长连接其实是指的TCP连接,只要设置Connection为keep-alive就算是长连接,但要服务器和客户端都设置。我们平时用的是长连接。(现在用的基本上都是HTTP1.1协议,你观察一下就会发现,基本上Connection都是keep-alive。而且HTTP协议文档上也提到了,HTTP1.1默认是长连接,也就是默认Connection的值就是keep-alive)长连接 :连接->传输数据->保持连接 -> 传输数据-> 。。。 ->关闭连接。 长连接指建立SOCKET连接后不管是否使用都保持连接,但安全性较差。

长连接是为了复用。那既然长连接是指的TCP连接,也就是说复用的是TCP连接,长连接情况下,多个HTTP请求可以复用同一个TCP连接,这就节省了很多TCP连接建立和断开的消耗。如果你是短连接(也就是每次都要重新建立TCP连接)的话,那你每打开一个网页,基本要建立几个甚至几十个TCP连接,这很浪费资源。但如果是长连接的话,那么这么多次HTTP请求,其实使用的都是一个TCP连接,很显然是可以节省很多消耗的。长连接并不是永久连接的。如果一段时间内(具体的时间长短,是可以在header当中进行设置的,也就是所谓的超时时间),这个连接没有HTTP请求发出的话,那么这个长连接就会被断掉。HTTP连接分为“长连接”和“短连接”,HTTP1.0协议不支持长连接,从HTTP1.1协议以后,连接默认都是长连接。而我们现在常用的都是HTTP1.1,因此我们用的都是长连接。

什么时候用长连接和短连接
长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况,每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。 而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。 总之,长连接和短连接的选择要视情况而定。

HTTP协议中的长轮询和短轮询
  短轮询不难理解,比如你现在要做一个电商中商品详情的页面,这个详情界面中有一个字段是库存量。而这个库存量需要实时的变化,保持和服务器里实际的库存一致。这个时候,最简单的一种方式,就是写个死循环,不停的去请求服务器中的库存量是多少,然后刷新到这个页面当中,这其实就是所谓的短轮询。
  这种方式有明显的坏处,那就是你很浪费服务器和客户端的资源。客户端还好点,现在PC机配置高了,你不停的请求还不至于把用户的电脑整死,但是服务器就不同了。如果有1000个人停留在某个商品详情页面,那就是说会有1000个客户端不停的去请求服务器获取库存量,这显然是不合理的。
长轮询和短轮询最大的区别是,短轮询去服务端查询的时候,不管库存量有没有变化,服务器就立即返回结果了。而长轮询则不是,在长轮询中,服务器如果检测到库存量没有变化的话,将会把当前请求挂起一段时间(这个时间也叫作超时时间,一般是几十秒)。在这个时间里,服务器会去检测库存量有没有变化,检测到变化就立即返回,否则就一直等到超时为止。
  而对于客户端来说,不管是长轮询还是短轮询,客户端的动作都是一样的,就是不停的去请求,不同的是服务端,短轮询情况下服务端每次请求不管有没有变化都会立即返回结果,而长轮询情况下,如果有变化才会立即返回结果,而没有变化的话,则不会再立即给客户端返回结果,直到超时为止。 
  这样一来,客户端的请求次数将会大量减少,而且也解决了服务端一直疲于接受请求的窘境。但是长轮询也是有坏处的,因为把请求挂起同样会导致资源的浪费,假设还是1000个人停留在某个商品详情页面,那就很有可能服务器这边挂着1000个线程,在不停检测库存量,这依然是有问题的。因此,不管是长轮询还是短轮询,都不太适用于客户端数量太多的情况,因为每个服务器所能承载的TCP连接数是有上限的,这种轮询很容易把连接数顶满。

长短轮询和长短连接的区别
第一,一个TCP连接是否为长连接,是通过设置HTTP的Connection Header来决定的,而且是需要两边都设置才有效。而一种轮询方式是否为长轮询,是根据服务端的处理方式来决定的,与客户端没有关系。
第二个区别就是实现的方式,连接的长短是通过协议来规定和实现的。而轮询的长短,是服务器通过编程的方式手动挂起请求来实现的。

 

 

 

HTTP/2
1996 年定义了HTTP 1.0 规范,今天HTTP 1.1 已经变成互联网中主要的协议。随着 web 技术的飞速发展。 HTTP 1.1 已经无法满足用户对性能的要求, HTTP/2(原名HTTP/2.0)主要基于 SPDY 协议。HTTP/2标准于2015年5月以RFC 7540正式发表。

二进制分帧
先来理解几个概念:
帧(帧):HTTP/2数据通信的最小单位。
消息(Message):指 HTTP/2 中逻辑上的 HTTP 消息。例如请求和响应等,消息由一个或多个帧组成。
流(流):存在于连接中的一个虚拟通道。流可以承载双向消息,每个流都有一个唯一的整数ID。
HTTP/2 采用二进制格式传输数据,而非 HTTP 1.x 的文本格式,二进制协议解析起来更高效。
HTTP/1 的请求和响应报文,都是由起始行,首部和实体正文(可选)组成,各部分之间以文本换行符分隔。HTTP/2 将请求和响应数据分割为更小的帧,并且它们采用二进制编码。
HTTP/2 中,同域名下所有通信都在单个连接上完成(多路复用中介绍),这个连接可以承载任意数量的双向数据流。每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装。
多路复用
多路复用,代替原来的序列和阻塞机制。所有就是请求的都是通过一个 TCP连接并发完成。
HTTP 1.x 中,如果想并发多个请求,必须使用多个 TCP 链接,且浏览器为了控制资源,还会对单个域名有 6-8 的个数限制,如下图,红色圈出来的请求就因域名链接数已超过限制,而被挂起等待了一段时间:

在 HTTP/2 中,有了二进制分帧之后,HTTP/2 不再依赖 TCP 链接去实现多流并行了,在 HTTP/2中:
●同域名下所有通信都在单个连接上完成。
●单个连接可以承载任意数量的双向数据流。
●数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装。
这一特性,性能会有极大的提升,因为:
●同个域名只需要占用一个 TCP 连接,消除了因多个 TCP 连接而带来的延时和内存消耗。
●单个连接上可以并行交错的请求和响应,之间互不干扰。
●在HTTP/2中,每个请求都可以带一个31bit的优先值,0表示最高优先级, 数值越大优先级越低。有了这个优先值,客户端和服务器就可以在处理不同的流时采取不同的策略,以最优的方式发送流、消息和帧。

服务器推送
服务端可以在发送页面HTML时主动推送其它资源,而不用等到浏览器解析到相应位置,发起请求再响应。例如服务端可以主动把JS和CSS文件推送给客户端,而不需要客户端解析HTML再发送这些请求。服务端可以主动推送,客户端也有权利选择接收与否。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送RST_STREAM帧来拒收。主动推送也遵守同源策略,服务器不会随便推送第三方资源给客户端。

头部压缩
HTTP 1.1请求的大小变得越来越大,有时甚至会大于TCP窗口的初始大小,因为它们需要等待带着ACK的响应回来以后才能继续被发送。HTTP/2对消息头采用HPACK(专为http2头部设计的压缩格式)进行压缩传输,能够节省消息头占用的网络的流量。而HTTP/1.x每次请求,都会携带大量冗余头信息,浪费了很多带宽资源。
HTTP 每一次通信都会携带一组头部,用于描述这次通信的的资源、浏览器属性、cookie 等,例如

为了减少这块的开销并提升性能, HTTP/2会压缩这些首部:
●HTTP/2在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送;
●首部表在HTTP/2的连接存续期内始终存在,由客户端和服务器共同渐进地更新;
●每个新的首部键-值对要么被追加到当前表的末尾,要么替换表中之前的值。
例如:下图中的两个请求, 请求一发送了所有的头部字段,第二个请求则只需要发送差异数据,这样可以减少冗余数据,降低开销。

我们来看一个实际的例子,下面是用WireShark抓取的访问google首页的包:

上图是是访问https://www.google.com/抓到的第一个请求的头部,可以看到头部的内容,总共占用了437 bytes,我们选中头部的cookie,可以看到cookie总共占用了118 bytes。接下来我们看看第二个请求的头部:

从上图可以看到,得益于头部压缩,第二个请求中cookie只占用了1个字节,我们来看看变化了的Accept字段:

由于Accept字段与请求一中的内容不同,需要发送给服务器,所以占用了29 bytes。

WebSocket 和 http/2.0
WebSocket
WebSocket实现了再Web客户端和服务端之间的全双工通信,一旦Web服务端与客户端之间建立WebSocket协议的通信连接,之后的所有通信都依赖这个专用协议进行。
WebSocket具有推送功能,服务端可直接向客户端推送数据,不必等待客户端的请求;由于WebSocket一直保持连接状态,并且首部信息小,使得通信量也相应的减少。
为了实现WebSocket通信。需要用到前面说到的HTTP首部字段Upgrade,达到告知服务端通信协议发生改变,当成功握手确立WebSocket连接之后,通信时不再使用HTTP的数据帧,而采用WebSocket独立的数据帧。
使用浏览器进行双全工通信的WebSocket协议主要特点:
a支持由服务器向客户端推送数据功能
b减少通信量,不但每次连接总开销减少,而且首部信息也很少
为了实现WebSocket通信需要将Http的Upgrade首部字段值设为websocket,对于之前的握手请求,返回状态码101 Switching Proticols.成功握手确立WebSocket连接之后,不再使用HTTP的数据帧,而采用WebSocket独立数据帧


HTTP/2.0
核心优势/特性
多路复用:多个请求都是通过一个 TCP 连接并发完成(HTTP/1.1管线化在多个请求之间的响应会被阻塞,HTTP/2.0解决了这问题,并且支持优先级和流量控制)
头部压缩:报文头部压缩处理,数通信量更小
服务端推送:服务端能够更快的把资源推送给客户端
语义改进:采用二进制格式传输数据

HTTPS
HTTP是明文传输的,也就意味着,介于发送端、接收端中间的任意节点都可以知道你们传输的内容是什么。这些节点可能是路由器、代理等。https是HTTP运行在SSL/TLS之上,SSL/TLS运行在TCP之上。所有传输的内容都经过加密,加密采用对称加密,但对称加密的密钥用服务器方的证书进行了非对称加密。此外客户端可以验证服务器端的身份,如果配置了客户端验证,服务器方也可以验证客户端的身份。安全传输层协议(TLS)用于在两个通信应用程序之间提供保密性和数据完整性。该协议由两层组成: TLS 记录协议(TLS Record)和 TLS 握手协议(TLS Handshake)。较低的层为 TLS 记录协议,位于某个可靠的传输协议(例如 TCP)上面,与具体的应用无关,所以,一般把TLS协议归为传输层安全协议。TLS、SSL其实是类似的东西,SSL是个加密套件,负责对HTTP的数据进行加密。TLS是SSL的升级版。现在提到HTTPS,加密套件基本指的是TLS。
HTTPS全称Hyper Text Transfer Protocol over Secure Socket Layer,直译过来就是通过SSL实现的超文本传输协议,简单来讲就是加密版的HTTP协议,也就是HTTP+SSL/TLS。
我们都知道,HTTP是明文传输的,因此使用HTTP协议传输隐私信息非常不安全,很容易在传输过程中被窃取,或者通信内容被人篡改冒充,使用HTTPS可以避免这些问题。

SSL/TLS
为了解决HTTP明文传输的风险性,网景公司设计了SSL。SSL目前的版本是3.0,之后IETF对SSL 3.0进行了升级,于是出现了TLS 1.0。简单而言就是TLS是SSL的升级版,现在浏览器一般用的都是TLS。
SSL(Secure Socket Layer,安全套接字层):1994年为 Netscape 所研发,SSL 协议位于 TCP/IP 协议与各种应用层协议之间,为数据通讯提供安全支持。他的版本有:SSL 1.0、SSL 2.0、SSL 3.0
TLS(Transport Layer Security,传输层安全):其前身是 SSL,1999年从 3.1 开始被 IETF 标准化并改名为TLS,发展至今已经有 TLS 1.0、TLS 1.1、TLS 1.2 三个版本。
SSL3.0和TLS1.0由于存在安全漏洞,已经很少被使用到。目前使用最广泛的是TLS 1.1、TLS 1.2。

https的实现原理
有两种基本的加解密算法类型:
1)对称加密:密钥只有一个,加密解密为同一个密码,且加解密速度快,典型的对称加密算法有DES、AES等;
2)非对称加密:密钥成对出现(且根据公钥无法推知私钥,根据私钥也无法推知公钥),加密解密使用不同密钥(公钥加密需要私钥解密,私钥加密需要公钥解密),相对对称加密速度较慢,典型的非对称加密算法有RSA、DSA等。

HTTPS加密方式介绍
浏览器-->SSL Client Hello(我支持这些加密方式)-->服务器
浏览器<-SLL Server Hello(就用这种加密,然后下面是我的证书)-<--服务器
浏览器-->证书验证ok,拿证书里的公钥加密key,告诉服务器-->服务器
浏览器<--私钥解密,得到key<--服务器
开始以对称密钥的方式,加密通信,密钥即key

HTTPS的优点
从实际出发来看,HTTPS主要有以下优点:
1防止私密信息泄露,防止信息被篡改;
2有助于SEO,百度、谷歌均明确表示会优先收录、展示HTTPS站点的内容;
3完全杜绝运营商HTTP劫持问题;
4有效解决运营商DNS劫持问题,降低网站被劫持的风险;
5HTTPS的小绿锁表示可以提升用户对网站信任程度(当然不是说有小绿锁的都是安全的);
6可以有效防止山寨、镜像网站等;
7为未来升级HTTP/2做准备,HTTP/2必须基于HTTPS部署;

HTTPS的缺点
1服务器性能下降,开启HTTPS会增加内存、CPU、网络带宽的开销,特别是非对称加密这一块;
2访问速度下降,HTTP连接的建立需要3次握手,HTTPS还需要加上ssl的几次握手(具体是几次没去考究,有说是9次),当然下降主要是在第一次建立连接的时候,后面正常通信速度一般没啥变化;
3除了握手部分外,所有信息传输之后浏览器和服务器都要进行加密解密,又是一笔额外的开销;
4申请证书需要一笔花费,当然现在免费证书也很容易申请到,这个不算明显缺点;

 

HTTPS原理
HTTPS主要分为单向认证和双向认证,99%的场景都只需要单向认证。

单向认证

 

1浏览器访问一个https地址,同时向服务端发送支持的SSL协议版本、支持的加密算法、一个客户端生成的随机数(用于稍后生成"对话密钥")等。
2服务端给客户端返回要使用的SSL协议版本号、加密算法、一个服务器生成的随机数(也同样用于稍后生成"对话密钥"),另外还有一个最重要的,返回服务器端的证书,即公钥证书;
3客户端收到服务器回应以后,首先验证证书是否合法,如果证书不是可信机构颁布、或者证书中的域名与实际域名不一致、或者证书已经过期、或者返回的公钥不能正确解开返回证书中的数字签名,就会向访问者显示一个警告,由其选择是否还要继续通信。如果证书没有问题,客户端就会从证书中取出服务器的公钥继续;
客4户端向服务端发送自己所能支持的对称加密方案(注意是对称加密),供服务器端进行选择;
5服务器端在客户端提供的加密方案中选择加密程度最高的加密方式;
6服务器将选择好的加密方案通过明文方式返回给客户端;
7客户端接收到服务端返回的加密方式后,使用该加密方式生成产生一个随机密钥(后续用作通信过程中对称加密的密钥),然后将该随机数用用证书中的公钥加密发给服务端;
8服务器收到客户端返回的加密信息后,使用自己的私钥进行解密,获得最终的对称加密密钥。至此,客户端和服务端都得到一个随机密钥,并且这个密钥别人没法知道;
9在接下来的会话中,服务器和客户端将会使用该密码进行对称加密解密,保证通信过程中信息的安全。

双向认证
双向认证和单向认证原理基本差不多,主要区别是除了客户端需要认证服务端以外,服务端对客户端也需要认证。什么场景下需要验证客户端呢?比如一些银行业务,银行会要求客户必须在电脑上插入它们签发的U盾之类的东西,或者安装什么控件,这里就类似客户端证书的概念,没有这个证书的人无法使用银行提供的业务。

 

一次完整的HTTPS请求

1.客户端发送Client Hello报文开始SSL通信,报文中包含客户端支持的SSL的指定版本、加密组件列表等
2.服务端可进行SSL通信时,会以Serve rHello报文作为应答
3.服务端发送Certificate报文,报文包含公开密钥证书
4.服务端发送Server Hello Done报文通知客户端,最初阶段的SSL握手协商部分结束
5.SSL第一次握手结束后,客户端以Client Key Exchange报文作为回应,其中包含通信加密中使用的随机密码串
6.客户端发送Change Cipher Spec报文,提示服务端此报文之后的通信采用符合上一步的随机密码串的密钥加密
7.客户端发送Finished报文,其中包含连接至今全部报文的整体校验值
8.服务端发送Change Cipher Spec报文
9.服务端发送Finished报文
10.Finished报文交换完毕后,SSL连接建立完成
11.应用层协议通信,HTTP
12.客户端断开连接,发送close notify

TLS握手过程
TSL握手协议如下图所示

在建立TCP连接后,开始建立TLS连接。下面抓包分析TLS握手过程,抓包图片来源于传输层安全协议抓包分析之SSL/TLS (自己没抓到这么完整的包,只能搬运过来了,摔)


(1) client端发起握手请求,会向服务器发送一个ClientHello消息,该消息包括其所支持的SSL/TLS版本、Cipher Suite加密算法列表(告知服务器自己支持哪些加密算法)、sessionID、随机数等内容。

 

(2) 服务器收到请求后会向client端发送ServerHello消息,其中包括:
SSL/TLS版本;
session ID,因为是首次连接会新生成一个session id发给client;
Cipher Suite,sever端从Client Hello消息中的Cipher Suite加密算法列表中选择使用的加密算法;
Radmon 随机数。

 

(3) 经过ServerHello消息确定TLS协议版本和选择加密算法之后,就可以开始发送证书给client端了。证书中包含公钥、签名、证书机构等信息。

 

(4) 服务器向client发送ServerKeyExchange消息,消息中包含了服务器这边的EC Diffie-Hellman算法相关参数。此消息一般只在选择使用DHE 和DH_anon等加密算法组合时才会由服务器发出。

 

(5) server端发送ServerHelloDone消息,表明服务器端握手消息已经发送完成了。

 

(6) client端收到server发来的证书,会去验证证书,当认为证书可信之后,会向server发送ClientKeyExchange消息,消息中包含客户端这边的EC Diffie-Hellman算法相关参数,然后服务器和客户端都可根据接收到的对方参数和自身参数运算出Premaster secret,为生成会话密钥做准备。

 

(7) 此时client端和server端都可以根据之前通信内容计算出Master Secret(加密传输所使用的对称加密秘钥),client端通过发送此消息告知server端开始使用加密方式发送消息。

 

(8) 客户端使用之前握手过程中获得的服务器随机数、客户端随机数、Premaster secret计算生成会话密钥master secret,然后使用该会话密钥加密之前所有收发握手消息的Hash和MAC值,发送给服务器,以验证加密通信是否可用。服务器将使用相同的方法生成相同的会话密钥以解密此消息,校验其中的Hash和MAC值。

 

(9) 服务器发送ChangeCipherSpec消息,通知客户端此消息以后服务器会以加密方式发送数据。

 

(10) sever端使用会话密钥加密(生成方式与客户端相同,使用握手过程中获得的服务器随机数、客户端随机数、Premaster secret计算生成)之前所有收发握手消息的Hash和MAC值,发送给客户端去校验。若客户端服务器都校验成功,握手阶段完成,双方将按照SSL记录协议的规范使用协商生成的会话密钥加密发送数据。

 

 

HTTP 访问过程

抓包如下:

如上图所示,HTTP请求过程中,客户端与服务器之间没有任何身份确认的过程,数据全部明文传输,“裸奔”在互联网上,所以很容易遭到黑客的攻击,如下:
可以看到,客户端发出的请求很容易被黑客截获,如果此时黑客冒充服务器,则其可返回任意信息给客户端,而不被客户端察觉,所以我们经常会听到一词“劫持”,现象如下:
下面两图中,浏览器中填入的是相同的URL,左边是正确响应,而右边则是被劫持后的响应
所以 HTTP 传输面临的风险有:
(1) 窃听风险:黑客可以获知通信内容。
(2) 篡改风险:黑客可以修改通信内容。
(3) 冒充风险:黑客可以冒充他人身份参与通信。

HTTPS需突破的5个技术难点
随着互联网用户对安全性、保密性的需求日益提升,将网站升级成为HTTPS已经如风潮般席卷了国内外互联网厂商,然而,对于互联网厂商来说,并不是部署了HTTPS就可以高枕无忧,要让HTTPS发挥最大作用,往往还需要与HSTS、HTTP 2.0、OSCP stapling等其它技术一起使用。本文罗列了网站在实现HTTPS中遇到的5个技术难点,帮助广大需要进行HTTPS升级和已经升级为HTTPS的互联网厂商呈现出升级HTTPS后更好的用户体验。

1、HSTS
即使我们将一个HTTP网站升级为HTTPS网站,当我们在浏览器中键入以www为开头的网址时,网页并不会自动跳转为HTTPS网站,因为浏览器默认打开HTTP网站,基于此,我们就需要对HTTP的访问在服务器端做301、302或307重定向,使之跳转到HTTPS网站。
其中最常用的就是302重定向了:
302重定向是一条对网站浏览器的指令,来使浏览器显示被要求显示的URL,当一个网页经历短期的URL变化时使用。
301重定向是302重定向的升级版,301重定向是永久的重定向,搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址。
但是它们存在一个共同的弱点:
当使用301、302跳转时,只要修改location指令,网站就会被劫持。
对此,国际互联网工程组织IETE推行了一种新的Web安全协议:HSTS,即307跳转。
采用HSTS协议的网站将保证浏览器始终连接到该网站的HTTPS加密版本,不需要用户手动在URL地址栏中输入加密地址。帮助网站采用全局加密,用户看到的就是该网站的安全版本。
HSTS的作用还包括阻止基于SSL Strip的中间人攻击,万一证书有错误,则显示错误,用户不能回避警告。从而能够更加有效安全的保障用户的访问。
目前主流的浏览器大多已支持HSTS,但IE 11以下版本还不支持HSTS。

2、HTTP/2
HTTP/2即超文本传输协议2.0,是HTTP协议的升级版。由互联网工程任务组的Hypertext Transfer Protocol Bis工作小组进行开发,以SPDY为原型,经过两年多的讨论和完善最终确定。
SPDY是一种HTTP兼容协议,由Google发起,Chrome、Opera、Firefox以及Amazon Silk等浏览器均已提供支持,并对当前的HTTP协议有4个改进:
•多路复用请求
•对请求划分优先级
•压缩HTTP头
•服务器推送流(即Server Push技术)

HTTP/2相比于SPDY,优势更加明显:
•HTTP/2采用二进制格式传输数据,其在协议的解析和优化扩展上带来更多的优势和可能
•HTTP/2对消息头采用HPACK进行压缩传输,能够节省消息头占用的网络的流量
•Server Push的服务端能够更快地把资源推送给客户端。
即便如此,HTTP/2在往返时延(RTT)上仍存在问题,尤其是在移动网络方面。所以谷歌正在测试另一项协议,即QUIC;QUIC在TCP到UDP的网络转换上更加流畅。

3、OSCP stapling
在HTTPS通信过程时,浏览器通过CRL和OCSP来验证服务器端下发的证书链是否已经被撤销。
CA机构在CRL中列举在有效期内但是被撤销的数字证书,CA机构会维护并定期更新CRL列表,但随着时间的推移,体现出两个不足之处:
•CRL列表越来越大
•浏览器更新不及时的时候,会造成误判

OCSP是实时证书在线验证协议,用来弥补CRL机制的上述不足之处,通过OCSP浏览器可以实时向CA机构验证证书。但OCSP也有自身的弊端:
•要求CA机构实时全球高可用
•客户端的访问隐私可能被泄露
•增加浏览器的握手延时
于是,OCSP Stapling技术被开发出来,作为对OCSP协议缺陷的弥补,这个技术实现了服务器可以事先模拟浏览器对证书链进行验证,并将带有CA机构签名的OCSP验证结果响应保存到本地。等到真正的握手阶段,再将OCSP响应和证书链一起下发给浏览器,以此避免增加浏览器的握手延时。由于浏览器不需要直接向 CA 站点查询证书状态,这个功能对访问速度的提升非常明显。

4、Session ID
HTTPS访问过程是在TCP三次握手之后进行SSL的四次握手,如果一个业务请求包含多条的加密流,反复的握手请求势必会导致较高的延迟。并且如果出于某种原因,对话中断,就需要重新握手,增加了用户访问时间。
Session ID是一种在网络通信中使用(通常在一块数据的HTTP)来识别一个会话,具有一系列相关的信息交流。SessionID属性用于唯一地标识在服务器上包含会话数据的浏览器。
SessionID值由ASP.NET随机生成,并存储在浏览器的不过期Cookie中。每次向ASP.NET应用程序发送请求时,SessionID值便被发送到Cookie中。因此,session ID可以有效的减少多次访问时的握手次数,降低访问延迟。

5、SNI技术
过去,只有独立IP的虚拟主机或VPS才能享有SSL/TLS连接服务。在SSL握手的过程中,不会传递域名信息,所以服务器端通常返回的是配置中的第一个可用证书;如果要使用多个证书,就只能配置不同的SSL端口或增加IP地址,或者花重金使用一个“多域名SSL证书”或一个“通配型证书”来达到相同效果。
随着SNI技术的出现,在一个IP地址上可以为不同域名分配使用不同SSL证书的技术得以实现;这同时意味着,共享IP的虚拟主机也可实现SSL/TLS连接。
SNI技术的实现是用于改善SSL/TLS的技术,它可以在SSLv3/TLSv1中被启用。当SNI技术实现时,客户端可以在发起SSL握手请求时提交请求的Host信息,服务器接收到信息后,能够切换到正确的域,再返回相应的证书。
要使用SNI,需要客户端和服务器端同时满足条件,对于浏览器来说,大部分都支持SSLv3/TLSv1,所以都可以享受SNI带来的便利。对于服务器来说,Nginx在以SNI为支持的OpenSSL的陪同下即可实现。
以上就是实现HTTPS的5个技术难点,希望大家在进行HTTPS升级的时候,可以顺利实现。

 

 

数据加密
密码学中的密码(cipher)是一套算法(algorithm),这套算法用于对消息进行加密和解密,从明文到密文的过程称之为加密,密文反过来生成明文称之为解密,加密算法与解密算法合在一起称为密码算法。
哈希算法
将任意长度的信息转换为较短的固定长度的值,通常其长度要比信息小得多,且算法不可逆。例如:MD5、SHA-1、SHA-2、SHA-256 等

数字签名
签名就是在信息的后面再加上一段内容(信息经过hash后的值),可以证明信息没有被修改过。hash值一般都会加密后(也就是签名)再和信息一起发送,以保证这个hash值不被修改。
消息发送者 发邮件找 消息接收者 借 1 万钱,因为邮件可以被人篡改(改成 10 万),也可以被伪造(消息发送者 根本就没发邮件,而是 中间攻击者 伪造 消息发送者 在发邮件),消息发送者 借了钱之后还可以不承认(不是我借的,我没有签名啊)。
  消息认证码可以解决篡改和伪造的问题,消息发送者 不承认自己借了钱时,消息接收者 去找第三方机构做公正,即使这样,公正方也没法判断 消息发送者 有没有真的借钱,因为他们俩共享了密钥,也就是说两个都可以计算出正确的 MAC 值,消息接收者 说:“明明你发的消息和 MAC 值和我自己生成的 MAC 值一样,肯定是你发的消息”,消息发送者 说:“你把密钥透露给了其他人,是他发的邮件,你找他去吧”。消息发送者 矢口否认。
  数字签名(Digital Signature)就可以解决否认的问题,发送消息时,消息发送者 和 消息接收者 使用不同的密钥,把公钥加密算法反过来使用,发送者 消息发送者 使用私钥对消息进行签名,而且只能是拥有私钥的 消息发送者 可以对消息签名,消息接收者 用配对的公钥去验证签名,第三方机构也可以用公钥验证签名,如果验证通过,说明消息一定是 消息发送者 发送的,抵赖也不行,因为你只有 消息发送者 可以生成签名。这就防止了否认的问题。

它的流程是:
  第一步:发送者 消息发送者 把消息哈希函数处理生成消息摘要,摘要信息使用私钥加密之后生成签名,连同消息一起发送给接收者 消息接收者。
  第二步:数据经过网络传输,消息接收者 收到数据后,把签名和消息分别提取出来。
  第三步:对签名进行验证,验证的过程是先把消息提取出来做同样的 Hash 处理,得到消息摘要,再与 消息发送者 传过来的签名用公钥解密,如果两者相等,就表示签名验证成功,否则验证失败,表示不是 消息发送者 发的。
对称加密
对称密钥(Symmetric-key algorithm)又称为共享密钥加密,有流式、分组两种,加密和解密使用相同的密钥。常见的对称加密算法有 DES、3DES、AES、RC5、RC6。对称密钥的优点是计算速度快,但是它有缺点,接收者需要发送者告知密钥才能解密,因此密钥如何安全的发送给接收者成为了一个问题。
对称加密的意思就是,加密数据用的密钥,跟解密数据用的密钥是一样的。对称加密的优点在于加密、解密效率通常比较高。缺点在于,数据发送方、数据接收方需要协商、共享同一把密钥,并确保密钥不泄露给其他人。此外,对于多个有数据交换需求的个体,两两之间需要分配并维护一把密钥,这个带来的成本基本是不可接受的。

消息发送者 给 消息接收者 发送数据时,把数据用对称加密后发送给 消息接收者,发送过程中由于对数据进行了加密,因此即使有人窃取了数据也没法破解,因为它不知道密钥是什么。但是同样的问题是 消息接收者 收到数据后也一筹莫展,因为它也不知道密钥是什么,那么 消息发送者 是不是可以把数据和密钥一同发给 消息接收者 呢。当然不行,一旦把密钥和密钥一起发送的话,那就跟发送明文没什么区别了,因为一旦有人把密钥和数据同时获取了,密文就破解了。所以对称加密的密钥配是个问题。如何解决呢,公钥加密是一个办法。

 

非对称加密
加密使用的密钥和解密使用的密钥是不相同的,分别称为:公钥、私钥,公钥和算法都是公开的,私钥是保密的。非对称加密算法性能较低,但是安全性超强,非对称加密算法能加密的数据长度是有限的。例如:RSA、DSA、ECDSA、 DH、ECDHE
公开密钥加密(public-key cryptography)简称公钥加密,这套密码算法包含配对的密钥对,分为加密密钥和解密密钥。发送者用加密密钥进行加密,接收者用解密密钥进行解密。加密密钥是公开的,任何人都可以获取,因此加密密钥又称为公钥(public key),解密密钥不能公开,只能自己使用,因此它又称为私钥(private key)。常见的公钥加密算法有RSA。通过公钥加密的数据,只能通过私钥解开。通过私钥加密的数据,只能通过公钥解开。这点对于理解HTTPS的整套加密、授权体系非常关键。

还是以消息发送者给消息接收者发送数据为例,公钥加密算法由接收者消息接收者发起
消息接收者 生成公钥和私钥对,私钥自己保存,不能透露给任何人。
消息接收者 把公钥发送给 消息发送者,发送过程中即使被人窃取也没关系
消息发送者 用公钥把数据进行加密,并发送给 消息接收者,发送过程中被人窃取了同样没关系,因为没有配对的私钥进行解密是没法破解的
消息接收者 用配对的私钥解密。

虽然公钥加密解决了密钥配送的问题,但是你没法确认公钥是不是合法的,消息接收者 发送的公钥你不能肯定真的是 消息接收者 发的,因为也有可能在 消息接收者 把公钥发送给 消息发送者 的过程中出现中间人攻击,把真实的公钥掉包替换。而对于 消息发送者 来说完全不知。还有一个缺点是它的运行速度。非对称加密只能保证单向数据传输的安全性。此外,单纯使用公开密钥加密存在两个比较明显的问题。1、公钥如何获取2、数据传输仅单向安全

问题一:公钥如何获取
浏览器是怎么获得XX的公钥的?当然,小明可以自己去网上查,XX也可以将公钥贴在自己的主页。然而,这会给用户造成极大的不便利,毕竟大部分用户都不知道“公钥”是什么东西。这里要涉及两个非常重要的概念:证书、CA(证书颁发机构)。

1)证书
可以暂时把它理解为网站的身份证。这个身份证里包含了很多信息,其中就包含了上面提到的公钥。
也就是说,当小明、小王、小光等用户访问XX的时候,再也不用满世界的找XX的公钥了。当他们访问XX的时候,XX就会把证书发给浏览器,告诉他们说,乖,用这个里面的公钥加密数据。
这里有个问题,所谓的“证书”是哪来的?这就是下面要提到的CA负责的活了。
2)CA(证书颁发机构)
可以颁发证书的CA有很多(国内外都有)。只有少数CA被认为是权威、公正的,这些CA颁发的证书,浏览器才认为是信得过的。比如VeriSign。(CA自己伪造证书的事情也不是没发生过。)证书颁发的细节可以先简单理解为,网站向CA提交了申请,CA审核通过后,将证书颁发给网站,用户访问网站的时候,网站将证书给到用户。

问题二:数据传输仅单向安全
上面提到,通过私钥加密的数据,可以用公钥解密还原。那么这是不是就意味着,网站传给用户的数据是不安全的?确实是这样的,可能你心里会有这样想:用了HTTPS,数据还是裸奔,这么不靠谱还不如直接用HTTP来的省事。HTTPS虽然用到了公开密钥加密,但同时也结合了其他手段,如对称加密,来确保授权、加密传输的效率、安全性。概括来说,整个简化的加密通信的流程就是:
a小明访问XX,XX将自己的证书给到小明(其实是给到浏览器,小明不会有感知)
b浏览器从证书中拿到XX的公钥A
c浏览器生成一个只有自己自己的对称密钥B,用公钥A加密,并传给XX(其实是有协商的过程,这里为了便于理解先简化)
cXX通过私钥解密,拿到对称密钥B
e浏览器、XX 之后的数据通信,都用密钥B进行加密
注意:对于每个访问XX的用户,生成的对称密钥B理论上来说都是不一样的。比如小明、小王、小光,可能生成的就是B1、B2、B3.

 

 

数字证书
因为数字签名、摘要是证书防伪非常关键的武器。简单的来说,“摘要”就是对传输的内容,通过hash算法计算出一段固定长度的串(是不是联想到了文章摘要)。然后,在通过CA的私钥对这段摘要进行加密,加密后得到的结果就是“数字签名”。(这里提到CA的私钥,后面再进行介绍)。CA本身有自己的证书,称为“根证书”。这个“根证书”是用来证明CA的身份的,本质是一份普通的数字证书。浏览器通常会内置大多数主流权威CA的根证书。浏览器内置的CA的根证书包含了关键内容:CA的公钥。

CA(Certificate Authority),即证书认证机构,它的作用就是提供证书(即服务器证书,由域名、公司信息、序列号和签名信息组成)加强服务端和客户端之间信息交互的安全性,以及证书运维相关服务。任何个体/组织都可以扮演 CA 的角色,难的是你要能得到全世界各大操作系统、浏览器等的默认信任。能得到他们的默认信任,你也可以自己开一家CA公司了,这类证书通常叫做根证书。浏览器默认信任的 CA 大厂商有很多,比如 Symantec赛门铁克、Comodo、Godaddy、GolbalSign(百度微博等都是它签发的) 和 Digicert。

CA是数字证书管理机构,数字证书在广义上可分为:个人数字证书、单位数字证书、单位员工数字证书、服务器证书、VPN证书、WAP证书、代码签名证书和表单签名证书。SSL证书是数字证书的一种,CA签发SSL证书,SSL证书主要用于服务器(应用)的数据传输链路加密和身份认证,绑定网站域名,不同的产品对于不同价值的数据和要求不同的身份认证。


消息摘要
消息摘要(message digest)函数是一种用于判断数据完整性的算法,也称为散列函数或哈希函数,函数返回的值叫散列值,散列值又称为消息摘要或者指纹(fingerprint)。这种算法是一个不可逆的算法,因此你没法通过消息摘要反向推倒出消息是什么。所以它也称为单向散列函数。下载软件时如何确定是官方提供的完整版呢,如果有中间人在软件里面嵌入了病毒,你也不得而知。所以我们可以使用散列函数对消息进行运算,生成散列值,通常软件提供方会同时提供软件的下载地址和软件的散列值,用户把软件下载后在本地用相同的散列算法计算出散列值,与官方提供的散列值对比,如果相同,说明该软件是完成的,否则就是被人修改过了。常用的散列算法有 MD5、SHA。  
散列函数可以保证数据的完整性,识别出数据是否被篡改,但它并不能识别出数据是不是伪装的,因为中间人可以把数据和消息摘要同时替换,数据虽然是完整的,但真实数据被掉包了,接收者收到的并不是发送者发的,而是中间人的。消息认证是解决数据真实性的办法。认证使用的技术有消息认证码和数字签名。
  
消息认证码
消息认证码(message authentication code)是一种可以确认消息完整性并进行认证(消息认证是指确认消息来自正确的发送者)的技术,简称 MAC。消息认证码可以简单理解为一种与密钥相关的单向散列函数。消息发送者 给 消息接收者 发送消息前,先把共享密钥(key)发送给 消息接收者,消息发送者 把消息计算出 MAC 值,连同消息一起发送给 消息接收者,消息接收者 接收到消息和 MAC 值后,与本地计算得到 MAC 值对比,如果两者相同,就说明消息是完整的,而且可以确定是 消息发送者 发送的,没有中间人伪造。不过,消息认证码同样会遇到对称加密的密钥配送问题,因此解决密钥配送问题还是要采用公钥加密的方式。此外,消息认证码还有一个无法解决的问题,消息接收者 虽然可以识别出消息的篡改和伪装,但是 消息发送者 可以否认说:“我没发消息,应该是 消息接收者 的密钥被 中间攻击者 盗取了,这是 中间攻击者 发的吧”。消息发送者 这么说你还真没什么可以反驳的,那么如何防止 消息发送者 不承认呢,数字签名可以实现。


明文 --> hash运算 --> 摘要 --> 私钥加密 --> 数字签名

证书格式
1. 证书版本号(Version)
版本号指明X.509证书的格式版本,现在的值可以为:
1) 0: v1
2) 1: v2
3) 2: v3
也为将来的版本进行了预定义

2. 证书序列号(Serial Number)
序列号指定由CA分配给证书的唯一的"数字型标识符"。当证书被取消时,实际上是将此证书的序列号放入由CA签发的CRL中,这也是序列号唯一的原因。

3. 签名算法标识符(Signature Algorithm)
签名算法标识用来指定由CA签发证书时所使用的"签名算法"。算法标识符用来指定CA签发证书时所使用的:
1) 公开密钥算法
2) hash算法
example: sha256WithRSAEncryption
须向国际知名标准组织(如ISO)注册

4. 签发机构名(Issuer)
此域用来标识签发证书的CA的X.500 DN(DN-Distinguished Name)名字。包括:
1) 国家(C)
2) 省市(ST)
3) 地区(L)
4) 组织机构(O)
5) 单位部门(OU)
6) 通用名(CN)
7) 邮箱地址

5. 有效期(Validity)
指定证书的有效期,包括:1) 证书开始生效的日期时间2) 证书失效的日期和时间.每次使用证书时,需要检查证书是否在有效期内。

6. 证书用户名(Subject)
指定证书持有者的X.500唯一名字。包括:
1) 国家(C)
2) 省市(ST)
3) 地区(L)
4) 组织机构(O)
5) 单位部门(OU)
6) 通用名(CN)
7) 邮箱地址

7. 证书持有者公开密钥信息(Subject Public Key Info)
证书持有者公开密钥信息域包含两个重要信息:1) 证书持有者的公开密钥的值2) 公开密钥使用的算法标识符。此标识符包含公开密钥算法和hash算法。

8. 扩展项(extension)
X.509 V3证书是在v2的基础上一标准形式或普通形式增加了扩展项,以使证书能够附带额外信息。标准扩展是指由X.509 V3版本定义的对V2版本增加的具有广泛应用前景的扩展项,任何人都可以向一些权威机构,如ISO,来注册一些其他扩展,如果这些扩展项应用广泛,也许以后会成为标准扩展项。

9. 签发者唯一标识符(Issuer Unique Identifier)
签发者唯一标识符在第2版加入证书定义中。此域用在当同一个X.500名字用于多个认证机构时,用一比特字符串来唯一标识签发者的X.500名字。可选。

10. 证书持有者唯一标识符(Subject Unique Identifier)
持有证书者唯一标识符在第2版的标准中加入X.509证书定义。此域用在当同一个X.500名字用于多个证书持有者时,用一比特字符串来唯一标识证书持有者的X.500名字。可选。

11. 签名算法(Signature Algorithm)
证书签发机构对证书上述内容的签名算法example: sha256WithRSAEncryption

12. 签名值(Issuer's Signature)
证书签发机构对证书上述内容的签名值

完全伪造的证书
这种情况比较简单,对证书进行检查:
a证书颁发的机构是伪造的:浏览器不认识,直接认为是危险证书
b证书颁发的机构是确实存在的,于是根据CA名,找到对应内置的CA根证书、CA的公钥。
c用CA的公钥,对伪造的证书的摘要进行解密,发现解不了。认为是危险证书

篡改过的证书
假设代理通过某种途径,拿到XX的证书,然后将证书的公钥偷偷修改成自己的,然后喜滋滋的认为用户要上钩了。然而太单纯了:
a检查证书,根据CA名,找到对应的CA根证书,以及CA的公钥。
b用CA的公钥,对证书的数字签名进行解密,得到对应的证书摘要AA
c根据证书签名使用的hash算法,计算出当前证书的摘要BB
d对比AA跟BB,发现不一致--> 判定是危险证书

如何保证公钥不被篡改

将公钥放在数字证书中。只要证书是可信的,公钥就是可信的。那如何保证证书可信呢?证书的生成都是由国际顶级认证机构签发的,签发的时候必须验证你是不是这个域名的所有者,只有是才给你签发证书(证书和域名一一挂钩),所以理论上其他人无法伪造你的证书(只是理论上),即使伪造了,浏览器在加载的时候会进行域名校验,如果证书中的域名和实际域名不匹配,浏览器是会警告的。浏览器怎么知道你的证书是不是合法的国际顶级认证机构签发的呢?操作系统和浏览器都内置了一些他们认为可信任的国际顶级认证机构(CA),只有他们签发的证书浏览器才信任。
如何查看操作系统内置了哪些CA呢?Internet选项->内容->证书->受信任的根证书颁发机构:

 

想让你的https网站默认情况下就被全世界浏览器信任你必须使用它们签发的证书,大部分都是要钱的,当然也有免费的

SSL证书
证书的种类
SSL 证书按大类一般可分为DV SSL 、OV SSL、EV SSL证书,又叫域名型、企业型、增强型证书:

 

DV SSL(Domain Validation),域名型SSL证书,证书颁布机构只对域名的所有者进行在线检查,只要你能证明你是这个域名的所有者就可以给你颁发证书,不会校验网站的资质,哪怕你是个黄赌毒网站也可以,个人网站、非盈利项目、开源项目等用域名型证书足矣;
OV SSL(Organization Validation),企业型SSL证书,需要购买者提交组织机构资料和单位授权信等在官方注册的凭证,证书颁发机构在签发 SSL 证书前不仅仅要检验域名所有权,还必须对这些资料的真实合法性进行多方查验,只有通过验证的才能颁发 SSL 证书;
EV SSL(Extended Validation),增强型SSL证书(EV SSL),验证流程更加具体详细,验证步骤更多,这样一来证书所绑定的网站就更加的可靠、可信。它跟普通SSL证书的区别是浏览器的地址栏变绿,如果是不受信的 SSL 证书则拒绝显示,如果是钓鱼网站,地址栏则会变成红色,以警示用户。

不论是 DV、OV 还是 EV 证书,其加密效果都是一样的,个人网站用DV证书、企业用OV足够了。如何查看证书类型?如下图,百度是OV,github是EV(其实好像并没有统一的区分方法,有的证书不会写):

 

证书的格式
一般来说,主流的 Web 服务软件,通常都基于 OpenSSL 和 Java 两种基础密码库。
●Tomcat、Weblogic、JBoss等Web服务软件,一般使用JDK自带的Keytool工具,生成Java Keystore(JKS)格式的证书文件。
●Apache、Nginx等Web服务软件,一般使用OpenSSL工具提供的密码库,生成 .key、.crt等格式的证书文件。
●IBM 的 Web 服务产品,如 Websphere、IBM Http Server(IHS)等,一般使用 IBM 产品自带的 iKeyman 工具,生成 KDB 格式的证书文件。
●微软的IIS使用Windows自带的证书库生成pfx格式的证书文件。
详见下图:

每种格式之间都可以相互转换,在腾讯云申请证书的时候会自动帮你生成4种服务器各自需要的格式,非常方便。
不是说收费的证书就一定比免费证书好,只不过现阶段各CA机构为了自己的盈利目的,免费证书一般都有一些限制,比如只支持单域名,子域名太多的话需要挨个申请。

 

转载于:https://www.cnblogs.com/tester-l/p/8560141.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值