在互联网世界,我们广泛采用 TLS 来保护通信安全,这里的安全主要包含两部分内容:身份鉴别、通信加密。身份鉴别是一切的基础,特别当发送消息比较敏感需要加密时,对接收方必然有一个身份“假设”,“假设”如何证实就是靠鉴别,而鉴别的前提是有一套身份标记规范——如中国的公民身份证、美国的社会保障号。

一切活动都是不同实体间的互动,虚拟世界要运作起来首先也必须建立各种实体,标记其身份,特别是需要和物理世界的实体进行对应时 —— 至于如何对应又是另一个复杂问题,这种映射到物理世界的困难似乎是所有概念的宿命。

整体结构

在互联网世界里,是通过 PKI(Public-Key Infrastructure,公钥基础设施)来建立身份体系,使用的标准为 X.509。在 X.509 中规定采用证书来标记身份(根本上还是非对称加密技术,此处不赘述),并通过相关的参与方来管理证书的整个生命周期。

在 PKI 体系中,主要有 4 个参与方:

  • CA(Certification Authority),证书颁发机构,核心设施,负责颁发、吊销证书;
  • RA(Registration Authority),证书登记机构,在现实中核实申请证书的用户身份,此功能可以合并到 CA 中;
  • 证书申请用户,使用证书来表明自己的合法身份,通常为网站;
  • 终端浏览器,用户通过浏览器访问网站的 https 地址,在建立 tls 会话的过程中获取证书、鉴别网站身份。

通常情况下,只需要单向认证,整个过程如下:

  1. 网站需要先生成证书签名申请(CSR,Certificate Signing Request),主要包含公钥、网站域名(可以有多个),以及私钥对申请信息的签名
  2. 将 CSR 提交 CA,CA 核实后生成网站证书,颁发给网站;
  3. 网站在 SSL 网关(如 Nginx)上配置证书(如果网站证书往上还有若干中间证书,则最好把中间证书和网站证书都放在一起),启用 https;
  4. 浏览器访问 https 网址,在 tls 握手过程中读取到网站证书;
  5. 查询 CRL(Certificate Revocation List,证书撤销列表)、OCSP(Online Certificate Status Protocol),验证证书的有效性,并从网站证书开始,循着证书链验证每一个节点的证书合法性。

证书

内容

证书就是实体的身份证,里面主要包含了实体的公钥以及 CA 机构的认证签名。

格式

证书有多种存放格式,主要有以下三种:

  • DER(Distinguished Encoding Rules),一种二进制编码格式;
  • BER(Basic Encoding Rules),是 DER 的子集
  • PEM(Privacy-enhanced Electronic Mail),是 DER 经过 BASE64 编码后的格式。

还有一种证书格式为 PFX,给客户端浏览器用的,PFX 文件中除了证书,还包含私钥(在双向认证里证明客户端身份),文件后缀为 .pfx 或 .p12。

申请

有 3 种证书申请类型:

  • DV(Domain Validation),全自动签发,只需要验证域名是申请者所有的就行,一般是发一封邮件给域名管理者,点击确认后即自动签发证书;
  • OV(Organization Validation),人工核验,审核相对严格一点;
  • EV(Extended Validation),弥补 OV 审核的不足,证书审核遵照 Baseline Requirements 里的要求,严格。

当然价格和售后服务也是不一样的,EV 最贵。网站一般用 DV 证书,比如博主用的就是 Let’s Encrypt 上薅的免费 DV 证书。

从对应域名的能力来看,证书又可以分为 4 种类型:

  • 单域名证书,只对应一个具体域名,如 www.chenqing.work;
  • 泛域名证书,对应一类域名,如 *.chenqing.work;
  • SAN 域名证书,对应多个具体域名,一般这多个域名无法合并到一个泛域名下,如 www.chenqing.work、www.chenqing.life;
  • SAN 泛域名证书,对应多个泛域名,如 *.chenqing.work、*.chenqing.life。

价格上肯定单域名的最便宜,能匹配越多域名的越贵。

Spring Docs 网站证书里的域名

关于证书,国内和国际还有一点差异,国际标准一般称为单证,用户使用唯一的一张证书及对应私钥进行签名和加密操作;而国内称为双证,签名的一对公私钥是自己生成,但加密过程中用的公私钥是由 CA 生成。

信任

身份通过证书来唯一标记,那如何验证证书的合法性?

首先来看一下网站证书,证书必须包含的内容之二是:颁发者(issuer)、颁发对象(subject)。结合当前证书的其他相关字段可以确证是该颁发者认证并颁发了证书给颁发对象。只要颁发者是合法的,那么颁发对象就是合法的,这样问题就递进为确认颁发者是不是合法的。


上推一级,去拿颁发者的证书,颁发者的证书中同样具有“颁发者”、“颁发对象”这两项内容,以此类推,就构成了一条证书链,当然链条的每个咬合点都需要使用签名来保障真实性。(猜猜区块链技术有没有借鉴它?)

因为证书链不可能无限长,上推到某一节点必须停止,在该节点“颁发者”、“颁发对象”是同一个,称为根证书,根证书显然为自签名证书。到这里问题就归约为根证书是否合法


根证书怎么验证合法性?通过网络请求 CA 鉴别?

问题是,通过网络请求 CA 进行鉴别前,需要先鉴别自称是 CA 的服务发来的证书是否表明它就是 CA。这就陷入了鸡生蛋还是蛋生鸡的循环,总之至少要预先共享一点啥。

解决方法还是物理配送,即在操作系统、浏览器中下锚——预置信任的根证书,如此整个信任链条就建立起来了。

所谓互联网上公开受信的证书,就是其根证书在操作系统、浏览器中有预置的证书。所以开发环境自签名证书时,需要将根证书手工导入操作系统或浏览器的受信任根证书区域,这样用户就不会收到浏览器的警告。


参考

  • 《HTTPS 权威指南》
  • 《Web 性能权威指南》
  • 《深入浅出 HTTPS》
分类: CODE

0 条评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注