HTTPS原理简单介绍

  HTTPS在今后的互联网中必将扮演者越来越重要的角色了,国外互联网大佬对https部署也是竭力鼓吹呐喊,HTTP/2协议的推广更是逼着你不上也得上!在HTTPS普及化过程中,必然会损害某些集团的利益,但是这是互联网的趋势,历史的洪流是谁也阻挡不了的!
  这篇文章就是对HTTPS的大概做一个了解,力图宏观上掌握其基本原理和流程,而其中涉及到的具体加密算法的细节之流就留给那些博士title的人研究去吧!
  还是一样,要用Wireshark抓取和分析SSL/TLS的数据包,需要设置电脑的SSLKEYLOGFILE环境变量才可以。在Windows上面搞了好久,发现抓到的数据包还是不能解密,最后在Ubuntu下一次就完成了,看来搞开发的话还要Linux算是神器啊!抓取的数据包和Master-Secret也打包共享给大家了。此外为了简单起见,客户端请求禁用了Diffie Hellman支持,这个算法是为了提高安全性考虑的,好处就是密钥可以独立于服务器的私钥,所以历史数据即使在私钥被窃取的情况下,会话的内容也无法被破解。HTTPS抓包分析还是挺麻烦的,所以我们开发时候对于测试环境都是用的HTTP环境以便于调试分析,等系统完备之后再上HTTPS环境,反正整个协议对上层来说是透明的。
https
  上面展现的客户端和服务器整个通信过程尽收眼底:首先三次握手建立TCP连接,然后客户端发起HTTP请求并得到302跳转,客户端进行ACK确认后,转而向443端口进行TCP三次握手连接,接下来就是TLS协商,加密信道建立后采用加密方式进行数据的传输。流程中夹杂着TLS和TCP的数据包,这一点也不奇怪,因为ACK是TCP协议的特性哦!

一、HTTPS和TLS简介

  说到HTTPS,其实他代表着运行在SSL/TLS之上的HTTP,TLS是把SSL标准化之后的产物,因为SSL 3.0有安全漏洞,所以互联网大佬们都提倡禁用SSL 3.0,因此推荐在你的Apache/Nginx等ssl_protocols的配置中,取消对于SSLv3及其更低版本SSLv2的支持。在协议中,TLS 1.0通常被标示为SSL 3.1,TLS 1.1为SSL 3.2,TLS 1.2为SSL 3.3,这点在抓取的数据包的头部可以看出来。
  TLS协议的一个优势,就是它是与应用层协议独立无关的,他的目的就是在通信双方在不可信的网络之上建立一个加密的通道用来安全地传输数据,因此上层的HTTP、FTP、SMTP和IMAP(使用STARTTLS)等应用层协议都可以透明的建立在TLS之上以满足可信通信的需求。
  互联网是开放的但也是不安全的,尤其是上个世纪设计出来的大量网络应用协议都是text模式的,这让心怀不轨的人随便截获数据包就可以查看分析,作恶的成本十分的低。曾经在以前公司做入职培训作业的时候,发现公司Exchange邮件服务器+Foxmail客户端的通信都是明文的,抓包中可以看到同网段中其他同事的邮箱账户和密码(不相信做网络的公司运维水平会如此之差,或者是某些目的故意而为之吧)。HTTP协议也是text模式的,所以如果你不用HTTPS上网,可能遇到的问题有:
  (1). 上网过程裸奔:你的上网记录可以被监控,HTTP头部信息和Cookie被一览无余,如果传输的内容没有经过加密处理,那么你的东西也会被别人截获查看,帐号密码啥的全都不保,而且你对此丝毫没有察觉。还有些防火墙样的东西,一旦发现你想看不该让你看到的东西,就可以直接把你的连接掐掉。
  (2). 返回数据被篡改:不知道这锅该不该甩给运营商,很多时候请求的资源总会弹出些乱七八糟的东西,下载个东西有时候是比葫芦娃还恐怖的木马,这点尤其在移动端更为的猖獗。因为HTTP的协议就这样,你给服务端一个请求,服务端就给你一个返回,而对返回的内容根本无法辨识和校验,就这么个东西爱要不要,这样在网页中插入几段广告,或者把下载的文件中途给换掉,你根本无法辨别。
  不过有一点,HTTP请求的话很方便做缓存,好的缓存对大家都有益处,可以节省带宽,同时也加快访问者的响应速度;还有比如中间传递者可以针对访问用户进行特定的转码优化。不过这一切都基于良性驱动的,恶意插入和推广的行径应当被谴责!
  所以负责任的网站在提供文件的下载连接的同时,还要提供MD5/SHA1散列码给用户验证,甚至对其进行数字签名。
  (3). 中间人攻击:这个就更恶劣了,你甚至不知道是不是在和真正的主机在通信,你只是发出请求然后接受应答,数据包通过明文不知中转了多少台设备,任何环节中间插入个第三者帮你和服务器之间中间传话,听着是不是就惊悚?
  对此,你能做的就是保护自己,所有的网络通信都要加密:HTTP要加密,邮件本身要加密,邮件的传输也要加密,DNS也要加密……为的不是防君子,而是防小人。

二、TLS认证过程

  这个过程首先普及一点加密的知识。就像当初在GnuPG中描述的一样,加密机制可以分为非对称加密和对称加密两种:
  非对称加密:会产生一对公钥和私钥,公钥公开发布到网上,私钥锁在自己保险柜中,用公钥加密的东西只能由私钥解密,用私钥签名的东西只能用公钥验证,注意我的措辞也概括了公钥和私钥的使用方式。一把非对称密钥只能实现一个方向的加密通信,要想实现双向加密通信,就必须通信的双方分别使用对方的公钥进行加密,然后再由对方用自己的私密接钥来实现。
  对称加密:双方拥有相同的密钥,该密钥可以用于加密,也可以用于解密,所以这个密钥是不能被公开或者猜测到的。对称加密又分为块加密和流加密,前者只能对定长的数据块进行加密,所以通常要对待加密数据进行padding操作;流加密可以对任意长的数据进行加密,一般明文和加密结果是一样的长度。两者比较块加密的效率要高得多,可以使用CPU的高级指令高效运算,但是padding就需要记录原始数据的长度,实现起来麻烦一些。
  老实说来,当时我一看完openssl支持的加密种类中,就知道先用非对称加密传输对称密钥,后续的通信使用对称加密(AES)的方式进行,后者的运算效率会比前者高很多(在一台每秒可进行千万次对称加密计算的电脑上,只能支持每秒几千次的非对称加密计算),只要保证在每次会话中产生强随机性的密钥,就能让通信的可靠性大大的增加。如果通信双方都采用非对称加密的方式进行,那么服务端要收集庞大的用户公钥,这显然是不现实的。
  下面这张图是从RFC中拷贝过来的,描述了TLS加密通信建立的过程:
https-step
  (1). Client Hello
  这个是客户端主动向服务端发送的第一个消息,主要产生的信息:Version、Random、Session ID、Cipher Suites、Compression Methods。
https-step
  Random由一个4字节的GMT Unix Time和28字节的随机串组成,前者是从Jan 1, 1970, UTC开始到现在所经过的秒数,不过奇怪的是访问我的Apache服务器返回的时间都像是随机的,而Google的服务器返回的值是正常的(不过RFC不强制该时间是准确的),请忽略图中值,他们共同组成一个32位的随机串供后面使用;如果短时间之前连接过相同服务器,Session ID可以帮助快速恢复连接,或者根据当前连接快速创建新的连接,因为有了之前的基础只需修改会话随机部分就可以了,效率会高很多,但是这个Session ID的传输是没有加密的哦,这里是空的;Cipher Suites列出客户端支持的加密方式,使用4字节进行编码的,如前面说所我把高安全的Diffie Hellman禁用了,所以只支持上面三种方式;Compression基本都是空的。既然这个过程是两者协商的,所以恶意情况下中间人可以进行干扰,让加密通信回退到最差安全协议的情况下进行通信。
  此处还需要注意扩展中有个server_name,SSL在最早的时候需要每个站点有不同的IP,但是在同一个IP下运行多个虚拟主机的情况下显然不合适,所以后面就增加了这个扩展来标识需要访问的主机域名。
  (2). Server Hello
  服务端收到上述消息后,会进行一个回应,主要是根据客户端的情况,选择合适的协议版本和Cipher Suite。
https-step
  上面服务端确认采用TLS 1.2,同时采用TLS_RSA_WITH_AES_128_CBC_SHA;除此之外,服务端跟客户端类似,也产生了一个总共长度32字节的随机串。TLS_RSA_WITH_AES_128_CBC_SHA称之为Cipher Suite,RSA用于签名校验和加密、AES_128_CBC用于对称数据加密解密、SHA用于消息完整性校验,openssl集成了大量的算法支持,所以这里的组合种类可能很多,但最终服务端会和客户端达成某种一致的Cipher Suite,而且往往服务端也不一定决定要用最安全的套件,因为越安全的算法往往对服务器性能消耗越大。
  如果Client Hello的Session ID不为空,此时服务端可以在缓存的会话中进行校验,如果OK会恢复相同的Session ID进行确认;服务器也可以产生一个新的Session ID,表明后续有缓存该对话的意图;或者服务器返回空,表示不会缓存对话。
  (3). CertificateServer Hello Done
  TLS握手过程中一个过程可能有多条消息构成,在上面的Server Hello发送完后,接下来服务端还会发送自己的数字证书,证书的信息通过浏览器上面的那把锁点击也可以查看详情。
https-step
  证书中包含了颁发者、使用域名、有效时间、公钥等重要信息。然后服务端通过Server Hello Done结束发送。
https-step
  (4). Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
  客户端收到证书后,就开始忙活了:证书有效期限、域名匹配、是否被吊销了比较简单,关键怎么验证服务器传送过来的证书是否有效呢,毕竟这个数字证书中包含了服务端的公钥,涉及到后面的非对称加密数据的传输的?
  在通信的双方不能完全相信彼此的情况下,只能通过引入权威第三方进行协调,就像是支付宝的原理样的。从之前的非对称加密原理可知,密钥可以对消息、文件进行数字签名,所以只要可信机构(CA)确认过我的身份可靠后,使用他们的私钥对我的公钥和附加信息进行数字签名,那么任何相信该可信机构的人,都可以使用可信机构的公钥来对我的证书进行验证以实现对我身份的校验了。
  不过我们如何获得可靠的第三方公钥呢,通过每层结构都用自己的私钥对自己颁发出去的公钥及其拥有者进行签名,可以自上而下形成一个信任层次,但是顶级证书谁来信任呢,这不是个鸡与蛋的问题么?所以第三方可信结构的证书都是预置在浏览器和操作系统里面的,他们的证书是自签名的,对他们的信任是无条件的,所以从WoSign作恶被曝光后,Firefox、Chrome都声称停止相信WoSign的证书了,众目睽睽之下证书颁发机构才能得到有效的监督。还有,证书的等级分为DV、OV、EV,这也体现在签发的时候证书机构对申请者审查的程度不同,DV只要能验证域名所有权就可以签发,而EV还需要很多的书面文件审核才可以颁发的。
https-step
  证书通过验证后,后面就可以使用其中的公钥来加密敏感消息发送给服务端了。
  在上面两个Hello中总共产生了2个32字节的随机数,并且通过明文的方式发送给了对方,此时Client端再产生一个48字节的pre_master_secret随机数,该随机数通过上面的公钥和协定的加密算法(RSA)加密后发送给服务端,只有持有私钥的服务端才可以解密得到内容。这样,客户端和服务端都共有三个随机数,可以用算法产生一个对称加密密钥了。
  这里只使用服务器的公钥将pre_master_secret加密后就发送出去了,设想黑客记录了通信过程中的所有数据包,那么他可以得到handshake Hello过程中的随机数(明文的)以及加密后的pre_master_secret,如果有一天服务器的私钥被泄露,黑客就可以用私钥解密得到pre_master_secret,采用周知的方法得到session key,后续所有通信的数据内容都可以被解密了,即使此时证书过期了或者被吊销了,也于事无补,所以单纯的RSA handshake是不安全的。而上文中提到被禁用的Diffie Hellman就是为了解决这个问题而被提出来的,该算法被设计出来进行密钥的安全交换,原理上就没深究了。
  接下来Client发送一个Change Cipher Spec消息,该消息只有一个字节,其值为1,后面服务端也会向客户端发送,主要作用是告知对端后续的通信将会使用之前协商的CipherSpec和密钥对进行通信。
  客户端发送的最后一个消息是Encrypted Handshake Message,也叫做Finished消息,其内容是之前所有消息(不包括Hello消息)的内容+handshake_messages(“client finished”)等消息产生verify_data,然后通过各种计算操作产生64字节加密结果发送给服务端,服务端对其解密和校验,这个过程主要就是验证客户端和服务端之前商定的Cipher Spec和密钥是否生效。
  (5). New Session Ticket, Change Cipher Spec, Encrypted Handshake Message
https-step
  服务端也会有类似的Change Cipher Spec和Encrypted Handshake Message消息,不过这里还有一个New Session Ticket。
  这又是另外一个RFC5077了,其实跟上面的Session ID起到类似的作用,都是通过历史会话快速生成新会话的功能(Session Resumption)。在HandShake过程中,Server发送一个加密的session ticket(包含session key)给客户端,当恢复一个对话的时候客户端返回该加密的key,服务端解密后就可以在不需要私钥的情况下快速恢复对话了。该特性由Firefox、Chrome主要支持,其他浏览器多使用Session ID的方式恢复对话。
  Session ID是TLS内置的功能,而session ticket是一个扩展,其两者的区别是:前者需要在客户端和服务端都缓存该Session ID,服务端的缓存导致该情况下恢复对话功能不能跨主机;session ticket只会将加密的会话保存在客户端,当客户端需要恢复对话的时候,直接将会话数据发送给服务端,服务端解密就可以了,所以所有能够解密该session ticket的服务器多可以用来恢复对话,在免除服务端缓存Session信息压力的同时,更具有灵活性。采用会话恢复机制,能显著减轻服务端的压力以及客户端的连接速度。
  (6). Application Data
  自此,TLS handshake完成,后继的通信都采用对称加密方式进行加密保护,尽请放心使用。
https-step

本文完!

参考