应用层之HTTPS协议
Last updated
Last updated
Https(Hyper Text Transfer Protocol over Secure Socket Layer)
,是一种基于SSL/TLS
的Http
,所有的http
数据都是在SSL/TLS
协议封装之上传输的。Https
协议在Http
协议的基础上,添加了SSL/TLS
握手以及数据加密传输,也属于应用层协议。所以,研究Https
协议原理,最终其实是研究SSL/TLS
协议。
SSL/TLS
协议SSL
协议,是一种安全传输协议,最初是由Netscape
在1996年发布,由于一些安全的原因SSL v1.0
和SSL v2.0
都没有公开,直到1996年的SSL v3.0
。TLS
是SSL v3.0
的升级版,1999年,互联网标准化组织ISOC
接替NetScape
公司发布了TLS 1.0
版。2006年和2008年,进行了两次升级,分别为TLS 1.1
版和TLS 1.2
版,最新的变动是2011年TLS 1.2
的修订版。目前市面上所有的Https
都是用的是TLS
,而不是SSL
。
从协议内部的功能层面上来看,SSL/TLS
协议可分为两层:
1.SSL/TLS
记录协议(SSL/TLS Record Protocol
),它建立在可靠的传输层协议(如 TCP
)之上,为上层协议提供数据封装、压缩、加密等基本功能。
2.SSL/TLS
握手协议(SSL/TLS Handshake Protocol
),它建立在 SSL/TLS
记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等初始化协商功能。
从协议使用方式来看,又可以分成两种类型:
1.SSL/TLS
单向认证,就是用户到服务器之间只存在单方面的认证,即客户端会认证服务器端身份,而服务器端不会去对客户端身份进行验证。首先,客户端发起握手请求,服务器收到握手请求后,会选择适合双方的协议版本和加密方式。然后,再将协商的结果和服务器端的公钥一起发送给客户端。客户端利用服务器端的公钥,对要发送的数据进行加密,并发送给服务器端。服务器端收到后,会用本地私钥对收到的客户端加密数据进行解密。然后,通讯双方都会使用这些数据来产生双方之间通讯的加密密钥。接下来,双方就可以开始安全通讯过程了。
2.SSL/TLS
双向认证,就是双方都会互相认证,也就是两者之间将会交换证书。基本的过程和单向认证完全一样,只是在协商阶段多了几个步骤。在服务器端将协商的结果和服务器端的公钥一起发送给客户端后,会请求客户端的证书,客户端则会将证书发送给服务器端。然后,在客户端给服务器端发送加密数据后,客户端会将私钥生成的数字签名发送给服务器端。而服务器端则会用客户端证书中的公钥来验证数字签名的合法性。建立握手之后过程则和单向通讯完全保持一致。
TLS
握手TLS
的握手阶段是发生在TCP
握手之后。握手实际上是一种协商的过程,对协议所必需的一些参数进行协商。TLS
握手过程分为四步,过程如下:(备注:图中加方括号的均为可选消息)
由于客户端(如浏览器)对一些加解密算法的支持程度不一样,但是在TLS
协议传输过程中必须使用同一套加解密算法才能保证数据能够正常的加解密。在TLS
握手阶段,客户端首先要告知服务端,自己支持哪些加密算法,所以客户端需要将本地支持的加密套件(Cipher Suite
)的列表传送给服务端。除此之外,客户端还要产生一个随机数,这个随机数一方面需要在客户端保存,另一方面需要传送给服务端,客户端的随机数需要跟服务端产生的随机数结合起来产生Master Secret
。
上图中,从Server Hello
到Server Done
,有些服务端的实现是每条单独发送,有服务端实现是合并到一起发送。Sever Hello
和Server Done
都是只有头没有内容的数据。
服务端在接收到客户端的Client Hello
之后,服务端需要将自己的证书发送给客户端。这个证书是对于服务端的一种认证。例如,客户端收到了一个来自于称自己是www.alipay.com
的数据,但是如何证明对方是合法的alipay
支付宝呢?这就是证书的作用,支付宝的证书可以证明它是alipay
,而不是财付通。证书是需要申请,并由专门的数字证书认证机构(CA)通过非常严格的审核之后颁发的电子证书。颁发证书的同时会产生一个私钥和公钥。私钥由服务端自己保存,不可泄漏。公钥则是附带在证书的信息中,可以公开的。证书本身也附带一个证书电子签名,这个签名用来验证证书的完整性和真实性,可以防止证书被串改。另外,证书还有个有效期。
在服务端向客户端发送的证书中没有提供足够的信息的时候,还可以向客户端发送一个Server Key Exchange
。
此外,对于非常重要的保密数据,服务端还需要对客户端进行验证,以保证数据传送给了安全的合法的客户端。服务端可以向客户端发出Cerficate Request
消息,要求客户端发送证书对客户端的合法性进行验证。跟客户端一样,服务端也需要产生一个随机数发送给客户端。客户端和服务端都需要使用这两个随机数来产生Master Secret
。
最后服务端会发送一个Server Hello Done
消息给客户端,表示Server Hello
消息结束了。
如果服务端需要对客户端进行验证,在客户端收到服务端的Server Hello
消息之后,首先需要向服务端发送客户端的证书,让服务端来验证客户端的合法性。
在此之前的所有TLS
握手信息都是明文传送的。在收到服务端的证书等信息之后,客户端会使用一些加密算法(例如:RSA, Diffie-Hellman
)产生一个48个字节的Key
,这个Key
叫PreMaster Secret
,很多材料上也被称作PreMaster Key
,最终通过Master secret
生成session secret
, session secret
就是用来对应用数据进行加解密的。PreMaster secret
属于一个保密的Key,只要截获PreMaster secret
,就可以通过之前明文传送的随机数,最终计算出session secret
,所以PreMaster secret
使用RSA
非对称加密的方式,使用服务端传过来的公钥进行加密,然后传给服务端。
接着,客户端需要对服务端的证书进行检查,检查证书的完整性以及证书跟服务端域名是否吻合。
ChangeCipherSpec
是一个独立的协议,体现在数据包中就是一个字节的数据,用于告知服务端,客户端已经切换到之前协商好的加密套件的状态,准备使用之前协商好的加密套件加密数据并传输了。在ChangecipherSpec
传输完毕之后,客户端会使用之前协商好的加密套件和session secret加密一段Finish
的数据传送给服务端,此数据是为了在正式传输应用数据之前对刚刚握手建立起来的加解密通道进行验证。
服务端在接收到客户端传过来的PreMaster
加密数据之后,使用私钥对这段加密数据进行解密,并对数据进行验证,也会使用跟客户端同样的方式生成session secret
,一切准备好之后,会给客户端发送一个ChangeCipherSpec
,告知客户端已经切换到协商过的加密套件状态,准备使用加密套件和session secret
加密数据了。之后,服务端也会使用session secret
加密后一段Finish
消息发送给客户端,以验证之前通过握手建立起来的加解密通道是否成功。
根据之前的握手信息,如果客户端和服务端都能对Finish
信息进行正常加解密且消息正确的被验证,则说明握手通道已经建立成功,接下来,双方可以使用上面产生的session secret
对数据进行加密传输了。
服务器也可以要求验证客户端,即双向认证,可以在过程2要发送
client_certificate_request
信息,客户端在过程4中先发送client_certificate
与certificate_verify_message
信息,证书的验证方式基本相同,certificate_verify_message
是采用client的私钥加密的一段基于已经协商的通信信息得到数据,服务器可以采用对应的公钥解密并验证;根据使用的密钥交换算法的不同,如
ECC
等,协商细节略有不同,总体相似;
sever key exchange
的作用是server certificate
没有携带足够的信息时,发送给客户端以计算pre-master
,如基于 DH 的证书,公钥不被证书中包含,需要单独发送;
change cipher spec
实际可用于通知对端改版当前使用的加密通信方式,当前没有深入解析;
alter message
用于指明在握手或通信过程中的状态改变或错误信息,一般告警信息触发条件是连接关闭,收到不合法的信息,信息解密失败,用户取消操作等,收到告警信息之后,通信会被断开或者由接收方决定是否断开连接。
PreMaster secret
PreMaster secret
是在客户端使用RSA
或者Diffie-Hellman
等加密算法生成的。它将用来跟服务端和客户端在Hello
阶段产生的随机数结合在一起生成Master secret
。在客户端使用服务单的公钥对PreMaster secret
进行加密之后传送给服务端,服务端将使用私钥进行解密得到PreMaster secret
。也就是说服务端和客户端都有一份相同的PreMaster secret
和随机数。
PreMaster secret
前两个字节是TLS
的版本号,这是一个比较重要的用来核对握手数据的版本号,因为在Client Hello
阶段,客户端会发送一份加密套件列表和当前支持的SSL/TLS
的版本号给服务端,而且是使用明文传送的,如果握手的数据包被破解之后,攻击者很有可能串改数据包,选择一个安全性较低的加密套件和版本给服务端,从而对数据进行破解。所以,服务端需要对密文中解密出来对的PreMaster
版本号跟之前Client Hello
阶段的版本号进行对比,如果版本号变低,则说明被串改,则立即停止发送任何消息。
Master secret
上面已经提到,由于服务端和客户端都有一份相同的PreMaster secret
和随机数,这个随机数将作为后面产生Master secret
的种子,结合PreMaster secret
,客户端和服务端将计算出同样的Master secret
。
Master secret
是有系列的hash
值组成的,它将作为数据加解密相关的secret
的Key Material
。Master secret
最终解析出来的数据如下:
其中,write MAC key
,就是session secret
或者说是session key
。Client write MAC key
是客户端发数据的session secret
,Server write MAC secret
是服务端发送数据的session key
。MAC(Message Authentication Code)
,是一个数字签名,用来验证数据的完整性,可以检测到数据是否被串改。
握手阶段用来建立SSL
连接。如果出于某种原因,对话中断,就需要重新握手。
这时有两种方法可以恢复原来的session
:一种叫做session ID
,另一种叫做session ticket
。这是TLS
协议的两类会话缓存机制。
session ID
的思想很简单,就是每一次对话都有一个编号(session ID
)。如果对话中断,下次重连的时候,只要客户端给出这个编号,且服务器有这个编号的记录,双方就可以重新使用已有的"对话密钥",而不必重新生成一把。
session ID
是目前所有浏览器都支持的方法,但是它的缺点在于session ID
往往只保留在一台服务器上。所以,如果客户端的请求发到另一台服务器,就无法恢复对话。session ticket
就是为了解决这个问题而诞生的,目前只有Firefox和Chrome浏览器支持。session ticket
是加密的,只有服务器才能解密,其中包括本次对话的主要信息,比如对话密钥和加密方法。当服务器收到session ticket
以后,解密后就不必重新生成对话密钥了。
如果客户端和服务器之间曾经建立了连接,服务器会在握手成功后返回 session ID
,并保存对应的通信参数在服务器中;
如果客户端再次需要和该服务器建立连接,则在 client_hello
中 session ID
中携带记录的信息,发送给服务器;
服务器根据收到的 session ID
检索缓存记录,如果没有检索到货缓存过期,则按照正常的握手过程进行;
如果检索到对应的缓存记录,则返回 change_cipher_spec
与 encrypted_handshake_message
信息,两个信息作用类似,encrypted_handshake_message
是到当前的通信参数与 master_secret
的hash
值;
如果客户端能够验证通过服务器加密数据,则客户端同样发送 change_cipher_spec
与 encrypted_handshake_message
信息;
服务器验证数据通过,则握手建立成功,开始进行正常的加密数据通信。
如果客户端和服务器之间曾经建立了连接,服务器会在 new_session_ticket
数据中携带加密的 session_ticket
信息,客户端保存;
如果客户端再次需要和该服务器建立连接,则在 client_hello
中扩展字段 session_ticket
中携带加密信息,一起发送给服务器;
服务器解密 sesssion_ticket
数据,如果能够解密失败,则按照正常的握手过程进行;
如果解密成功,则返回 change_cipher_spec
与 encrypted_handshake_message
信息,两个信息作用与 session ID
中类似;
如果客户端能够验证通过服务器加密数据,则客户端同样发送 change_cipher_spec
与encrypted_handshake_message
信息;
服务器验证数据通过,则握手建立成功,开始进行正常的加密数据通信。
重建连接 renegotiation
即放弃正在使用的 TLS
连接,从新进行身份认证和密钥协商的过程,特点是不需要断开当前的数据传输就可以重新身份认证、更新密钥或算法,因此服务器端存储和缓存的信息都可以保持。
服务器端重建连接一般情况是客户端访问受保护的数据时发生。基本过程如下:
客户端和服务器之间建立了有效 TLS
连接并通信;
客户端访问受保护的信息;
服务器端返回 hello_request
信息;
客户端收到 hello_request
信息之后发送 client_hello
信息,开始重新建立连接。
客户端重建连接一般是为了更新通信密钥。
客户端和服务器之间建立了有效 TLS
连接并通信;
客户端需要更新密钥,主动发出 client_hello
信息;
服务器端收到 client_hello
信息之后无法立即识别出该信息非应用数据,因此会提交给下一步处理,处理完之后会返回通知该信息为要求重建连接;
在确定重建连接之前,服务器不会立即停止向客户端发送数据,可能恰好同时或有缓存数据需要发送给客户端,但是客户端不会再发送任何信息给服务器;
服务器识别出重建连接请求之后,发送 server_hello
信息至客户端;
客户端也同样无法立即判断出该信息非应用数据,同样提交给下一步处理,处理之后会返回通知该信息为要求重建连接;
客户端和服务器开始新的重建连接的过程。
前文讨论了HTTPS
原理与优势:身份验证、信息加密与完整性校验等,且未对TCP
和HTTP
协议做任何修改。但通过增加新协议以实现更安全的通信必然需要付出代价,HTTPS
协议的性能损耗主要体现如下:
消耗较多的CPU资源 :除数据传输之外,HTTPS
通信主要包括对对称加解密、非对称加解密(服务器主要采用私钥解密数据),RSA
的解密能力是困扰HTTPS
接入的主要难题。
CDN
接入 HTTPS
增加的延时主要是传输延时 RTT
,RTT
的特点是节点越近延时越小,CDN(Content Delivery Network)
天然离用户最近,因此选择使用 CDN
作为 HTTPS
接入的入口,将能够极大减少接入延时。CDN
节点通过和业务服务器维持长连接、会话复用和链路质量优化等可控方法,极大减少 HTTPS
带来的延时。
虽然前文提到 HTTPS
即使采用会话缓存也要至少1*RTT
的延时,但是至少延时已经减少为原来的一半,明显的延时优化;同时,基于会话缓存建立的 HTTPS
连接不需要服务器使用RSA
私钥解密获取 Pre-master
信息,可以省去CPU 的消耗。如果业务访问连接集中,缓存命中率高,则HTTPS
的接入能力讲明显提升。
为接入服务器安装专用的SSL
硬件加速卡,作用类似 GPU,释放 CPU,能够具有更高的 HTTPS
接入能力且不影响业务程序的。
本地接入消耗过多的 CPU 资源,浪费了网卡和硬盘等资源,考虑将最消耗 CPU 资源的RSA
解密计算任务转移到其它服务器,如此则可以充分发挥服务器的接入能力,充分利用带宽与网卡资源。远程解密服务器可以选择 CPU 负载较低的机器充当,实现机器资源复用,也可以是专门优化的高计算性能的服务器。当前 CDN
是用于大规模HTTPS
接入的解决方案之一。
SPDY/HTTP2
前面的方法分别从减少传输延时和单机负载的方法提高 HTTPS
接入性能,但是方法都基于不改变 HTTP 协议的基础上提出的优化方法,SPDY/HTTP2
利用 TLS/SSL
带来的优势,通过修改协议的方法来提升 HTTPS
的性能,提高下载速度等。
Https
与Http
的区别1、https
协议需要到CA申请证书,一般免费证书较少,因而需要一定费用。
2、http
是超文本传输协议,信息是明文传输,https
则是具有安全性的ssl/tls
加密传输协议。
3、http
和https
使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http
的连接很简单,是无状态的;HTTPS
协议是由SSL/TLS+HTTP
协议构建的可进行加密传输、身份认证的网络协议,比http
协议安全。
HTTPS
方式与Web服务器通信时的步骤客户使用https
的URL访问Web服务器,要求与Web服务器建立SSL
连接。
Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
客户端的浏览器与Web服务器开始协商SSL/TLS
连接的安全等级,也就是信息加密的等级。
客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。
Web服务器利用自己的私钥解密出会话密钥。
Web服务器利用会话密钥加密与客户端之间的通信。
CA证书的相关内容见网络与安全部分。
增加延时 :分析前面的握手过程,一次完整的握手至少需要两端依次来回两次通信,至少增加延时 ,利用会话缓存从而复用连接,延时也至少 。