完全理解HTTPS如何做到传输安全

2,647 阅读15分钟
原文链接: github.com

概念

HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。

HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。

我们可以带着问题去理解 HTTPS 为什么更安全:

  1. 客户端怎么确定来自服务器的信息没有被篡改过?
  2. 服务端怎么确定来自客户端的信息没有被篡改过?

名词解释

公钥(yuè)私钥(yuè)

公开密钥加密(英语:Public-key cryptography),也称为非对称加密(英语:asymmetric cryptography),是密码学的一种算法,它需要两个 密钥,一个是公开密钥,另一个是私有密钥;一个用作加密的时候,另一个则用作解密。使用其中一个密钥把明文加密后所得的密文,只能用相对应的另一个密钥才能解密得到原本的明文;甚至连最初用来加密的密钥也不能用作解密。由于加密和解密需要两个不同的密钥,故被称为非对称加密;不同于加密和解密都使用同一个密钥的 对称加密。虽然两个密钥在数学上相关,但如果知道了其中一个,并不能凭此计算出另外一个;因此其中一个可以公开,称为公钥,任意向外发布;不公开的密钥为私钥,必须由用户自行严格秘密保管,绝不通过任何途径向任何人提供,也不会透露给要通信的另一方,即使他被信任。

以上是来自维基百科的公钥私钥的定义,HTTPS 是基于非对称加密的,公钥和私钥是整个 HTTPS 的基础。简单来说,公钥是公开的(要不叫公钥),比如小 A 想给我发送加密信息就要他我的公钥,让他用我的公钥对信息进行加密,这个信息只有我的私钥能打开。所以私钥是绝对不能泄漏的,那么私钥只能用来解开公钥吗?并不是,公钥私钥都可以加密和用对方来解密,私钥用来签发数字签名,我用独一无二的私钥签发了一个数字签名,你们都有我的公钥,只有我签发的数字签名能用我的公钥解开,才能证明这个签名发自我。

知乎上有个回答特别精辟:

不要去硬记。 你只要想:既然是加密,那肯定是不希望别人知道我的消息,所以只有我才能解密,所以可得出公钥负责加密,私钥负责解密;同理,既然是签名,那肯定是不希望有人冒充我发消息,只有我才能发布这个签名,所以可得出私钥负责签名,公钥负责验证

Diffie–Hellman

迪菲-赫尔曼密钥交换(英语:Diffie–Hellman key exchange,缩写为D-H) 是一种安全协议。它可以让双方在完全没有对方任何预先信息的条件下通过不安全 信道创建起一个 密钥。这个密钥可以在后续的通讯中作为对称密钥加密通讯内容。

笔者本人并没很仔细理解这个算法的原理,但是作为前端在实际应用中只需要知道这个加密算法的作用就好了,中间就是黑箱。简单来说这个算法的作用就是:Alice 和 Bob 各自有对方的公钥(当然其他人也有),Alice 和 Bob 再产生一个随机数(不告诉别人),然后用两个人的公钥和自己手里的随机数产生两个数 A B,然后它们交换这两个数,每个人可以用自己手头的随机数和交换得来的数再次计算,两个人得到的数是一样的,就得到了一个共享密钥。

知乎上找到一个这个共享秘钥计算过程的描述

(1)Alice与Bob确定两个大素数n和g,这两个数不用保密

(2)Alice选择另一个大随机数x,并计算A如下:A=gxmod n

(3)Alice将A发给Bob

(4)Bob 选择另一个大随机数y,并计算B如下:B=gymod n

(5)Bob将B发给Alice

(6)计算秘密密钥K1如下:K1=Bxmod n

(7)计算秘密密钥K2如下:K2=Aymod n K1=K2,因此Alice和Bob可以用其进行加解密

因此,client 和 server 可以“离线“计算出一份只有对方知道的秘钥。

数字证书

公开密钥认证(英语:Public key certificate),又称公开密钥证书公钥证书数字证书(digital certificate)、数字认证身份证书(identity certificate)、电子证书安全证书,是用于 公开密钥基础建设的电子文件,用来证明公开密钥拥有者的 身份。此文件包含了公钥信息、拥有者身份信息(主体)、以及 数字证书认证机构(发行者)对这份文件的 数字签名,以保证这个文件的整体内容 正确无误

包含的内容有:

版本:现行通用版本是 V3
序号:用以辨识每一张证书,特别在撤消证书的时候有用
主体:拥有此证书的法人或自然人身份或机器,包括:
国家(C,Country)
州/省(S,State)
地域/城市(L,Location)
组织/单位(O,Organization)
通用名称(CN,Common Name):在TLS应用上,此字段一般是网域
发行者:以数字签名形式签署此证书的数字证书认证机构
有效期开始时间:此证书的有效开始时间,在此前该证书并未生效
有效期结束时间:此证书的有效结束时间,在此后该证书作废
公开密钥用途:指定证书上公钥的用途,例如数字签名、服务器验证、客户端验证等
公开密钥
公开密钥指纹
数字签名
数字签名算法
主体别名:例如一个网站可能会有多个网域(www.wikipedia.org, zh.wikipedia.org, zh.m.wikipedia.org 都是维基百科)、一个组织可能会有多个网站(*.wikipedia.org, *.wikibooks.org, *.wikidata.org 都是维基媒体基金会旗下的网域),不同的网域可以一并使用同一张证书,方便实现应用及管理

其中,在加密过程中最重要的是公开密钥数字签名算法,前者用来生成 session key,后者是验算 hash 的方法。

CA

数字证书认证机构(英语:Certificate Authority,缩写为CA),也称为电子商务认证中心电子商务认证授权机构,是负责发放和管理数字证书的权威机构,并作为电子商务交易中受信任的第三方,承担公钥体系中公钥的合法性检验的责任。

在 CA 给服务端颁发证书的同时会产生一个私钥和公钥。私钥由服务端自己保存,不可泄漏。公钥则是附带在证书的信息中,可以公开的。证书本身也附带一个证书电子签名,这个签名用来验证证书的完整性和真实性,可以防止证书被串改。

流程

SSL协议分为两部分:Handshake Protocol 和 Record Protocol。其中 Handshake Protocol 用来协商密钥,协议的大部分内容就是通信双方如何利用它来安全的协商出一份密钥。 Record Protocol 则定义了传输的格式。

由于非对称加密的速度比较慢,所以它一般用于密钥交换,双方通过公钥算法协商出一份密钥,然后通过对称加密来通信。

STEP 1:ClientHello

首先,由客户端向服务端发起一个明文的无保护的请求,用来初始化 SSL(这里的客户端只是一个职责的代号,代表"首先发送信息的一方",对前端来说,就是浏览器)。

            message 
clinet +---------------> server

message 中包含以下内容:

  • 客户端最高能支持的协议
  • 一个随机数,称为 client_random
  • session ID(以防客户端想在握手阶段回复 session)
  • 客户端支持的 cipher suite
  • 客户端支持的压缩方法
  • 一些其他信息

这个随机数是会在后面中用到的,其他的是用来标明客户端支持的特性的。

STEP 2: ServerHello

        ServerHello
        Certificate*
        ServerKeyExchange*
        CertificateRequest*
        ServerHelloDone
clinet <---------------------+ server

服务端收到客户端发来的信息,返回给客户端自己的信息,message 中包括

  • 客户端和服务端将使用的协议
  • 一个随机数,称为 server_random
  • 这次会话的 session ID
  • 双方将会使用的 cipher suite
  • 双方将会使用的压缩方法
  • 服务器的证书 + 数字签名
  • ServerKeyExchange: 在服务端向客户端发送的证书中没有提供足够的信息(证书公钥)的时候,用来验证身份。
  • ServerHelloDone(表示 Server Hello 完成)

这里要说一下数字证书与数字签名,数字证书这个东西是向第三方机构去申请的。

数字签名用来保证数字证书没有被篡改过,因为数字签名是用 CA 的私钥来加密的,如果第三方篡改了签名是无法用 CA 的公钥解密的(就伪装不下去了),数字签名也是 CA 给的。

数字签名的过程如下,使用证书中的数字签名算法计算证书的一个 HASH 值,然后 CA 用私钥给加密,然后给服务端,服务端保管好即可。

		 数字签名算法  	      CA私钥加密
数字证书 +-------------> HASH +-------------> 数字签名

服务端发送的信息中还包括 ServerHelloDone,标志着 ServerHello 阶段已经完成,客户端应该发送信息了。

STEP 3:客户端回应

验证证书

client:
+---------------------------------------------------------------------+
|                CA公钥解密                                            |
| 数字签名 +--------------------> 服务端的HASH   +-----+                |
|                                                     |                |
|                                                     +-----> 是否相同  |
|         数字证书中的数字签名算法                      |                |
| 数字证书 +--------------------> 客户端计算的HASH  +-- +                |
|                                                                      |
+----------------------------------------------------------------------+

客户端根据证书中的数字签名算法计算出数字证书的 HASH,再用本地的 CA 公钥(浏览器厂商会内置根证书,可以通过证书链将服务端的证书用内置的根证书认证)。解密出数字签名的 HASH,比较一致则表明这确实是未被篡改过的数字证书。到这一步,客户端已经成功拿到了服务端的公钥。

回应服务端

        Certificate*
        ClientKeyExchange
        CertificateVerify*
        [ChangeCipherSpec]
        Finished    
clinet +---------------------> server
证书

客户端的证书,如果服务端需要的话会发送(比如某些网银需要 U 盾来生成证书验证客户端的身份)

ClientKeyExchange

如果服务端需要对客户端进行验证,在客户端收到服务端的 Server Hello 消息之后,首先需要向服务端发送客户端的证书,让服务端来验证客户端的合法性。

CertificateVerify

如果证书没有问题,客户端就会从服务器证书中取出服务器的公钥。然后,向服务器发送下面三项信息:

  1. 一个随机数。该随机数用服务器公钥加密,防止被窃听(称为 pre-master key)
  2. 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送
  3. 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验
ChangeCipherSpec

ChangeCipherSpec是一个独立的协议,体现在数据包中就是一个字节的数据,用于告知服务端,客户端已经切换到之前协商好的加密套件(Cipher Suite)的状态,准备使用之前协商好的加密套件加密数据并传输了。它标志着从客户端之后发出的信息将使用 shared secret 来进行加密。

Finished

在ChangecipherSpec传输完毕之后,客户端会使用之前协商好的加密套件和 Session Secret 加密一段 Finish 的数据传送给服务端,此数据是为了在正式传输应用数据之前对刚刚握手建立起来的加解密通道进行验证。

STEP 4:服务端回应

         [ChangeCipherSpec]
         Finished    
clinet <---------------------+ server

在这一步,服务端无论如何将得到 pre-master key,但是 SSL 有几种不同的交换密钥的算法,由 cipher suite 来决定,每种密钥交换算法需要不同的公钥来推倒,这里介绍两种:

  1. RSA:服务端的加密方式为 RSA,客户端产生一个随机数,就上上一步中的 pre-master key,然后用服务端的公钥加密,如果是这样的话就不需要传输 ServerKeyExchange。
  2. DHE_RSA:服务端的加密方式为 RSA,不过只是用来签名。真正需要的密钥是用上面介绍的 DH 算法推倒的。ServerKeyExchange 中包含 DH 需要的参数和一个更新过的 DH 公钥,然后服务端对其进行加密发送给客户端。客户端更新这个 DH 公钥返回给 服务端。这个 DH 公钥会产生 pre-master key。

不管用哪种方法,服务端和客户端现在都已经持有 pre-master key 后,使用私钥进行解密获得 pre-master key。再加上自己手上的 server_random 和 client_random,然后客户端和服务端会使用一个PRF(Pseudo-Random Function)来产生master-secret。

master_secret = PRF(pre_master_secret,  "master secret",  ClientHello.random + ServerHello.random)

再由 master-secret 推导出 session-key(也称 shared-secret),这是双方后续通信用来最终加密的对称密钥。

一切准备好之后,服务端也回应客户端一个自己的用 session-key 加密的 ChangeCipherSpec,标明自己之后的信息也将使用 session-key 来加密。之后,服务端也会使用 session-key 加密一段 Finish 消息发送给客户端,以验证之前通过握手建立起来的加解密通道是否成功。

STET 6:HTTPS 通信

根据之前的握手信息,如果客户端和服务端都能对Finish信息进行正常加解密且消息正确的被验证,则说明握手通道已经建立成功,接下来,双方可以使用上面产生的 session-key 对数据进行加密传输了。

总结

最后放上一张图来总结整个 SSL 的过程,其中加密方式采用的是 RSA,但是整个流程是思路是一致的。
其实 HTTPS 要复杂的多,本文介绍的过程是简化了的,主要是理清如何安全获得对称公钥。
via The SSL/TLS Handshake: an Overview

ssltls_handshake

GOOD & BAD

放上 HTTPS 的好处与坏处,via https是什么?使用https的好处与不足?

好处

正是由于HTTPS非常的安全,攻击者无法从中找到下手的地方,从站长的角度来说,HTTPS的优点有以下2点:

  1. SEO方面 谷歌曾在2014年8月份调整搜索引擎算法,并称“比起同等HTTP网站,采用HTTPS加密的网站在搜索结果中的排名将会更高”。

  2. 安全性 尽管HTTPS并非绝对安全,掌握根证书的机构、掌握加密算法的组织同样可以进行中间人形式的攻击,但HTTPS仍是现行架构下最安全的解决方案,主要有以下几个好处:

    1. 使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;
    2. HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性。
    3. HTTPS是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。

不足

虽然说HTTPS有很大的优势,但其相对来说,还是有些不足之处的,具体来说,有以下2点:

  1. SEO方面 据ACM CoNEXT数据显示,使用HTTPS协议会使页面的加载时间延长近50%,增加10%到20%的耗电,此外,HTTPS协议还会影响缓存,增加数据开销和功耗,甚至已有安全措施也会受到影响也会因此而受到影响。

    而且HTTPS协议的加密范围也比较有限,在黑客攻击、拒绝服务攻击、服务器劫持等方面几乎起不到什么作用。

    最关键的,SSL证书的信用链体系并不安全,特别是在某些国家可以控制CA根证书的情况下,中间人攻击一样可行。

  2. 经济方面

    1. SSL证书需要钱,功能越强大的证书费用越高,个人网站、小网站没有必要一般不会用。
    2. SSL证书通常需要绑定IP,不能在同一IP上绑定多个域名,IPv4资源不可能支撑这个消耗(SSL有扩展可以部分解决这个问题,但是比较麻烦,而且要求浏览器、操作系统支持,Windows XP就不支持这个扩展,考虑到XP的装机量,这个特性几乎没用)。
    3. HTTPS连接缓存不如HTTP高效,大流量网站如非必要也不会采用,流量成本太高。
    4. HTTPS连接服务器端资源占用高很多,支持访客稍多的网站需要投入更大的成本,如果全部采用HTTPS,基于大部分计算资源闲置的假设的VPS的平均成本会上去。
    5. HTTPS协议握手阶段比较费时,对网站的相应速度有负面影响,如非必要,没有理由牺牲用户体验。

参考

RSA的公钥和私钥到底哪个才是用来加密和哪个用来解密?

Diffie-Hellman密码交换是如何运作的?

迪菲-赫尔曼密钥交换

公开密钥认证

SSL/TLS原理详解

https的pre-master-secret到master-secret的过程?

Differences between the terms “pre-master secret”, “master secret”, “private key”, and “shared secret”?

How does SSL/TLS work?

What's the point of the pre-master key? [duplicate]

The SSL/TLS Handshake: an Overview