前言

最近在考虑搭建 Internal PKI,于是开始学习安全和加密相关的知识。在学习 PKI 之前,我对证书的认识还很模糊,觉得最大的用途可能就是实现 HTTP 的加密请求。但是阅读了一些相关题材的博客和文档后发现,它远比我所了解的要复杂!

你必须牢记各种概念,并且将它们带入到实际的需求中,才能够加强对这些概念的理解。

因为在安全领域很多事情我们无法做到完美,加之涉及的领域又比较广泛和深入。例如会涉及数学,加密,算法等等,但最让人摸不着头脑的是各种证书格式以及加密算法,光记住名称对于大多数人来说就已经很头疼了!

互联网安全问题

虽则 Web 的发展,主要暴露了如下三个问题:

  • 通信数据可能被窃取:因为 HTTP 本身不具备加密功能,所有流量都是透明的,容易窃取一些如登录密码等敏感数据;
  • 通信数据可能被篡改:因为流量是透明的,如果由中间人拦截,然后篡改通信数据;
  • 无法验证通信方身份:因为 HTTP 不具备服务端身份认证功能,那么可以通过使用与被伪造域名近似的域名进行钓鱼。

为了解决上面的三个问题,便有了 SSL/TLS,那么 SSL 层是如何解决上述问题的呢?

SSL/TLS 解决通信数据可能被窃取

SSL/TLS 的功能实现主要依赖于三类基本算法:散列函数对称加密非对称加密,其利用非对称加密实现身份认证和密钥协商,对称加密算法采用协商的密钥对数据加密,基于散列函数验证信息的完整性。

使用对称密钥的好处是解密的效率比较快,使用非对称密钥的好处是可以使得传输的内容不能被破解,因为就算你拦截到了数据,但是没有对应的私钥,也是不能破解内容的,所以我们可以将对称加密与非对称加密结合起来,充分利用两者各自的优势,在交换密钥环节使用非对称加密方式,之后的建立通信交换报文阶段则使用对称加密方式。

具体做法是,发送密文的一方使用对方的公钥进行加密处理对称的密钥,然后对方用自己的私钥解密拿到对称的密钥,这样可以确保交换的密钥是安全的前提下,使用对称加密方式进行通信,所以 HTTPS 采用对称加密和非对称加密两者并用的混合加密机制。

解决通信数据可能被篡改

网络传输过程中需要经过很多中间节点,虽然数据无法被解密,但可能被篡改,那如何校验数据的完整性呢?在这种情况下我们就可以考虑使用校验数字签名,通常数字签名有两种功效:

  • 能确定消息确实是由发送方签名并发出来的,因为别人假冒不了发送方的签名
  • 数字签名能确定消息的完整性,证明数据是否未被篡改过

接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用 Hash 函数对收到的原文产生一个摘要信息,与上一步得到的摘要信息对比,如果相同,则说明收到的信息是完整的,在传输过程中没有被修改,否则说明信息被修改过,因此数字签名能够验证信息的完整性。

解决无法验证通信方身份

上面我们提到了数字签名很美好!你可以使用公钥来进行解密,说明确实是私钥方发送的,但是有没有想过,万一这把公钥本身,就被人做了手脚呢?所以为了保证公钥是可信的,这里就引出了证书颁发机构(Certificate Authority,简称 CA,也就是所谓的第三方认证中心)。

这里唯一不同的是,假设对网站信息加密的算法是 MD5,通过 MD5 加密后,然后通过第三方机构的私钥再次对其加密,这样的话,数字证书包含有两个特别重要的信息,即某网站公钥 + 数字签名,假如中间人拦截后把服务器的公钥替换为自己的公钥,因为数字签名的存在,会导致客户端验证签名不匹配,这样就防止了中间人替换公钥的问题。

下面我们来看一下客户端是如何去对比两者数字签名的:

  • 浏览器会去安装一些比较权威的第三方认证机构的公钥,比如 VeriSign、Symantec 以及 GlobalSign 等等;
  • 验证数字签名的时候,会直接从本地拿到相应的第三方的公钥,对私钥加密后的数字签名进行解密得到真正的签名;
  • 然后客户端利用签名生成规则进行签名生成,看两个签名是否匹配,如果匹配认证通过,不匹配则获取证书失败。

这里存在一个问题,那就是既然有第三方认证,为什么我们不直接使用第三方认证的方式来进行加密呢?

这是因为第三方认证机构是一个公开的平台,中间人可以去获取,如果只是对网站信息进行第三方机构私钥加密的话,还是会受到欺骗。

因为没有认证,所以中间人也向第三方认证机构进行申请,然后拦截后把所有的信息都替换成自己的,客户端仍然可以解密,并且无法判断这是服务器的还是中间人的,最后造成数据泄露,这其实也就是数字签名作用。

HTTPS 工作流程

HTTPS 工作流程

  • Client 发起一个 HTTPS 的请求,连接 443 端口,这个过程可以理解成是请求公钥的过程
  • Server 端收到请求后,通过第三方机构私钥加密,会把数字证书(也可以认为是公钥证书)发送给 Client
  • Client 验证公钥证书,比如是否在有效期内,证书的用途是不是匹配 Client 请求的站点,是不是在 CRL 吊销列表里面,它的上一级证书是否有效,这是一个递归的过程,直到验证到根证书(操作系统内置的 Root 证书或者 Client 内置的 Root 证书),如果验证通过则继续,不通过则显示警告信息
  • Client 使用伪随机数生成器生成加密所使用的对称密钥,然后用证书的公钥加密这个对称密钥,发给 Server
  • Server 使用自己的私钥(private key)解密这个消息,得到对称密钥,至此,Client 和 Server 双方都持有了相同的对称密钥
  • Server 使用对称密钥加密明文内容 A,发送给 Client
  • Client 使用对称密钥解密响应的密文,得到明文内容 A
  • Client 再次发起 HTTPS 的请求,使用对称密钥加密请求的明文内容 B,然后 Server 使用对称密钥解密密文,得到明文内容 B

那么什么是证书呢

了解完整个 HTTPS 工作流程后,我们得到一个结论:

证书的目的就是将某个实体的 Identity 与其对应的 Public Key 绑定在一起,并加以签名仿制被伪造或篡改。

上面提到的实体 (Entity) 是任何存在的东西(Anything that exists)即使只在逻辑或概念上存在(Even if only exists logically or conceptually)。

例如:

  • 你用的计算机是一个 Entity;
  • 你写的代码也是一个 Entity;
  • 你自己也是一个 Entity;
  • 你早餐吃的杂粮饼也是一个 Entity;
  • 你六岁时见过的鬼也是一个 Entity —— 即使你妈妈告诉你世界上并没有鬼,这只是你的臆想。

我们可以使用工具来观察浏览器拿到的证书是这样的(其中 #– XXX –# 是我用于注释的内容):

step certificate inspect https://george.betterde.com
Certificate:
    Data:
        Version: 3 (0x2) #-- X.509 v3 证书 --#
        Serial Number: 277028619957168996496866148377847610215553 (0x32e1d2b7678a3cde0a0aff3d8973da00c81) #-- 唯一 Serial Number --#
    Signature Algorithm: SHA256-RSA
        Issuer: C=US,O=Let's Encrypt,CN=R3 #-- 颁发机构:Let's Encrypt --#
        Validity #-- 证书起始有效期和截止有效期 --#
            Not Before: Nov 15 07:22:21 2022 UTC
            Not After : Feb 13 07:22:20 2023 UTC
        Subject: CN=george.betterde.com
        Subject Public Key Info:
            Public Key Algorithm: RSA #-- 证书公钥 --#
                Public-Key: (4096 bit)
                Modulus:
                    a3:5d:2a:3c:6c:f7:b0:d6:6d:c1:97:0f:42:c4:7c:
                    7e:76:f7:5a:02:30:8b:12:fb:52:ca:aa:14:f3:a1:
                    45:90:48:41:27:76:4a:14:be:a8:28:24:45:d8:4f:
                    8f:dd:a5:0e:56:bb:f8:a1:65:05:cd:f5:fb:a3:0b:
                    77:da:89:30:64:c5:4e:ec:f4:be:b4:ae:6a:75:24:
                    25:6b:61:12:3d:df:ef:47:60:f9:fd:20:d0:d3:3e:
                    57:c8:c4:73:7e:ea:89:c3:df:6e:f8:a9:72:60:b3:
                    d4:b9:83:27:74:c4:cb:19:49:c2:1f:87:a8:a2:72:
                    50:11:f0:4f:4a:dc:1d:4f:3b:f7:df:a0:e3:07:e6:
                    33:45:cf:96:0a:ab:4f:90:ad:5e:8b:25:bb:c5:0d:
                    93:bb:7c:da:88:ae:c0:97:e9:f4:1d:a4:c1:82:00:
                    9b:3a:cb:a7:75:72:1f:12:ee:22:63:de:49:e9:dc:
                    fe:d3:79:ec:e5:a1:18:19:5b:ae:c2:a1:19:d8:73:
                    78:3d:45:9b:d1:32:f3:c8:a0:39:c3:f4:fc:80:7a:
                    70:de:c1:ac:a4:bf:92:b2:d7:d1:66:d6:b3:1a:de:
                    80:ed:53:6a:45:ef:87:4f:d1:c7:3a:1a:60:98:1d:
                    e6:f6:7d:17:07:38:4d:91:29:4c:9b:01:ef:f4:d3:
                    ea:d8:c5:15:e2:aa:01:a5:c7:fb:7e:fb:eb:7d:7a:
                    0f:7f:cc:41:cf:c9:31:a7:2e:2e:8a:c1:2e:f3:55:
                    7f:3b:aa:b5:76:58:b2:dd:a1:81:b8:1c:9d:f7:57:
                    56:93:a3:61:88:07:23:4c:86:bc:38:15:bd:17:0a:
                    88:f1:bc:4f:b7:83:b7:f8:0b:81:46:41:b4:a8:ac:
                    38:96:b9:8b:8a:32:98:8b:0c:fb:26:07:b9:c7:38:
                    c1:f8:f3:92:6a:b4:f2:38:aa:2c:78:18:ae:05:3c:
                    78:e1:4d:c9:5a:2f:8e:14:a1:e4:bf:2e:5a:f0:a0:
                    a6:37:56:e2:c0:76:d1:df:f4:8b:49:12:f2:f4:40:
                    ae:a6:63:44:cb:22:df:c9:7a:72:61:0a:68:56:1b:
                    da:a5:6a:21:98:3e:a3:d7:11:36:fa:82:f2:e8:43:
                    83:b0:b7:5a:ba:7c:b6:54:6b:cf:b6:bb:64:b1:17:
                    a6:6f:74:e2:af:51:62:af:63:d3:37:03:a7:23:f3:
                    25:15:bd:fa:0e:e1:25:b3:20:48:98:d6:45:8c:70:
                    3f:30:84:f4:83:8d:96:ad:b9:7f:f4:ac:a3:b8:08:
                    9c:55:8c:df:61:e1:d1:67:05:cf:63:82:ae:a4:96:
                    97:4e:ad:b3:15:33:20:ec:32:a9:c9:fd:0a:20:07:
                    4a:db
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment #-- 描述公钥用途 --#
            X509v3 Extended Key Usage:
                Server Authentication, Client Authentication #-- 描述公钥用途 --#
            X509v3 Basic Constraints: critical
                CA:FALSE #-- 不是 CA 证书 --#
            X509v3 Subject Key Identifier:
                91:AC:86:05:F8:94:F1:26:6F:4A:CE:DA:04:F2:69:52:00:55:81:D2
            X509v3 Authority Key Identifier:
                keyid:14:2E:B3:17:B7:58:56:CB:AE:50:09:40:E6:1F:AF:9D:8B:14:C2:C6
            Authority Information Access:
                OCSP - URI:http://r3.o.lencr.org #-- OCSP --#
                CA Issuers - URI:http://r3.i.lencr.org/ #-- 颁发者 URL --#
            X509v3 Subject Alternative Name:
                DNS:george.betterde.com #-- SAN,对应文中的 Entity Name --#
            X509v3 Certificate Policies: #-- CA 遵循的策略 --#
                Policy: 2.23.140.1.2.1
                Policy: 1.3.6.1.4.1.44947.1.1.1
            RFC6962 Certificate Transparency SCT:
                SCT [0]:
                    Version: V1 (0x0)
                    LogID: tz77JN+cTbp18jnFulj0bF38Qs96nzXEnh0JgSXttJk=
                    Timestamp: Nov 15 08:22:21.996 2022 UTC
                    Signature Algorithm: SHA256-ECDSA
                      30:44:02:20:2a:3f:27:09:57:5c:f2:09:95:59:1c:8b:7b:c3:
                      f0:52:71:b1:39:49:05:4d:9b:fd:6a:f5:da:43:e0:21:af:b5:
                      02:20:29:90:1c:36:36:db:8f:0d:15:79:b7:66:50:48:22:7d:
                      6d:e0:f3:6c:64:88:8c:77:9a:ae:bb:ad:3f:32:16:2c
                SCT [1]:
                    Version: V1 (0x0)
                    LogID: ejKMVNi3LbYg6jjgUh7phBZwMhOFTTvSK8E6V6NS61I=
                    Timestamp: Nov 15 08:22:22.064 2022 UTC
                    Signature Algorithm: SHA256-ECDSA
                      30:44:02:20:11:01:00:93:31:9e:b6:f5:28:bd:2d:c2:88:f0:
                      d2:c7:43:a9:c4:4b:89:ab:c2:76:53:55:27:60:b7:e4:e0:e8:
                      02:20:3d:a6:ec:68:1a:e2:60:6d:a7:62:87:70:be:de:c2:08:
                      86:03:07:ee:4d:b4:c0:b8:c0:32:8e:80:9b:c9:fd:67
    Signature Algorithm: SHA256-RSA #-- 公钥签名,用于验证公钥是否被篡改 --#
         4a:b6:6e:1b:27:db:1f:7e:4c:13:c3:21:18:06:88:81:d7:30:
         b4:7d:26:d4:4a:30:ca:15:cc:5f:ca:42:aa:ee:69:90:ae:8b:
         98:e1:ea:63:69:53:ff:a2:f6:86:d4:04:33:12:57:2a:df:fc:
         83:be:b5:2f:6c:41:62:11:e2:3b:60:56:ad:0a:a3:5f:45:6b:
         49:1b:8b:65:ca:f7:a9:17:97:06:9f:1b:0e:06:0f:70:c5:66:
         3d:72:ca:11:d0:b4:4b:73:91:58:df:6a:7f:09:b5:5c:8b:40:
         51:48:98:f9:5c:65:6c:8f:83:9b:f0:e7:86:5f:c6:e8:50:ed:
         7f:55:1b:88:86:d8:f6:e5:95:21:60:f4:fa:88:86:f2:28:7f:
         72:79:27:80:6d:c7:ff:25:6d:4c:41:dd:c7:5b:91:4b:08:28:
         26:33:0e:16:93:7f:1e:7d:86:a9:ce:0d:5b:31:85:b2:83:fd:
         1f:c7:9c:1d:f3:43:9b:c1:8e:8b:1c:80:f3:65:5c:80:e6:42:
         40:15:e5:20:2e:66:4d:bd:a7:02:e1:5d:ca:05:dc:59:bb:46:
         e8:f9:34:35:33:cb:d6:e5:65:6a:b7:40:60:aa:9b:26:d1:68:
         ee:ed:80:18:56:ec:52:01:3e:fa:30:cf:f5:dc:e4:d9:0f:32:
         ab:81:ec:24

可以看出证书中主要包含的信息就是:

  • 签发者信息
  • 所有者信息
  • 公钥信息
  • 遵循的策略
  • CA 机构对证书的签名

证书的类型

DV (Domain Validation)

DV 证书绑定的是 DNS Name,CA 在颁发时需要验证的这个 Domain Name 确实是由该 Subscriber 控制的。

OV (Organization Validation)

OV 和下面将介绍的 EV 证书构建在 DV 证书之上,它们包括了 Name 和 Domain Name 所属组织的位置信息(Location)。OV 和 EV 证书不仅仅将证书关联到域名,还关联到控制这个域名的法律实体(Legal Entity)。

OV 证书的验证过程,不同的 CA 并不统一,为解决这个问题,CAB Forum 引入了 EV 证书。

EV (Extended Validation)

EV 证书包含的基本信息与 OV 是一样的,但强制要求严格验证(Identity Proofing)。这种证书会在浏览器 URL 地址栏上显示证书所有者的组织信息。

但这种证书的实际使用率并不高,因为成本太高,第一是时间成本(审核时间较长,可能需要几周),第二是资金成本(可能需要数万美元),再则 Web PKI RP 也未强依赖它。

证书的生命周期

苹果公司在第 49 届 CA/浏览器论坛(CA/Browser)会议上宣布:为了提高网络安全性,任何有效期超过了 398 天的新网站证书都将不会受到 Safari 浏览器的信任。但是,在截止日期(2020年9月1日)之前颁发的证书不受此规则的影响。

简单来说当 SSL 证书同时满足以下条件时,将不会被 Safari 信任:

  1. 在2020年9月1日之后签发
  2. 有效期超过398天

在 2020年9月1日前签发的证书不受影响。此举目的是通过确保开发者使用最新加密标准的证书来提高网站的安全性,并减少被忽视的旧证书的数量,这些证书有可能被盗窃,并被用于网络钓鱼和驱动器恶意软件攻击。

过期

证书通常都会过期,虽然这不是强制规定,但一般都这么做。设置一个过期时间非常重要!

  • 证书都是分散在各处的:通常 RP 在验证一个证书时,并没有某个中心式权威能感知到(这个操作)。
  • 如果没有过期时间,证书将永久有效。
  • 安全领域的一条经验就是:时间过的越久,凭证被泄露的概率就越接近 100%。

因此,设置过期时间非常重要。具体来说,X.509 证书中包含一个有效时间范围:

  • Issued at
  • Not before
  • Not after:过了这个时间,证书就过期了。

这个机制看起来设计良好,但实际上也是有一些不足的:

  • 首先,没有什么能阻止 RP 错误地(或因为糟糕的设计)接受一个过期证书;
  • 其次,证书是分散的。验证证书是否过期是每个 RP 的责任,而有时它们会出乱子。例如,RP 依赖的系统时钟不对时。 最坏的情况就是系统时钟被重置为了 Unix epoch(1970.1.1),此时它无法信任任何证书。

在 Subscriber 侧,证书过期后,私钥要处理得当:

  • 如果一个密钥对之前是用来签名/认证的(例如,基于 TLS),
    • 应该在不需要这个密钥对之后,立即删除私钥。
    • 保留已经失效的签名秘钥(signing key)会导致不必要的风险:对谁都已经没有用处,反而会被拿去仿冒签名。
  • 如果密钥对是用来加密的,情况就不同了。
    • 只要还有数据是用这个加密过的,就需要留着这个私钥。

这就是为什么很多人会说,不要用同一组秘钥来同时做签名和加密(Signing and encryption)。 因为当一个用于签名的私钥过期时,无法实现秘钥生命周期的最佳管理: 最终不得不保留着这个私钥,因为解密还要用它。

续期

证书快过期时,如果还想继续使用,就需要续期。Web PKI 实际上并没有标准的续期过期:

  • 没有一个标准方式来延长证书的合法时间;
  • 一般是直接用一个新证书替换过期的;
  • 因此续期过程和颁发过程是一样的:生成并提交一个 CSR,然后完成 Identity Proofing。

撤销

如果一个私钥泄露了,或者一个证书已经不再用了,就需要撤销它。即希望:

  • 明确地将其标记为非法的;
  • 所有 RP 都不再信任这个证书了,即使它还未过期。

但实际上,撤销证书过程也是一团糟。主动撤销证书的困难如下:

  • 与过期类似,执行撤回的职责在 RP;
  • 与过期不同的是,撤销状态无法编码在证书中。RP 只能依靠某些带外过程(Out-of-band process) 来判断证书的撤销状态。

除非显式配置,否则大部分 Web PKI TLS RP 并不关注撤销状态。换句话说,默认情况下,大部分 TLS 实现都乐于接受已经撤销的证书。

另外常常见的主动检查机制有:

  • CRL (Certificate Revocation Lists,证书撤销列表,RFC 5280)
  • OCSP (Online Certificate Signing Protocol,在线证书签名协议,RFC 2560)

总结

在这片文章中,大致了解了 HTTPS 的流程和证书的相关细节,后续会继续探索 PKI 和加密相关内容。

加密领域有沉重的历史包袱,使当前的这些东西学起来、用起来非常让人沮丧,这比一项技术因为太难而不想学更加令人沮丧。

I hope this is helpful, Happy hacking…