我们来聊聊HTTPS吧

网络安全事实上在《计算机网络安全引论》 这篇中已经简单的讨论过了,《计算机网络安全引论》可以理解为本系列文章的总纲。

前言

其实在没了解HTTPS之前,我对HTTPS的理解就是HTTPS = HTTP + SAFE,意为安全的HTTP协议,其实这么理解也没问题,HTTPS就是让HTTP变的安全,那说到安全我们该如何定义这个安全呢? 我认为有以下几个方面是值得关注的:

  • 保密性

这一点很好理解,数据在网络中传输有被别人截获的风险,那我们自然期望就算是数据被截获,也无法从截获的数据中提取到有效信息。

为了做到这一点,我们就需要这种密码技术。

  • 端点鉴别

网络传输不同于当面说话,在通信过程中我们不能完全信任第三方,因为第三方可能是假冒的。即使当面说话,也有对应的风险,因为对面有可能还是易容的,这里想到了秦时明月,小皮一下。

  • 信息的完整性

那么即使我们验证了第三方的身份,那么报文也有被篡改的风险,我们依然不能认为网络是安全的,还必须确认收到

  • 运行时安全性-访问控制

对数据进行访问控制,必须对访问网络的权限加以控制。

HTTPS 完成了 保密性、端点鉴别、信息完整性这三部分,我们将分篇介绍这三点。上面的HTTPS的S其实是TLS/SSL。

加密技术简介

什么是加密?从技术上讲,它是将人类可读的明文转换成不可理解文本(也称为密文的过程)。

加密过程

上面的”Hello world” 在AES的作用下变成了一堆看起来毫无规律的字符,其实上面还漏了密钥,完整的过程是下面这样:

完整的AES加密过程

那什么是密钥: 加密算法中用于更改数据而使用的字符串,以便混淆需要加密的数据,以便使其看起来是随机的。某种程度上,我们可以理解为AES加密通过密钥将我们需要加密的数据关在了一串看起来随机的密文中,那对应的就有解密,也就是AES通过密钥将我们的数据还原为源数据。在AES下面,加解密的密钥都是一种,我们一般称之为对称加密。在对称加密中,另一种为人所熟知的加密方法为DES,于1977年被美国联邦选为加密标准,但是经过了几十年的研究,56位的DES已经不再被认为是安全的了,后面的学者们提出了三重DES对DES进行改进。

但是对称密钥也有对应的问题,在传输过程中为了实现加解密,我们首先要将密钥进行传输,但在网络中传输就有可能被人截获,由此就引出了非对称加密体制,也称公钥密码体制(公开密钥密码体制),由斯坦福大学的Diffie与Hellman于1979年所提出。公钥密码体制使用不同的加密密钥与解密密钥。

在公钥密码体制提出不久,人们就找到了三种公钥密码体制。目前最著名的是由美国三位科学家Rivest、Shamir和Adelman提出并在1978年正式发表的RSA体制,它是一种基于数论中的大数分解问题的体制。

在公钥密码体制中,加密密钥PK(Public Key)是可以向公众公开的,而解密密钥SK(Secret Key)则是需要保密的。加密算法、解密算法也是公开的。

你也可以用私钥加密,用公钥解密。那看到这里有同学就会问了,你说在通信中用对称加密,密钥会被截获,那非对称加密就能不被截获了?

中间人攻击到身份鉴别

我们将目前通信的双方称之为A和B,在通信过程中使用非对称加密,B在首次通信的时候发送自己的公钥PK1,然后A接收到之后用PK1对自己的私钥PK2进行加密:

非对称加密的通信流程

然后A再向B发送自己的公钥,B用A的公钥对自己的私钥进行加密,这样双方就彼此交换了公私钥。由于私钥不公开,所以就算是其他人截获了A给B的报文,也解不开。 所以A和B就能愉快的实现通信了吗?当然不是,中间人只需要假冒A就行了,在收到到B第一次发的PK1的时候,用PK1对自己的私钥进行加密,然后发送给B,假冒A。同时将自己的公钥发送给A,假冒B,这样整个通信都被破坏了。由此我们就引出了身份鉴别问题,我们怎么知道通信的对方是我们要通信的。

这就需要一个有一个值得信赖的机构来将公钥与其对应的实体进行绑定,这也就是认证中心(Certification Authority), 每个实体都由CA发来的证书(Certificate), 里面有公钥及拥有者标识的信息。此证书被CA进行了数字签名,防止被篡改,公钥用来验证某个公钥是否为哪个实体所拥有(通过向CA查询)。

使用HTTPS连接的网站,在浏览器的地址栏,有个锁的标记:

查看证书信息

证书相关信息

证书的样子

所以如果你想要使用HTTPS协议,还不是那么简单的事情,首先需要向CA机构申请证书,我觉得这个证书某种程度上可以理解为身份证号。我们的核心问题其实还是为了分发公钥,即将通信双方的私钥进行交换,为了避免被第三方截获公钥,CA机构为每个证书也准备了公钥、私钥。现在仍然辛苦A和B,目前我们将A更名为胡辣汤,将B更名为水煎包,来介绍有了CA机构介入之后的流程。

首先水煎包为了自证身份将自己的公钥以及个人信息制作成了证书提交给了CA机构,CA机构验证完身份之后, 会用自己的私钥计算出证书的数字签名,有同学看到这里可能会问,非对称加密中私钥不是用来解密的吗?还没加密,用私钥能解密吗?这里用私钥计算出来的数字签名只是为了得到某种不可读的明文,防止证书在由水煎包给到胡辣汤的途中,被人篡改,用于验证身份。对付中间人攻击,确认这个证书确确实实是由水煎包发过来的,跟我通信的确实是水煎包。

在验证完身份之后,胡辣汤就提取到了证书里面的公钥,这里其实还是有风险,虽然没办法篡改,但是可以实现监听,第三方劫持到了证书,也获得了密钥......

所以这里就引出了双向认证,即服务端确认客户端的身份,客户端也要向服务端提交自己的身份说明。

上面我们提到了对签名进行验证,一般的术语我们称之为鉴别,我们一般不采用非对称加密对报文进行鉴别,原因在于对于较长的报文进行数字签名会使计算机增加非常大的负担,因为这需要进行比较多的时间进行运算。我们的愿景是找出一种相对简单的方法对报文进行鉴别,由此引出了密码散列函数(cryptographic hash function)。

密码散列函数简介

提到密码散列函数,可能大家都比较陌生,但是散列的对应英文hash,还有另外一个名字叫哈希,我想Java程序员已经联想到了HashMap,对就是那个hash, 基本上每个key产生的hash值是唯一的,不同的key,可能输出相同的hash值,我们称之为hash碰撞。但是密码散列函数,相对于HashMap来说,有一点不同的就在于: 找到两个不同的报文,它们具有相同的密码散列函数输出,在计算上是不行的,也就是说,密码散列函数事实上是一种单向函数,不可逆。所以MD 5不是一种加密算法,而是一种密码散列函数。

目前来说比较为人熟知的实用密码散列函数为MD5和SHA-1。MD 是Message Digest的缩写,中文译为报文摘要,所以MD5的意识是MD5的第五个版本。MD5的设计者Rivest曾提到一个猜想,即根据给定的MD5摘要算法,要找出一个与原来报文有相同报文摘要的另一报文,其难度在计算上是不可能的。中国学者王小云在2004年发表了轰动世界的密码学论文,证明可以用系统的方法找出一对报文,这对报文具备相同的MD5摘要,而这仅需15分钟。

注意不是给定一个MD5值,找到另一个报文具备相同的报文值,而是找出一对报文,具备相同的MD5摘要。随着陆续的发展,MD5最终被另一种安全散列算法的标准(Secure Hash Algorithm)所替代,也就是SHA,虽然在某种程度上来说SHA比MD5更安全,但是在计算上相对于MD5来说却又慢一些。其实SHA也没达到设计要求,而且也被王小云教授的研究团队攻破。随后不久就又推出了SHA-2,SHA-3.

证书的标准格式

为了使CA证书具有统一的格式,ITU-T制定了X.509协议标准,用来描述证书的结构。在现代网络通讯中通行的公钥证书标准名为X.509 V3,由RFC-5280定义。X.509 V3 格式被广泛应用在TLS/SSL等众多加密协议中,它规定公钥证书应该包含如下内容:

  • 证书

    • 序列号(Serial Number): 用以识别每一张证书,在作废证书的时候会用到它
    • 版本: 证书的规范版本

    • 公钥(Public Key): 我们的核心目的就是分发公钥,因此显然要把公钥放在证书里面

    • 公钥指纹: 即公钥的 Hash 值,当前大部分证书都使用 SHA256 计算此指纹

    • 公钥用途(Key Usage + Extended Key Usage): 记录了此证书可用于哪些用途——数字签名、身份认证等

    • 主体

      (Subject): 即姓名、组织、邮箱、地址等证书拥有者的个人信息。

      • 有了这个我们就能确认证书的拥有者了
    • 证书有效期的开始时间、结束时间

      (Not Before + Not After): 为了确保安全性,每个证书都会记录一个自身的有效期

      • 证书一旦签发并公开,随着科技的发展、时间的推移,其公钥的安全性会慢慢减弱
      • 因此每个证书都应该包含一个合理的有效期,证书的拥有者应该在有效期截止前更换自身的证书以确保安全性
    • 签发者(Issuer): 签发此证书的「签发者」信息

    • 其他拓展信息

    • 数字签名

      (Signature): 我们还需要对上面整个证书计算一个数字签名,来确保这些数据的真实性、完整性,确保证书未被恶意篡改/伪造

      • 此数字签名由「证书签发者(Issuer)」使用其私钥+证书内容计算得出
    • 数字签名算法(Signature Algorithm): 证书所使用的签名算法,常用的有 RSA-SHA-256ECDSA-SHA-256

对称密钥交换算法

上面我们提到了为了安全传输数据需要加密+引入CA机构验证身份,加密主要是为了防止数据窃听,我们在上面介绍的对称加密过程中只是为了说明问题,到这里来看,上面的模型实在粗糙,因为首次通信给的就是密钥,中间人甚至不用假装身份就能拿到,在真实的交换对称密钥的过程中,我们采取的是另一种交换密钥算法:迪菲-赫尔曼密钥交换(Diffie–Hellman Key Exchange)是一种安全协议,它可以让双方在完全没有对方任何预先信息的条件下通过不安全信道安全地协商出一个安全密钥,而且任何窃听者都无法得知密钥信息。 这个密钥可以在后续的通讯中作为对称密钥来加密通讯内容。

DHKE 有两种实现方案:

  • 传统的 DHKE 算法:使用离散对数实现
  • 基于椭圆曲线密码学的 ECDH

为了理解 DHKE 如何实现在「大庭广众之下」安全地协商出密钥,我们首先使用色彩混合来形象地解释下它大致的思路。我们再次请出水煎包和胡辣汤同志。

  • 首先水煎包和胡辣汤沟通,协商出一个初始的颜色,比如黄色,这个不需要保密。
  • 然后水煎包和胡辣汤各自选择一个自己的色彩,这个要保密。
  • 现在水煎包和胡辣汤,分别将初始色彩跟自己的秘密色彩进行混合,分别得到两个混合色彩。
  • 现在水煎包和胡辣汤开始交换混合色彩,我们假设在仅知道初始色彩跟混合色彩的情况下,很难推导出被混合的秘密色彩。这样第三方去监听的时候,不假冒身份也无法获取到最终的秘密色型。
  • 最后水煎包和胡辣汤再分别将自己的秘密色彩,跟对方的混合色彩混合,就得到了最终的秘密色彩。这个最终色彩只有水煎包和胡辣汤知道。

DHKE协议也是基于类似的原理,但是使用的是离散对数跟模幂而不是色彩混合。对离散对数跟模幂感到陌生的,可以去翻翻离散数学的教材。其实这个推导过程倒也不难,哈哈哈哈,有时间单独开这个算法推导的过程。

那上面写的为了安全传输,所需要进行的验证,我们要自己实现一套吗? 当然不是,已经有一套相关的标准了,由此引出SSL/TLS。

由此引出SSL/TLS

Netscape 于1995年开发了名为安全套接字层(Secure Socket Layer,SSL)的上一代加密协议,旨在确保 Internet 通信中的隐私、身份验证和数据完整性。SSL 自 1996 年推出 SSL 3.0 以来未曾更新过,现已弃用。SSL 协议中存在多个已知漏洞,安全专家建议停止使用。实际上,大多数现代 Web 浏览器已彻底不再支持 SSL。TLS 1.0 版实际上最初作为 SSL 3.1 版开发,但在发布前更改了名称,以表明它不再与 Netscape 关联。由于这个历史原因,TLS 和 SSL 这两个术语有时会互换使用。HTTPS 是在 HTTP 协议基础上实施 TLS 加密,所有网站以及其他部分 web 服务都使用该协议。因此,任何使用 HTTPS 的网站都使用 TLS 加密。

我们上面讨论了在网络数据传输中遇到了问题,并尝试给出了解决方案,这其实就是SSL/TLS的一部分。粗略的说,我们可以理解为HTTP从SSL/TLS里面收发数据协议。在SSL/TLS中我们主要使用非对称加密+CA证书来验证身份防止中间人攻击,在验证完身份交换密钥之后,还是走的对称加密,因为对称加密,速度更快。

HTTPS 通信流程

首先浏览器和服务端进行通信,在建立TCP连接之后,要经过TLS握手,才建立后续的HTTPS连接。大致步骤如下:

  • “客户端问候(client hello)” 消息: 客户端通过向服务器发送“问候”消息来开始握手。该消息将包含客户端支持的 TLS 版本,支持的密码套件
  • “服务器问候(server hello)”消息: 作为对 client hello 消息的回复,服务器发送一条消息,内含服务器的 SSL 证书、服务器选择的密码套件。
  • 身份验证: 客户端使用颁发该证书的证书颁发机构验证服务器的 SSL 证书。此举确认服务器是其声称的身份,且客户端正在与该域的实际所有者进行交互。
  • 预主密钥: 客户端再发送一串随机字节,即“预主密钥(premaster secret)”。预主密钥是使用公钥加密的,只能使用服务器的私钥解密。(客户端从服务器的 SSL 证书中获得公钥。)
  • 私钥被使用: 服务器对预主密钥进行解密
  • 生成会话密钥: 客户端和服务器均使用客户端随机数、服务器随机数和预主密钥生成会话密钥。双方应得到相同的结果。
  • 客户端就绪: 客户端发送一条“已完成”消息,该消息用会话密钥加密。
  • 服务器就绪: 服务器发送一条“已完成”消息,该消息用会话密钥加密。
  • 实现安全对称加密: 已完成握手,并使用会话密钥继续进行通信。

总结一下

在明文传输下,可能被截获篡改,引入加密算法,则会有中间人攻击,为了自证身份,我们引入了CA,每个网站可以向其申请证书,类似于身份证。这也就引出了SSL/TLS。目前的HTTPS就是HTTP+SSL/TLS。SSL/TLS也被应用于传输层。上面我们讲TLS握手,说在握手之前要建立TCP连接,其实少了个限制词,应当是在HTTP/2。HTTP/3弃用了TCP协议,技术总在朝前走。

写在最后

这个世上存在绝对可靠的吗?写到这里,突然脑袋出现一句话: 这世间没有绝对的真理,只有相对的真理。写到这里的时候还问了学哲学的朋友,朋友指出我这么说不严谨,朋友回答了一句:

马克思主义哲学认为真理是绝对与相对的辩证统一

写到这里,可以说总算可以舒一口气了,终于舒一口气了,其实写安全相关的文章,找资料是个让人颇为头疼的事情,我在写的时候也会向我自己提出问题,然后发现无法给出让自己认可的解释,就只能查资料,反复的想。这里的思路是从网络传输数据的问题入手逐步引导SSL/TLS,最终引出到HTTPS。我想尽可能的接近真实的HTTPS流程,不想让文章中有致命伤,本篇写作的时候是一边看教材《计算机网络教材 (第七版)》,一边推敲里面的逻辑合不合理,教材中写:

双方用会话密钥加密和解密它们之间传送的数据并验证其完整性。

其实关于这一点我其实并不理解,在已经验证完身份,保证密钥不被窃取的情况下,为什么还要验证其完整性。我查了许多资料,在知乎上关于这个问题的讨论比较少,有个答主认为这个验证其完整性是不必须的,我在介绍HTTPS的网站中也没看到握手完成之后还要对其报文进行验证其完整性,防止被篡改。搜不到我就去对应的RFC 5246,这个文档看的我很痛苦,也没找到答案,这里先将这个问题放在这里,我打算后面看HttpClient的源码的时候去验证。

双向认证这个介绍来自于我看HTTPS的通信流程的时候,客户端不提供证书,那我伪装客户端,然后在阿里云文档里面看到了双向认证。其实在网络传输中还有一个问题没介绍,就是重放攻击。

第三方不需要看到通信的报文代表什么意思,原因可能在于第三方没有窃取到通信密钥,只需要让发送方发送的休息无法正确到达接收方就行了。就比如胡辣汤和水煎包进行通信,第三方将胡辣汤发送的报文转发给水煎包,让水煎包误以为第三方是胡辣汤,然后水煎包就将原本发给胡辣汤的报文发送给第三方,我们一般称这种攻击方式为重放攻击,做的更像一点,第三方还可以截获A的IP地址,然后进行冒充,进行IP欺骗,使B更加容易受骗。

在《计算机网络教材 (第七版)》中讲TLS能应对重放攻击,但是参考文档[6] 《如何有效防止API的重放攻击?》(参考资料里面有连接),上面说HTTPS无法应对重放攻击。在参考资料[7] 《再探https与重放攻击 》中指出在TLS有些情况下可以应对重放攻击,还找到了RFC 5246的说明。但是要介绍究竟能不能应对重放攻击,又要再研究TLS的握手过程,我本篇只是打算介绍HTTPS的宏观通信流程,索性这里就裁掉了。

对称密钥交换算法这一章节对称密钥交换算法来自参考文档[3] , 真是相当精彩的比喻,老是说我能看懂这个算法,但是这个比喻真是让人赞叹。

再补充一下对签名的鉴别,其实这一技术不仅仅应用于网络传输,像现在正在推广的电子合同也用到了这个技术,签署合同的时候生成一个签名,合同携带此签名,篡改合同,对文件进行改动,合同的签名值就会发生改变。

参考资料

[1] 为什么 HTTP 不安全?| HTTP 与 HTTPS www.cloudflare.com/zh-cn/learn…

[2] Explaining public-key cryptography to non-geeks medium.com/@vrypan/exp…

[3] 写给开发人员的实用密码学(八)—— 数字证书与 TLS 协议 thiscute.world/posts/about…

[4] 给工程师:关于证书(certificate)和公钥基础设施(PKI)的一切 mp.weixin.qq.com/s/li3ZjfNgX…

[5] HTTPS双向认证(Mutual TLS authentication) help.aliyun.com/document_de…

[6] 如何有效防止API的重放攻击? help.aliyun.com/document_de…

[7] 再探https与重放攻击 blog.csdn.net/junyang2012…

猜你喜欢

转载自juejin.im/post/7131271758006452231