熟悉了对称加密与非对称加密、数字签名与证书等密码学知识。就能够正式开始研究 HTTPS 和 TLS 协议了。算法
当你在浏览器地址栏里键入“https”开头的 URI,再按下回车,会发生什么呢?浏览器
你应该知道,浏览器首先要从 URI 里提取出协议名和域名。由于协议名是“https”,因此浏览器就知道了端口号是默认的 443,它再用 DNS 解析域名,获得目标的 IP 地址,而后就可使用三次握手与网站创建 TCP 链接了。安全
在 HTTP 协议里,创建链接后,浏览器会当即发送请求报文。但如今是 HTTPS 协议,它须要再用另一个“握手”过程,在 TCP 上创建安全链接,以后才是收发 HTTP 报文。bash
这个“握手”过程与 TCP 有些相似,是 HTTPS 和 TLS 协议里最重要、最核心的部分,懂了它,你就能够自豪地说本身“掌握了 HTTPS”。服务器
先简单介绍一下 TLS 协议的组成。dom
TLS 包含几个子协议,你也能够理解为它是由几个不一样职责的模块组成,比较经常使用的有记录协议、警报协议、握手协议、变动密码规范协议等。网站
记录协议(Record Protocol)规定了 TLS 收发数据的基本单位:记录(record)。它有点像是 TCP 里的 segment,全部的其余子协议都须要经过记录协议发出。但多个记录数据能够在一个 TCP 包里一次性发出,也并不须要像 TCP 那样返回 ACK。ui
警报协议(Alert Protocol)的职责是向对方发出警报信息,有点像是 HTTP 协议里的状态码。好比,protocol_version 就是不支持旧版本,bad_certificate 就是证书有问题,收到警报后另外一方能够选择继续,也能够当即终止链接。加密
握手协议(Handshake Protocol)是 TLS 里最复杂的子协议,要比 TCP 的 SYN/ACK 复杂的多,浏览器和服务器会在握手过程当中协商 TLS 版本号、随机数、密码套件等信息,而后交换证书和密钥参数,最终双方协商获得会话密钥,用于后续的混合加密系统。spa
变动密码规范协议(Change Cipher Spec Protocol),它很是简单,就是一个“通知”,告诉对方,后续的数据都将使用加密保护。那么反过来,在它以前,数据都是明文的。
下面的这张图简要地描述了 TLS 的握手过程,其中每个“框”都是一个记录,多个记录组合成一个 TCP 包发送。因此,最多通过两次消息往返(4 个消息)就能够完成握手,而后就能够在安全的通讯环境里发送 HTTP 报文,实现 HTTPS 协议。
刚才的是握手过程的简要图,这里有一个详细图
在 TCP 创建链接以后,浏览器会首先发一个“Client Hello”消息,也就是跟服务器“打招呼”。里面有客户端的版本号、支持的密码套件,还有一个随机数(Client Random),用于后续生成会话密钥。
Handshake Protocol: Client Hello
Version: TLS 1.2 (0x0303)
Random: 1cbf803321fd2623408dfe…
Cipher Suites (17 suites)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
复制代码
服务器收到“Client Hello”后,会返回一个“Server Hello”消息。把版本号对一下,也给出一个随机数(Server Random),而后从客户端的列表里选一个做为本次通讯使用的密码套件,在这里它选择了“TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384”。
Handshake Protocol: Server Hello
Version: TLS 1.2 (0x0303)
Random: 0e6320f21bae50842e96…
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
复制代码
这个的意思就是:“版本号对上了,能够加密,你的密码套件挺多,我选一个最合适的吧,用椭圆曲线加 RSA、AES、SHA384。我也给你一个随机数,你也得留着。”
而后,服务器为了证实本身的身份,就把证书也发给了客户端(Server Certificate)。
接下来是一个关键的操做,由于服务器选择了 ECDHE 算法,因此它会在证书后发送“Server Key Exchange”消息,里面是椭圆曲线的公钥(Server Params),用来实现密钥交换算法,再加上本身的私钥签名认证。
Handshake Protocol: Server Key Exchange
EC Diffie-Hellman Server Params
Curve Type: named_curve (0x03)
Named Curve: x25519 (0x001d)
Pubkey: 3b39deaf00217894e...
Signature Algorithm: rsa_pkcs1_sha512 (0x0601)
Signature: 37141adac38ea4...
复制代码
这至关于说:“刚才我选的密码套件有点复杂,因此再给你个算法的参数,和刚才的随机数同样有用,别丢了。为了防止别人冒充,我又盖了个章。”
以后是“Server Hello Done”消息,服务器说:“个人信息就是这些,打招呼完毕。”
这样第一个消息往返就结束了(两个 TCP 包),结果是客户端和服务器经过明文共享了三个信息:Client Random、Server Random 和 Server Params。
客户端这时也拿到了服务器的证书,那这个证书是否是真实有效的呢?
走证书链逐级验证,确认证书的真实性,再用证书公钥验证签名,就确认了服务器的身份:“刚才跟我打招呼的不是骗子,能够接着往下走。”
而后,客户端按照密码套件的要求,也生成一个椭圆曲线的公钥(Client Params),用“Client Key Exchange”消息发给服务器。
Handshake Protocol: Client Key Exchange
EC Diffie-Hellman Client Params
Pubkey: 8c674d0e08dc27b5eaa…
复制代码
如今客户端和服务器手里都拿到了密钥交换算法的两个参数(Client Params、Server Params),就用 ECDHE 算法一阵算,算出了一个新的东西,叫“Pre-Master”,其实也是一个随机数。
如今客户端和服务器手里有了三个随机数:Client Random、Server Random 和 Pre-Master。用这三个做为原始材料,就能够生成用于加密会话的主密钥,叫“Master Secret”。而黑客由于拿不到“Pre-Master”,因此也就得不到主密钥。
为何非得这么麻烦,非要三个随机数呢?
这就必须说 TLS 的设计者考虑得很是周到了,他们不信任客户端或服务器伪随机数的可靠性,为了保证真正的“彻底随机”“不可预测”,把三个不可靠的随机数混合起来,那么“随机”的程度就很是高了,足够让黑客难以猜想。
有了主密钥和派生的会话密钥,握手就快结束了。客户端发一个“Change Cipher Spec”,而后再发一个“Finished”消息,把以前全部发送的数据作个摘要,再加密一下,让服务器作个验证。
意思就是告诉服务器:“后面都改用对称算法加密通讯了啊,用的就是打招呼时说的 AES,加密对不对还得你测一下。”
服务器也是一样的操做,发“Change Cipher Spec”和“Finished”消息,双方都验证加密解密 OK,握手正式结束,后面就收发被加密的 HTTP 请求和响应了。
上面说的是“单向认证”握手过程,只认证了服务器的身份,而没有认证客户端的身份。这是由于一般单向认证经过后已经创建了安全通讯,用帐号、密码等简单的手段就可以确认用户的真实身份。
但为了防止帐号、密码被盗,有的时候(好比网上银行)还会使用 U 盾给用户颁发客户端证书,实现“双向认证”,这样会更加安全。
双向认证的流程也没有太多变化,只是在“Server Hello Done”以后,“Client Key Exchange”以前,客户端要发送“Client Certificate”消息,服务器收到后也把证书链走一遍,验证客户端的身份。
内容比较多、比较难,不过记住下面四点就能够