George Cao于2020年03月28日 HTTP HTTPS CA RSA 信任链 非对称加密 证书 密钥对 证书链 数字签名
如今的HTTPS基本上已经占据了大部分流量,根据Google Chrome的统计,截止2020年3月21日,有96%的请求是走HTTPS的。以Chrome浏览器的市场占有率,应该很能说明问题了。嗯,HTTPS在大部分场景下基本上是标配了。那弄懂HTTPS的工作机制就很有必要了。
超文本传输协议(英语:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。而HTTPS则可以称为安全版本的HTTP, HTTPS开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。
拿Facebook作为例子,当我们在浏览器地址栏输入http://www.facebook.com之后,我们怎么能确定访问的就是Facebook的网站呢? 大部分情况下应该是的,但是也有些钓鱼网站,DNS污染等等手段是能让我们访问到别有用心的其他网站。也就是说不管怎么样,我们不能100%的确信。为了能够确定我们访问的是真正的Facebook,我们是需要一种方法来确认服务器是Facebook的而不是其他网站的,也就是服务器的身份认证。如果能做到这个,我们就能判断出是否访问了攻击者仿冒的网站而不是真正的Facebook。
幸运的是,使用非对称加密我们是可以做到的。具体就是Facebook需要有一对公钥和私钥,然后公布自己的公钥,但是把私钥安全保存在自己的服务器上。现在,你只要用Facebook的公钥加密自己的请求数据,根据加密知识,你知道只有Facebook的私钥才能解密这个数据。如果你访问的服务器能够正确的解密数据并且给你返回数据,你就能确信服务器有Facebook的私钥。
只要Facebook能够保护好自己的私钥,确保不被其他人盗用,我们就解决了服务器的认证问题,简单。这样的话,尽管受到互联网本身特性的制约,我们还是设计了一种方法来验证网站的身份。事实上,我们刚刚描述的这个过程和真正的HTTPS是非常像的。当我们说一个服务器的HTTPS证书的时候,我们其实说的就是一个公钥。
尽管如此,上述过程存在一个大问题,而这个问题HTTPS必须要解决的。这个问题就是你如何获取每个你想访问的网站的公钥呢?当然了,你有了Facebook的公钥就可以安全的访问Facebook了,但是,如果你想安全的访问Google,你需要Google的公钥。同样的,你想安全的访问Twitter,你需要Twitter的公钥。
互联网上有成千上万的网站,而且还在不停的变化。所以就不太可能在你的个人电脑上保存一份全部网站的公钥,只能换一种思路了。现在,我们可以不用在电脑上一直维护这个巨大的公钥列表,而是在第一次访问网站的时候让网站发给我们她的公钥。不过这样就又回到开始的问题了:如果我们在不知情的情况下访问了恶意的第三方,那第三方可能会伪装并且发送她自己的公钥给我们。
到这一步,你可能要泄气了。虽然我们使用了公钥和私钥,但是我们实际上又回到了最初的问题:我们需要一种让Facebook能够证明其身份的方法,然后我们才能信任他们的公钥。既然如此,公钥的真正的意义又是啥呢?
还有一个问题是互联网上的某个网站不能对每个访问者验证其公钥的有效性,因为现今互联网的规模大到这么做是不经济的。想象一下Facebook16.9亿用户,每个用户至少得发起一次请求,鉴于HTTP的无状态特性,每次请求都要验证一下这个公钥的有效性,这个规模是非常大的。为了解决这个问题,我们使用证书机构或者简称CA。
证书机构(CA)能正确工作的前提是我们首先得信任他。这听起来有很多顾虑,但是实践中却工作的很好。CA是依靠信任的,所以当CA做了一些可疑的事情,浏览器马上就不再信任这些CA,这些CA也就该倒闭了。即使是CA方面的简单错误也足以永久破坏其声誉。
那CA是如何解决我们的身份认证问题的呢?CA收钱为网站提供这种身份认证服务。DigiCert是一家有名的CA,同时也是Facebook使用的CA,我们就用她作为CA的例子。Facebook想证明她的公钥的有效身份,从而让用户安全的访问。所以她就花钱请DigiCert确认她就是真正的Facebook,一旦做了这个,DigiCert就会知道哪个公钥真的就是Facebook的。现在当你访问Facebook的时候,你就不需要Facebook证明她自己的身份了,你只需要Facebook证明DigiCert已经验证过她的身份就可以了。DigiCert为许多网站提供这种服务,你不需要弄清楚如何信任某个网站,你只需要信任DigiCert就可以了。如果你信任DigiCert,而DigiCert信任Facebook,那么理论上你就可以信任Facebook了。我们叫这个信任链。
从抽象的高度看,这就是HTTPS的工作原理了。但是,我们需要弄清楚该过程的中的两个具体细节,才能理解详细的工作原理。
你怎么知道你正在使用DigiCert,而不是仿冒的DigiCert?
这看起来又回到问题的起点了。如果我们拥有DigiCert的公钥,则可以验证其身份。但是我们需要以某种方式确保我们拥有DigiCert的公钥,而不是别人的。这里的解决办法是什么呢?其实是我们使用的操作系统或浏览器已经存储了DigiCert的公钥。现如今,我们信任很多CA,只不过她们是众所周知的,才能让现代操作系统或者浏览器存储她们的公钥。这部分公钥存储在计算机的“受信任的根证书颁发机构存储区(Trusted Root Certificate Authority Store)”中。存储的密钥数量似乎很多,但这总比为互联网上的每个网站存储一个公钥要容易多了。
Facebook如何证明DigiCert对其进行了验证?
一旦DigiCert验证过Facebook就是Facebook之后,DigiCert就知道了Facebook的真正公钥,然后使用自己的私钥对Facebook的公钥进行数字签名,并且将这个签名后的公钥给Facebook。这种交互完全发生在Facebook和DigiCert之间,而且远远早于用户连接到Facebook的时间,一般网站上线之前就发生了。现在,当你连接到Facebook时,Facebook会给你发送一个已由DigiCert的私钥签名的公钥。然后你可以使用操作系统存储的公钥来验证DigiCert对Facebook的公钥进行了签名。
整个过程中有两对公钥和私钥,一对是网站的,一对是CA的。双方都对外公布自己的公钥,并安全保存自己的私钥。网站的公钥先是给了CA,被签名之后间接的最终还是给了用户,这个公钥在协商阶段还会用到。而CA的公钥则直接被操作系统或者浏览器存储下来了,也相当于给了用户。CA用自己的私钥对网站的公钥进行数字签名,发给网站,这就是服务器的证书。当用户连接到服务器的握手环节,服务器发送证书给用户,用户通过本地的CA的公钥来解密网站发来的证书(CA私钥签名过的网站公钥),如果成功则完成了验证问题。
使用非对称加密完成了网站服务器的身份认证,接下来的保护交换数据的隐私与完整性则最终使用了对称加密手段。过程非常复杂,HTTPS的握手环节还进了用户与服务器之间一系列的加密算法,对称加密密码等等协商之后就可以进行安全的访问了。HTTPS完整的握手环节可以通过这里查看,详细到每个字节,同时也解释了协议并且图形化描述了整个过程。
Google Transparency Report - HTTPS encryption on the web
www.youdzone.com - What is a Digital Signature?
ulfheim.net - The New Illustrated TLS Connection
dnsimple.com - What is the SSL Certificate Chain?