[关闭]
@blueGhost 2017-09-01T09:23:18.000000Z 字数 5233 阅读 911

HTTPS系列1——HTTPS三次握手

encrypt


参考文献:
1. 视频讲解HTTPS握手过程
2. iOS 中对 HTTPS 证书链的验证
3. How does HTTPS actually work?
4. 聊聊 Android HTTPS 的使用姿势
5. HTTPS趣谈
6. PKI wiki介绍
7. What is the SSL Certificate Chain?

关键词:HTTPS三次握手证书链


一、SSL/TLS

SSL(Sucure Sockets Layer)&TLS(Transport Layer Security)是用于网络数据加密的协议。

  1. 公开发布的SSL版本是SSL2.0,发布于1995年,然后在1996年迅速更新为SSL3.0
  2. TLS1.0基于SSL3.0,在RFC2246中做了规范
  3. TLS1.1发布于2006年,在RFC4346做了规范,然后在2008年发布了TLS1.2(RFC5246)

二、HTTPS握手过程

1. HTTPS要完成的任务:

1.Client必须要能确定,它要访问的Server确实是正确的Server
2.Client和Server交流的信息不能被其它第三方窃听
3.当然,针对第1点,反过来,Server也可以要求,必须确认Client是它想通信的正确的Client,不过道理和1一样,这里不展开

为了理解上述3点,这里举个例子:
假如小黄和小红异地恋,他俩通过书信来往,假设愚人节当天,小黄收到来自小红的分手信,这里有2个问题:

1.小黄怎么知道这信确实是小红自己写的,而不是别人为了愚弄他伪造的信?即,小黄怎么知道和他通信的是小红本人?
2.即使信真的是小红寄出的,但是,邮差在送信的过程中,怎么保证信的真实内容不会被第三者攥改或者被偷窥?

2. 通过HTTPS握手建立加密信道来保证上述要求

三次握手过程如下:

Created with Raphaël 2.1.2ClientClientServerServerHello!1.协议版本号及客户端支持的加密算法2.客户端随机数(Client Random)1.接收客户随机数2.确认支持该加密算法则返回证书继续;否则取消链接1.下发证书,包含公钥2.服务端随机数(Server Random)1.客户端校验服务端返回的证书,校验不过则取消链接;校验通过则产生第三个随机数(Premaster Secret)2.使用服务端下发的证书中的公钥加密此随机数1.上送经过公钥加密后的随机数1.用私钥解密得到第三个随机数2.使用握手过程中的3个随机数生成Session Key,作为后续传输数据使用的对称密钥

三、HTTPS握手的剖析

看了上述三次握手过程,可以知道,handshake主要完成的事情:

1.客户端&服务端通信,协商加密方式
2.客户端(Client)和服务端(Server)互相确认身份(上面的图省略了服务端验证客户端身份的步骤)
3.双方安全地交换https通信使用的密钥(Session Key)

1. 第一阶段:C&S协商加密方式

客户端向服务端发送ClientHello信息,信息主要包括客户端支持的加密方式、客户端支持的SSL版本等;服务端接收到ClientHello信息后,向客户端发送一个ServerHello信息,主要是告诉客户端它将使用什么加密方式和SSL版本。

2. 第二阶段:身份校验

阶段2主要是,客户端&服务端互相校验对方身份,下面只举例,说明了客户端如何通过证书校验服务端身份,因为反过来的流程也是一样的。

1.关于证书:

服务端向客户端下发自己的证书,通常是CA认证的证书。证书包括了很多信息,主要有“公钥信息”、“签名”、“组织机构地区等信息”、“证书颁发机构”,关联的中级证书(medium certificate)、根证书(root certificate)等。

以百度的证书为例:使用chrome打开百度页面,command+option+j呼出开发者工具在“security”栏目下,点击"View certificate"按钮,可以看到该网站的证书

ac0b0415c05d3316bb705b132a77520a.png-45.7kB

1.公钥:baidu.com证书,如图黄色框内为公钥(后话:用于握手流程图中“上送经过公钥加密后的随机数”步骤,这里的公钥就是用来加密那个随机数的)

f5184eeab73dd7a2b6b0785a00089865.png-68kB

2.签名,如下图红色框内为baidu.com证书的签名。签名用于证明这个证书所描述的内容是对的,属实的,且没有被攥改过的。

54a7225fe62615a41ab067e822108872.png-55kB

2.客户端如何通过证书确定服务端的身份?

证明下面两点,(然后才可以使用证书上的公钥来加密生成Session key的随机数)

  1. 证明baidu.com这个证书确实是百度的
  2. 证明baidu.com这个证书没有被其他人攥改过

证书以证书链的形式组织,在颁发证书的时候首先要有根CA机构颁发的根证书,再由根CA机构颁发一个中级CA机构的证书,最后由中级CA机构颁发具体的SSL证书。以百度为例,如下图,"end-user" -> "intermediates" -> "root"形成一条链。
屏幕快照 2017-07-05 下午9.51.20.png-51.1kB

数字证书采用信任链验证。数字证书的信任锚(信任的起点)就是根证书颁发机构。根证书(root certificate)是一个无签名或自签名的证书。是用于识别根证书颁发机构(CA)的公钥证书。

验证的具体实现如下图所示:
Chain_of_trust.svg-32.7kB

  1. 从左往右,用户证书指向签署它的中级证书,并且,用户证书的摘要经由中级证书的私钥加密,密文作为该用户的证书签名(signature)记录在用户证书上。以百度为例,上一节说的签名就是了。
  2. 中级证书相应的,指向签署它的根证书,同时,中级证书的摘要经由根证书的私钥加密,密文作为中级证书的签名记录在中级证书上
  3. 根证书在签署的时候,使用签发机构的私钥对证书的摘要进行加密,密文作为根证书的签名记录在根证书上。

实际上,根证书甚至可以不签名,因为根证书是预先安装在系统中的,并且由系统保护起来,是值得信赖的。(根证书作为证书信任链的最后一环,非常重要,所以请不要随便安装不知底细的根证书)

了解了信任链(trust chain)后,我们可以通过下面的步骤来验证证书:

  1. 使用中级证书的公钥对下级证书的签名解密得到下级证书的摘要,由于是RSA解密,能够解密成功说明了下级证书确实是中级证书所签署的(快速脑补一下RSA算法原理
  2. 对下级证书做信息摘要,拿这个摘要与1步骤解密出来的摘要做对比,如果两者一致,则证明了这个下级证书没有被攥改
  3. 接着,按照上面1~2步骤,对中级证书进行验证,直到可信任的其他中级证书或者到可信任的根证书(即上溯到一个可信锚点),那么就可以证明这条trust chain上的证书都是正确的可信任的。

好了,现在可以解答这两个问题了:

  1. 证明baidu.com这个证书确实是百度的——通过trust chain,可以验证这个用户证书确实是CA颁发的,而CA给用户颁发证书,已经校验了该用户的资质和情况(比如,确保申请证书的用户确实拥有www.baidu.com站点),并且做了备案
  2. 证明baidu.com这个证书没有被其他人攥改过————通过证书链,逐级解密签名得出摘要,通过对比该摘要是否和当前证书的实际摘要相同,确保没有被攥改

说明1: 关于如何使用openssl去校验证书,可以参考我的这篇文章:HTTPS系列2——证书的信任链校验:certificate trust chain

说明2: 准确的说,有可能服务端下发证书到客户端时,被第三方拦截,并下发一个证书,这个证书,如果是假证书,则客户端校验不通过,无法继续建立HTTPS链接(在浏览器里,就是一个红色的警告页面,告诉用户该证书不受信任);如果证书是真的,校验通过,即使后面第三方依旧拦截客户端与服务端的通信,由于拦截者没有证书私钥,因此无法解密通信内容,也无济于事。

说明3:这个阶段,服务端也可以要求验证客户端的身份,过程和上述过程一致,只是换成客户端发送其证书,服务端收到证书,验证客户端身份。

3. 第三阶段:产生通信密钥

前面讲过,第1阶段,服务端告知了客户端后面要使用的加密方式(普遍都是对称加密,因为非对称加密成本太高,速度低下)。

第2阶段,客户端验证服务端证书是正确的,即,证书上标明的公钥拿来加密信息,加密后的信息,只有该服务端能解密,其它第三方无法解密。
那么在第三阶段,客户端产生了第三个随机数,这个随机数称为PMSc(a premaster secret,46 bytes ),使用服务端的公钥对PMSc加密,然后上送给服务端。服务端取到这个密文后,用自己的私钥解密,得到PMSc。

好了,接下来最重要的一步来了:根据之前协商好的加密方式,以及3个随机数,客户端、服务端各自产生出通信密钥,该密钥称为Master Secret,简称MS,也称Session Key。这个密钥虽然是各自产生的,但是产生后是一致的。

4. 加密信道已经建立

客户端,服务端各自产生了通信密钥后,就用这个相同的MS对往后的所有通信信息进行加密。而这个密钥,第三方是不知道的,第三方尽管去窥探,但是他们看不懂信息,所以效果相当于,客户端&服务端在一个加密信道中通信。

四、探讨一些实际应用

1.抓包工具抓取HTTPS的原理?

做开发的都知道,安装一个抓包工具,将它配置为代理服务器,被抓包的设备只要安装并信任这个抓包工具的证书,然后网络链接到该代理服务器上,就可以抓HTTPS包了。
安装并信任这个抓包工具的证书这一步骤非常重要,否则无法抓取HTTPS包。这一过程相当于在设备里安装了一个“受信任的证书”,该证书后续就作为HTTPS信任链校验中的“可信任锚点”,其作用和系统预装好的“可信任根证书”是一样的!而默认的HTTPS证书校验,会走信任链,直到找到“可信任锚点”则校验通过。
所以,不要随便安装和信任来历不明的证书,一旦安装并信任了,那么该证书在设备上就是一个“可信任锚点”,由该证书签发的任何其他证书,都会被设备校验通过。使用这一系列证书建立的HTTPS通信,可以被第三方所窥探。

2.连接公共WIFI访问HTTPS站点,是否安全?

假设你的设备没有安装信任过来历不明的证书,那么不管在任何WIFI或者网络环境下,通常HTTPS通信都是安全的。
1). 假设该开放网络偷偷作为中间人,拦截HTTPS握手,下发一个它自己签发的假证书,这种情况下,由于该证书无法被设备的证书信任链校验通过,HTTPS链接建立失败,浏览器会有一个明显的错误提示页面,提示用户证书不被信任。
2). 假设该开放网络作为中间人,拦截HTTPS握手,下发一个合法的CA证书,这个时候,客户端校验通过,建立HTTPS链接,但是由于在协商生成Session Key的过程,PMSc使用了证书的公钥进行加密,这意味着只有那个合法的CA证书拥有者才有私钥可以解密,中间人无法解密。所以中间人无法识别到HTTPS的通信内容。
3). 根据第2点的思路,假设中间人下发的也是一个合法的CA证书,但是这个证书是中间人自己的,因此中间人知道这个证书的私钥!这种情况下,意味着一旦建立了HTTPS链接,通信内容完全可以被窥视。是否能正确建立HTTPS链接,完全取决于设备如何验证证书,比如我们的设备准备和https://www.baidu.com通信,在握手阶段,被第三方拦截,第三方下发了一个合法CA给设备,设备如果在校验的过程中,既校验的信任链,又从证书中取出域名做校验、取出CA证书拥有者的信息做校验,那么就可以辨别这个证书不是baidu的!因为第三方的CA证书虽然也是CA颁发,但是CA在颁发时已经确认过该机构的信息以及域名等写到证书上了。所以,假如程序员开发程序时准备自己来校验HTTPS证书,要非常谨慎、严格地校验,起码要校验信任链(可以采取严格的校验,即通过预置可信任锚点到客户端,或者通过RSA加密方式动态下发信任锚点,然后只使用这个锚点来校验HTTPS建立链接时服务端下发的证书,无需走系统默认的信任链)、校验证书的颁发机构、有效期、证书域名与将要访问的域名是否一致、证书的持有者等信息。关于详细的,自己实现HTTPS证书强校验的重要性及实现方案,准备后续出文章讨论,请期待。


五、附录:

推荐几篇文章
0. Basics of Digital Certificates and Certificate Authority
1. 通过分析亚马逊网站https请求来解析https握手全过程
2. 视频讲解HTTPS握手过程
3. 阮老师讲RSA算法实现
4. 阮老师讲数字签名
5. 那些证书相关的玩意儿(SSL,X.509,PEM,DER,CRT,CER,KEY,CSR,P12等)
6. 对称加密+非对称加密设计加密过程
7. 使用常用的Openssl命令:证书格式转换、校验、debug等
8. Openssl入门
9. 应用 openssl 工具进行 SSL 故障分析
10. OpenSSL Essentials: Working with SSL Certificates, Private Keys and CSRs
11. 使用 OpenSSL 实现私钥和证书的转换

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注