心宇

FDF24DCED8C6738F8313A6D3B073C3F4

首页 管理

本文从数字证书的基本概念开始,详细介绍 CA 机构、PKI 信任体系、Let's Encrypt 证书申请流程、证书文件结构、证书链验证、TLS 1.3 握手原理,以及浏览器和 Nginx 如何加密与解密 HTTPS 数据。


一、数字证书是什么?有什么作用?

1.1 为什么需要 HTTPS?

在理解数字证书之前,首先需要了解 HTTP 协议存在的问题。

HTTP 是应用层协议,传统 HTTP 通常通过 TCP 明文传输数据。

例如,浏览器向服务器发送登录请求:

POST /login HTTP/1.1
Host: example.com
Content-Type: application/json

{
    "username": "admin",
    "password": "123456"
}

如果使用没有额外安全保护的 HTTP,攻击者可能通过网络监听获取请求内容。

HTTP 明文传输主要存在三个问题:

1. 数据可能被窃听

攻击者可以读取传输中的用户名、密码、Cookie 等敏感信息。

2. 数据可能被篡改

攻击者可能在传输过程中修改 HTTP 请求或响应。

例如,将网页中的软件下载地址替换成恶意程序地址。

3. 无法可靠验证服务器身份

客户端可能连接到攻击者伪装的服务器。

为了解决这些问题,出现了 HTTPS。

HTTPS = HTTP + TLS

TLS(Transport Layer Security)是传输层安全协议。

TLS 主要提供三个安全属性:

安全属性 作用
机密性 防止第三方读取通信内容
完整性 检测通信数据是否遭到篡改
身份认证 验证通信对方的身份

其中,数字证书主要解决身份认证以及公钥与身份的可信绑定问题。

需要注意,HTTPS 并不意味着网站本身绝对安全,它无法阻止服务器漏洞、恶意网页或终端设备被入侵等问题。


1.2 什么是数字证书?

数字证书(Digital Certificate)是一种经过数字签名的数据结构。

HTTPS 使用的证书通常遵循 X.509 标准。

数字证书可以理解为:

由可信机构签发的、用于证明某个身份与某个公钥之间关联关系的电子凭证。

例如:

网站域名:example.com

网站公钥:Public Key

证书颁发机构:Let's Encrypt

证书有效期:指定的起止时间

CA 数字签名:Signature

CA 通过数字签名,证明它按照相应规则验证并签发了这张证书。

浏览器通过验证证书签名、域名和证书链等信息,判断服务器身份是否可信。

数字证书通常包含什么?

字段 作用
Version X.509 证书版本
Serial Number 证书序列号
Signature Algorithm 证书签名算法
Issuer 签发证书的 CA
Subject 证书主体信息
Validity 证书有效期
Subject Public Key Info 公钥及公钥算法
Subject Alternative Name 证书适用的域名或 IP
Key Usage 公钥允许的用途
Extended Key Usage 例如 TLS 服务器身份认证
Basic Constraints 是否属于 CA 证书
Signature Value 签发者生成的数字签名

现代 HTTPS 域名匹配主要依据 SAN(Subject Alternative Name)扩展。

证书中包含公钥,但不包含对应的服务器私钥。


二、公钥、私钥和数字签名

2.1 什么是非对称密码学?

非对称密码学使用一对相互关联的密钥:

          密钥对
             |
       +-----+-----+
       |           |
       v           v
     公钥         私钥
  Public Key   Private Key

公钥可以公开。

私钥必须由持有者妥善保管。

不同密码算法对公私钥的使用方式不同。

例如:

  • RSA 可以用于数字签名,也可以在适当的加密方案中用于加密。
  • ECDSA 用于数字签名。
  • ECDHE 用于临时密钥协商。

不能把所有公私钥算法都简单理解为“公钥加密、私钥解密”。


2.2 什么是数字签名?

数字签名主要用于验证:

  1. 签名是否由对应私钥持有者生成。
  2. 被签名的数据是否遭到修改。

以 CA 签发证书为例。

CA 签名过程

       待签发的证书内容
               |
               v
        按签名算法处理
               |
               v
        CA 使用私钥签名
               |
               v
           数字签名
               |
               v
       附加到 X.509 证书

签名的具体计算方式取决于 RSA-PSS、ECDSA 等签名算法。

浏览器验证过程

       网站数字证书
             |
             v
     获取证书签名和内容
             |
             v
     获取签发 CA 的公钥
             |
             v
       验证数字签名
             |
       +-----+-----+
       |           |
       v           v
     成功          失败
       |           |
       v           v
  继续证书检查   证书验证失败

注意:

数字签名验证成功,只说明签名与对应公钥匹配,并不自动说明该 CA 值得信任。

浏览器还必须建立有效的证书信任链。


三、什么是 CA 机构?

3.1 CA 的定义

CA 全称:

Certificate Authority

中文称为:

证书颁发机构

常见的公开 CA 包括:

  • Let's Encrypt
  • DigiCert
  • GlobalSign
  • Sectigo

CA 的主要职责包括:

  1. 验证证书申请者是否满足签发条件。
  2. 签发数字证书。
  3. 使用 CA 私钥对证书进行数字签名。
  4. 管理证书生命周期。
  5. 提供证书吊销或状态查询相关服务。
  6. 遵守证书签发和审计要求。

例如,Let's Encrypt 可以验证申请者是否控制 example.com 域名。

验证通过后,Let's Encrypt 才会签发对应的域名证书。


3.2 CA 为什么可信?

浏览器不会信任所有 CA。

操作系统或浏览器维护着一组可信任的根证书。

这组证书称为:

Root Certificate Store

即根证书信任库。

例如:

浏览器 / 操作系统
       |
       v
  可信根证书库
       |
       +-- Root CA A
       |
       +-- Root CA B
       |
       +-- Root CA C

如果网站证书能够通过有效证书链连接到可信根证书,并且满足域名、用途、有效期等安全要求,浏览器才会接受它。

不同浏览器和操作系统使用的信任库可能不同。


四、什么是 PKI 公钥基础设施?

PKI 全称:

Public Key Infrastructure

中文称为:

公钥基础设施

PKI 是一套用于管理公钥、数字证书、信任关系和证书生命周期的技术体系。

主要组成包括:

组成部分 作用
CA 证书签发机构
RA 注册与身份验证机构
Root CA 根证书机构
Intermediate CA 中间证书机构
Certificate 数字证书
Private Key 私钥
Root Store 可信根证书库
CRL 证书吊销列表
OCSP 在线证书状态协议
CT 证书透明度机制

其中 RA 的工作也可以由 CA 自己承担。

PKI 的核心目的,是让通信双方能够在没有事先交换私钥的情况下,建立可信的身份认证关系。


五、根证书、中间证书、叶子证书

HTTPS 证书通常采用分层信任体系。

典型结构:

                  Root CA
                   根 CA
                     |
                     |
                     v
              Intermediate CA
                 中间 CA
                     |
                     |
                     v
                example.com
                 叶子证书

5.1 根证书(Root Certificate)

根证书处于信任体系的顶层。

根证书通常由根 CA 自签名。

例如:

Subject: Root CA
Issuer:  Root CA

根证书通常具有:

Basic Constraints:
    CA:TRUE

根证书对应的私钥用于签发下级 CA 证书。

根 CA 私钥需要受到极其严格的保护。

为什么根证书是可信的?

不是因为它进行了自签名。

而是因为浏览器或操作系统事先将其配置为可信任的信任锚。

任何人都可以创建自签名证书,但不能因此让浏览器自动信任。


5.2 中间证书(Intermediate Certificate)

中间 CA 证书由上级 CA 签发。

它可以在被授权的范围内签发下级证书。

例如:

Root CA
   |
   v
Intermediate CA
   |
   v
example.com

中间证书的作用主要包括:

  1. 减少根 CA 私钥的使用。
  2. 实现证书签发权限分层。
  3. 隔离不同签发体系的风险。
  4. 方便管理和更换签发机构。

中间 CA 通常具有:

Basic Constraints:
    CA:TRUE

证书链也可能存在多个中间 CA。

例如:

Root CA
   |
   v
Intermediate CA A
   |
   v
Intermediate CA B
   |
   v
example.com

5.3 叶子证书(Leaf Certificate)

叶子证书也称:

End-Entity Certificate

即终端实体证书。

网站证书就是常见的叶子证书。

例如:

example.com.cer

它通常具有:

Basic Constraints:
    CA:FALSE

叶子证书用于证明服务器身份,而不是签发下级证书。

三种证书对比

类型 签发者 主要用途 是否属于 CA
根证书 通常自签名 作为信任锚 是
中间证书 上级 CA 签发下级证书 是
叶子证书 中间 CA 网站身份认证 否

六、浏览器如何验证证书链?

假设网站证书链如下:

Root CA
   |
   | 使用 Root CA 私钥签名
   v
Intermediate CA
   |
   | 使用 Intermediate CA 私钥签名
   v
example.com

浏览器访问:

https://example.com

服务器向浏览器发送:

example.com 叶子证书
Intermediate CA 中间证书

根证书通常不需要由服务器发送。

浏览器验证流程:

第一步:验证域名

检查证书 SAN 是否包含:

DNS:example.com

如果不匹配,则证书不适用于当前访问的域名。

第二步:验证有效期

检查:

Not Before
Not After

证书必须在允许的有效期内。

第三步:验证叶子证书签名

浏览器获取中间 CA 的公钥。

使用该公钥验证网站证书上的 CA 数字签名。

第四步:验证中间 CA 证书

浏览器使用上级 CA 的公钥验证中间证书签名。

第五步:寻找可信根证书

浏览器尝试将证书链连接到本地可信根证书。

第六步:检查其他约束

还需要检查:

  • Basic Constraints
  • Key Usage
  • Extended Key Usage
  • 证书路径约束
  • 算法安全性
  • 适用的吊销状态要求
  • 浏览器证书透明度等策略

只有相关检查全部通过,浏览器才会接受服务器证书。


七、Let's Encrypt 是什么?

Let's Encrypt 是一个公开的、提供免费自动化 TLS 证书的 CA。

它使用 ACME 协议实现证书的自动申请和管理。

需要区分:

Let's Encrypt
    |
    +-- CA:负责验证和签发证书

ACME
    |
    +-- 自动化证书管理协议

acme.sh
    |
    +-- ACME 客户端软件

acme.sh 本身不是 CA。

它负责与 CA 通信,完成申请、验证、下载和续期等操作。


八、Let's Encrypt 申请证书的完整流程

假设需要申请:

example.com
www.example.com

8.1 第一步:安装 acme.sh

curl https://get.acme.sh | sh -s email=admin@example.com

该命令会下载并执行安装脚本。生产环境中应确认来源并审查脚本。

检查版本:

acme.sh --version

指定 Let's Encrypt:

acme.sh --set-default-ca --server letsencrypt

8.2 第二步:注册 ACME 账户

acme.sh 首次使用 CA 时,会创建或注册 ACME 账户。

客户端会生成账户密钥。

例如:

ACME Account
     |
     +-- Account Private Key
     |
     +-- Account Public Key

账户密钥用于认证 ACME 管理请求。

注意:

ACME 账户私钥与网站 TLS 私钥通常不是同一把私钥。


8.3 第三步:生成网站密钥对

客户端为网站生成密钥对:

example.com
     |
     +-- Private Key
     |
     +-- Public Key

网站私钥保存在:

example.com.key

公钥会写入 CSR。

例如使用 OpenSSL 生成 RSA 私钥:

openssl genpkey \
  -algorithm RSA \
  -pkeyopt rsa_keygen_bits:2048 \
  -out example.com.key

或者生成椭圆曲线私钥:

openssl ecparam \
  -name prime256v1 \
  -genkey \
  -noout \
  -out example.com.key

正常使用 acme.sh 时,密钥生成通常由客户端自动完成。


8.4 第四步:生成 CSR

CSR 全称:

Certificate Signing Request

即证书签名请求。

CSR 包含:

  • 申请的域名。
  • 网站公钥。
  • 证书扩展请求。
  • 申请者使用网站私钥生成的签名。

示例:

openssl req \
  -new \
  -key example.com.key \
  -out example.com.csr \
  -subj "/CN=example.com" \
  -addext "subjectAltName=DNS:example.com"

CSR 可以证明申请者持有对应私钥。

但不能单独证明申请者拥有域名控制权。

因此 CA 还需要执行域名验证。


8.5 第五步:域名所有权或控制权验证

Let's Encrypt 主要通过 ACME Challenge 验证申请者对域名的控制权。

常见验证方式:

验证方式 原理 特点
HTTP-01 验证 HTTP 资源 通常需要 80 端口
DNS-01 验证 DNS TXT 记录 支持通配符证书
TLS-ALPN-01 通过 TLS ALPN 验证 使用 443 端口

方式一:HTTP-01

执行:

acme.sh --issue \
  --server letsencrypt \
  -d example.com \
  -w /var/www/html

流程如下。

步骤 1:acme.sh 向 CA 请求域名验证。

acme.sh --------------> Let's Encrypt

申请 example.com 的域名授权

步骤 2:Let's Encrypt 返回挑战 Token。

例如:

TOKEN = abc123...

步骤 3:acme.sh 创建验证文件。

/var/www/html/
└── .well-known/
    └── acme-challenge/
        └── abc123...

文件内容为 ACME 协议要求的 Key Authorization。

其组成与挑战 Token 和 ACME 账户公钥指纹有关。

步骤 4:Let's Encrypt 发起 HTTP 请求。

GET /.well-known/acme-challenge/abc123... HTTP/1.1
Host: example.com

CA 通过公网访问网站的 80 端口,检查响应内容。

步骤 5:验证成功。

CA 确认申请者能够控制对应域名的 HTTP 验证资源。

HTTP-01 不支持通配符证书。

方式二:DNS-01

DNS-01 通过 DNS TXT 记录验证。

例如:

域名:example.com

记录类型:TXT

记录名称:
_acme-challenge.example.com

记录内容:
由 ACME 挑战计算出的验证值

Let's Encrypt 查询对应 DNS TXT 记录。

验证成功后,确认申请者具备相应的 DNS 控制能力。

DNS-01 支持:

*.example.com

通配符证书。

例如使用 Cloudflare DNS API:

acme.sh --issue \
  --server letsencrypt \
  --dns dns_cf \
  -d example.com \
  -d '*.example.com'

使用前需要配置对应 DNS API 凭据。


8.6 第六步:CA 签发证书

域名验证成功后,acme.sh 完成 ACME 订单流程并提交 CSR。

Let's Encrypt 会检查:

  1. 域名授权是否有效。
  2. CSR 是否符合要求。
  3. CSR 签名是否有效。
  4. 证书请求是否符合签发策略。

随后,CA 使用签发证书的私钥生成数字签名。

最终得到:

example.com.cer

该证书包含网站公钥及 CA 数字签名。

Let's Encrypt 不需要获得网站私钥。


8.7 第七步:客户端下载证书

acme.sh 下载网站证书及相关 CA 证书链。

典型文件如下:

example.com/
│
├── example.com.cer
├── example.com.conf
├── example.com.csr
├── example.com.csr.conf
├── example.com.key
├── ca.cer
└── fullchain.cer

至此证书申请完成。

但还需要把证书部署到 Nginx。


九、七个证书文件分别是什么?

9.1 文件总览

文件 内容 作用
example.com.cer 网站叶子证书 证明网站身份
example.com.conf acme.sh 配置 证书申请、续期和部署管理
example.com.csr CSR 请求 向 CA 请求签发证书
example.com.csr.conf CSR 配置 生成 CSR 的参数
example.com.key 网站私钥 TLS 身份认证
ca.cer CA 中间证书链 建立证书信任链
fullchain.cer 网站证书 + 中间证书链 Nginx 部署 HTTPS

9.2 example.com.cer

这是 CA 签发给网站的叶子证书。

文件通常采用 PEM 编码:

-----BEGIN CERTIFICATE-----
MIIF......
......
-----END CERTIFICATE-----

其中 Base64 内容编码的是 DER 格式的 X.509 证书。

它通常包含:

Subject:
    example.com

Issuer:
    Let's Encrypt 的签发 CA

Public Key:
    网站公钥

Validity:
    证书有效期

Signature:
    CA 数字签名

查看:

openssl x509 \
  -in example.com.cer \
  -text \
  -noout

查看证书域名:

openssl x509 \
  -in example.com.cer \
  -noout \
  -ext subjectAltName

查看有效期:

openssl x509 \
  -in example.com.cer \
  -noout \
  -dates

9.3 example.com.conf

这是 acme.sh 的证书管理配置文件。

它不是数字证书。

可能包含:

Le_Domain='example.com'
Le_Alt='www.example.com'
Le_Webroot='/var/www/html'
Le_Keylength='ec-256'
Le_API='https://acme-v02.api.letsencrypt.org/directory'

实际字段因 acme.sh 版本、CA 和验证方式而不同。

主要作用:

  • 保存申请域名。
  • 保存验证方式。
  • 保存 CA 接口。
  • 保存续期配置。
  • 保存证书部署配置。
  • 保存续期后执行的命令。

配置文件可能含有敏感配置,不应随意公开。

Nginx 不需要直接读取它。


9.4 example.com.csr

CSR 是证书签名请求文件。

格式通常为:

-----BEGIN CERTIFICATE REQUEST-----
MIIC......
......
-----END CERTIFICATE REQUEST-----

它包含:

  • 网站公钥。
  • 申请域名。
  • 申请的证书扩展。
  • 申请者的数字签名。

查看:

openssl req \
  -in example.com.csr \
  -text \
  -noout

CSR 与正式证书的区别:

CSR 正式证书
申请者生成 CA 签发
用申请者私钥签名 用 CA 私钥签名
表示证书申请 表示签发结果
不证明域名已通过 CA 验证 可用于受信任的域名身份认证

9.5 example.com.csr.conf

这是生成 CSR 时使用的 OpenSSL 配置文件。

示例:

[req]
distinguished_name = req_dn
req_extensions = v3_req
prompt = no

[req_dn]
CN = example.com

[v3_req]
subjectAltName = @alt_names

[alt_names]
DNS.1 = example.com
DNS.2 = www.example.com

主要用于指定:

  • 证书主体。
  • 域名。
  • SAN 扩展。
  • CSR 生成参数。

它不属于正式签发的数字证书。


9.6 example.com.key

这是网站证书对应的私钥。

可能使用 RSA、ECDSA 等算法。

常见格式:

-----BEGIN PRIVATE KEY-----
MIIE......
......
-----END PRIVATE KEY-----

也可能使用其他 PEM 私钥格式。

私钥的作用:

在 TLS 握手中证明服务器持有证书对应的私钥。

例如 TLS 1.3 中,服务器通过 CertificateVerify 消息完成签名证明。

私钥必须严格保护。

建议:

chown root:root /etc/nginx/ssl/example.com.key

chmod 600 /etc/nginx/ssl/example.com.key

不要将私钥提交到 GitHub 或公开仓库。

如果私钥泄露,应重新生成密钥并申请新证书,必要时吊销旧证书。


9.7 ca.cer

这是 CA 中间证书链文件。

例如:

Intermediate CA Certificate

它可能包含一张或多张中间证书。

作用是帮助客户端验证网站证书的签发路径。

注意:

ca.cer 不一定包含根证书。

查看证书数量:

grep -c 'BEGIN CERTIFICATE' ca.cer

9.8 fullchain.cer

这是完整证书链文件。

通常包含:

网站叶子证书
+
中间 CA 证书链

例如:

-----BEGIN CERTIFICATE-----
example.com 网站证书
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
Intermediate CA 中间证书
-----END CERTIFICATE-----

它通常不包含根 CA 证书。

也不包含网站私钥。

Nginx 推荐使用:

ssl_certificate /etc/nginx/ssl/fullchain.cer;

十、fullchain.cer 为什么需要包含中间证书?

假设只向浏览器发送:

example.com.cer

浏览器知道该证书由某个中间 CA 签发。

但是,如果客户端没有对应的中间 CA 证书,就可能无法构建完整信任路径。

因此服务器通常需要发送:

example.com
    |
    v
Intermediate CA

浏览器再将这条路径连接到本地信任库中的根证书。

完整过程:

Nginx 发送:

example.com Certificate
          |
          v
Intermediate CA Certificate

浏览器本地:

Trusted Root CA Certificate

浏览器构建:

Trusted Root CA
       |
       v
Intermediate CA
       |
       v
example.com

10.1 为什么不需要发送根证书?

因为根证书的信任必须来自客户端自身的信任配置。

即使服务器发送一张根证书,也不能让客户端自动信任它。

服务器通常只需要提供叶子证书和必要的中间证书。

10.2 如何查看 fullchain 的全部证书?

openssl crl2pkcs7 \
  -nocrl \
  -certfile fullchain.cer |
openssl pkcs7 \
  -print_certs \
  -noout

查看证书数量:

grep -c 'BEGIN CERTIFICATE' fullchain.cer

10.3 fullchain.cer 和 example.com.cer 的区别

example.com.cer
       |
       +-- 网站叶子证书

ca.cer
       |
       +-- 中间 CA 证书链

fullchain.cer
       |
       +-- 网站叶子证书
       |
       +-- 中间 CA 证书链

在典型 acme.sh 输出中,可以将其理解为:

cat example.com.cer ca.cer > fullchain.cer

正常情况下,acme.sh 已经生成该文件,无需手动拼接。


十一、浏览器访问 HTTPS 网站时,数据如何加密?

这是理解 HTTPS 最重要的部分。

首先需要纠正一个常见误解。

11.1 错误理解

很多人认为:

浏览器获取网站证书
        |
        v
提取网站公钥
        |
        v
使用网站公钥加密 HTTP 请求
        |
        v
Nginx 使用网站私钥解密请求

这个流程不是现代 TLS 1.3 的工作方式。

TLS 1.3 中:

  • 证书用于身份认证。
  • 证书私钥用于握手签名。
  • ECDHE 用于协商共享秘密。
  • HKDF 用于派生流量密钥。
  • 对称认证加密算法用于保护 HTTP 数据。

下面详细说明。


十二、TLS 1.3 握手流程

假设浏览器访问:

https://example.com/login

12.1 第一步:DNS 解析

浏览器解析:

example.com

得到 IP:

203.0.113.10

这里的 IP 仅为文档示例。

浏览器准备连接服务器。


12.2 第二步:建立 TCP 连接

传统 HTTPS 通常使用 TCP 443 端口。

Browser                 Nginx
   |                       |
   |------ TCP SYN ------->|
   |<--- TCP SYN/ACK ------|
   |------ TCP ACK ------->|
   |                       |
   |   TCP 连接建立完成     |

HTTP/3 使用 QUIC,不采用这里介绍的 TCP 连接方式。

以下讨论的是 TCP 上的 TLS 1.3。


12.3 第三步:ClientHello

浏览器发送 ClientHello。

其中包括:

  • 支持的 TLS 版本。
  • 支持的加密套件。
  • 支持的密钥交换组。
  • 客户端临时 ECDHE 公钥。
  • SNI 域名。
  • ALPN 协议列表。

例如:

ClientHello

TLS Version:
    TLS 1.3

SNI:
    example.com

Cipher Suites:
    TLS_AES_128_GCM_SHA256
    TLS_AES_256_GCM_SHA384
    TLS_CHACHA20_POLY1305_SHA256

Key Share:
    Client ECDHE Public Key

此时普通 HTTP 请求还没有发送。


12.4 第四步:ServerHello

Nginx 收到 ClientHello 后,选择双方支持的 TLS 参数。

例如:

ServerHello

TLS Version:
    TLS 1.3

Cipher Suite:
    TLS_AES_128_GCM_SHA256

Key Share:
    Server ECDHE Public Key

浏览器与服务器交换了各自的临时 ECDHE 公钥。

双方保留自己的临时私钥。


12.5 第五步:ECDHE 协商共享秘密

ECDHE 全称:

Elliptic Curve Diffie-Hellman Ephemeral

即椭圆曲线临时 Diffie-Hellman 密钥交换。

假设:

客户端生成:

Client Private Key = a

Client Public Key = aG

服务器生成:

Server Private Key = b

Server Public Key = bG

其中 G 是选定椭圆曲线的基点。

客户端计算:

Shared Secret = a(bG)

服务器计算:

Shared Secret = b(aG)

根据椭圆曲线运算性质:

a(bG) = b(aG)

因此双方得到相同的共享秘密:

Shared Secret = abG

网络监听者即使获得双方的临时公钥,通常也无法计算出该共享秘密。

注意:这是简化的数学模型。实际 TLS 还涉及具体曲线、编码和密钥交换规则。


12.6 第六步:通过 HKDF 派生密钥

ECDHE 产生的共享秘密并不是直接用作全部 HTTP 数据的加密密钥。

TLS 1.3 使用 HKDF 密钥派生机制。

简化结构:

ECDHE Shared Secret
         |
         v
   TLS 1.3 Key Schedule
         |
         +-- Client Handshake Traffic Secret
         |
         +-- Server Handshake Traffic Secret
         |
         +-- Client Application Traffic Secret
         |
         +-- Server Application Traffic Secret

不同通信方向使用不同的流量密钥材料。

这意味着:

浏览器发送方向
    使用客户端发送流量密钥

服务器发送方向
    使用服务器发送流量密钥

双方分别派生出用于发送和接收的匹配密钥。


12.7 第七步:Nginx 发送证书链

TLS 1.3 中,ServerHello 之后的主要握手消息受到握手密钥保护。

服务器发送 Certificate 消息。

该消息包含:

example.com 叶子证书

Intermediate CA 中间证书

这些证书来自 Nginx 配置:

ssl_certificate /etc/nginx/ssl/fullchain.cer;

浏览器接收证书后,执行证书验证。


12.8 第八步:浏览器验证服务器证书

浏览器检查:

1. 域名是否匹配?

2. 证书是否过期?

3. CA 签名是否有效?

4. 证书链是否完整且有效?

5. 根 CA 是否可信?

6. 证书用途是否正确?

7. 是否满足浏览器安全策略?

如果验证失败,浏览器可能提示:

Your connection is not private

如果验证成功,则继续验证服务器握手身份。


12.9 第九步:服务器证明自己持有私钥

这是证书私钥发挥关键作用的地方。

Nginx 使用:

example.com.key

对应的私钥,对 TLS 1.3 规定的握手上下文进行数字签名。

然后发送:

CertificateVerify

浏览器使用网站证书中的公钥验证签名。

示意:

Nginx
  |
  | 使用网站私钥
  v
对握手上下文签名
  |
  v
CertificateVerify
  |
  v
Browser
  |
  | 使用网站证书公钥
  v
验证签名

这样浏览器不仅验证了证书链,还确认当前服务器持有对应的私钥。

在 TLS 1.3 中,网站私钥主要用于服务器身份认证签名,而不是解密所有 HTTP 数据。


12.10 第十步:Finished 消息

服务器和客户端通过 Finished 消息验证握手完整性。

其作用包括:

  • 验证双方具有一致的握手密钥材料。
  • 验证握手消息未被未检测到的方式篡改。
  • 将身份认证和密钥交换绑定到当前连接。

握手成功后,双方开始使用应用数据流量密钥。


十三、浏览器如何加密 HTTP 请求?

假设浏览器准备发送:

POST /login HTTP/1.1
Host: example.com
Content-Type: application/json

{
    "username": "admin",
    "password": "123456"
}

在 TLS 1.3 中,HTTP 请求会作为应用数据交给 TLS 记录层。

TLS 记录层使用协商好的对称认证加密算法。

常见算法包括:

AES-128-GCM

AES-256-GCM

ChaCha20-Poly1305

这些算法属于 AEAD:

Authenticated Encryption with Associated Data

即带关联数据的认证加密。

它们同时提供:

  1. 数据机密性。
  2. 数据完整性认证。

加密流程:

浏览器生成 HTTP 请求
          |
          v
      HTTP 数据
          |
          v
    TLS Record Layer
          |
          v
  客户端应用流量密钥
          |
          v
  AES-GCM / ChaCha20-Poly1305
          |
          v
     加密 TLS 记录
          |
          v
       TCP 发送
          |
          v
        Nginx

网络中的攻击者通常只能观察到加密后的 TLS 记录及部分网络元数据。

无法直接读取 HTTP 请求正文。


十四、Nginx 如何解密 HTTPS 请求?

Nginx 收到加密的 TLS 记录后,并不是简单地使用:

example.com.key

去解密整个 HTTP 请求。

实际使用的是 TLS 握手派生的客户端发送方向流量密钥。

解密流程:

Nginx 接收 TCP 数据
          |
          v
      TLS 加密记录
          |
          v
    TLS 库进行认证解密
          |
          | 使用当前连接的流量密钥
          v
       HTTP 明文
          |
          v
    Nginx HTTP 模块
          |
          v
      请求处理
          |
     +----+----+
     |         |
     v         v
 静态文件    反向代理
               |
               v
           后端服务

Nginx 通常通过 OpenSSL 等 TLS 库处理握手和 TLS 记录。

如果 TLS 记录认证失败,就不能将其当作有效 HTTP 数据继续处理。

需要特别注意反向代理

如果配置:

location / {
    proxy_pass http://127.0.0.1:8080;
}

那么:

浏览器
   |
   | HTTPS 加密
   v
Nginx
   |
   | HTTP 明文
   v
后端服务

Nginx 与后端之间的 HTTP 流量没有 TLS 加密。

如果需要加密反向代理到后端的通信,可以根据后端支持情况使用 HTTPS:

location / {
    proxy_pass https://backend.example.internal;
    proxy_ssl_server_name on;
    proxy_ssl_verify on;
    proxy_ssl_trusted_certificate /etc/nginx/ssl/backend-ca.pem;
}

这里还需要正确配置后端证书名称和信任链,不能只把 http:// 改成 https:// 就认为后端身份已经得到验证。


十五、Nginx 如何加密 HTTP 响应?

假设 Nginx 返回:

HTTP/1.1 200 OK
Content-Type: text/html

<html>
    <body>Hello HTTPS</body>
</html>

TLS 层使用服务器发送方向的应用流量密钥对响应进行认证加密。

Nginx HTTP 响应
       |
       v
    TLS 记录层
       |
       v
服务器应用流量密钥
       |
       v
AES-GCM / ChaCha20-Poly1305
       |
       v
加密 TLS 记录
       |
       v
    发送给浏览器
       |
       v
浏览器使用匹配的接收密钥解密

因此 HTTPS 双向通信是:

                  HTTPS

Browser                          Nginx
   |                                |
   |--- 加密 HTTP Request --------->|
   |                                |
   |<-- 加密 HTTP Response ---------|
   |                                |

两种方向使用不同的流量密钥材料。


十六、TLS 1.3 完整握手流程图

Browser                                Nginx
   |                                      |
   |----------- ClientHello ------------>|
   |             key_share                |
   |                                      |
   |<---------- ServerHello --------------|
   |             key_share                |
   |                                      |
   |       双方派生握手阶段密钥            |
   |                                      |
   |<--------- EncryptedExtensions -------|
   |<--------- Certificate ---------------|
   |<--------- CertificateVerify ---------|
   |<--------- Finished ------------------|
   |                                      |
   |       浏览器验证证书和签名            |
   |                                      |
   |----------- Finished ---------------->|
   |                                      |
   |       双方使用应用数据流量密钥        |
   |                                      |
   |========== HTTP Request =============>|
   |            TLS 加密                   |
   |                                      |
   |<========= HTTP Response =============|
   |            TLS 加密                   |
   |                                      |

这是典型 TLS 1.3 完整握手的简化流程。

不包括:

  • 客户端证书认证。
  • 会话恢复。
  • PSK。
  • 0-RTT Early Data。
  • TLS KeyUpdate。

十七、为什么 HTTPS 不直接用 RSA 加密所有 HTTP 数据?

主要有三个原因。

17.1 非对称密码运算成本更高

非对称密码算法通常不适合直接处理大量 HTTP 数据。

对称加密算法更适合高吞吐量的数据加密。

17.2 需要前向保密

现代 TLS 使用临时密钥交换。

这样即使网站长期证书私钥未来泄露,攻击者通常也不能仅凭该私钥解密过去记录的安全 TLS 会话。

这称为:

Forward Secrecy

前向保密。

17.3 需要认证加密

现代 TLS 使用 AEAD 算法同时提供机密性和完整性。

因此 TLS 1.3 采用:

证书与数字签名
       |
       v
服务器身份认证

ECDHE
       |
       v
共享秘密

HKDF
       |
       v
流量密钥

AES-GCM / ChaCha20-Poly1305
       |
       v
HTTP 数据加密与完整性认证

十八、Nginx 配置 Let's Encrypt 证书

假设证书保存在:

/etc/nginx/ssl/

目录结构:

/etc/nginx/ssl/
├── fullchain.cer
└── example.com.key

Nginx 配置:

server {
    listen 80;
    server_name example.com;

    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /etc/nginx/ssl/fullchain.cer;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;

    ssl_protocols TLSv1.2 TLSv1.3;

    root /var/www/html;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

其中:

ssl_certificate /etc/nginx/ssl/fullchain.cer;

用于加载网站证书和中间 CA 证书链。

ssl_certificate_key /etc/nginx/ssl/example.com.key;

用于加载网站私钥。

为什么推荐 fullchain.cer?

因为它包含服务器需要发送给客户端的证书链。

如果只配置:

ssl_certificate /etc/nginx/ssl/example.com.cer;

某些客户端可能因为缺少中间证书而无法完成证书验证。

因此推荐:

ssl_certificate /etc/nginx/ssl/fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/example.com.key;

十九、使用 acme.sh 部署证书

推荐使用 acme.sh 的部署命令,而不是直接让 Nginx 引用 acme.sh 的内部工作目录。

mkdir -p /etc/nginx/ssl

部署:

acme.sh --install-cert -d example.com \
  --key-file /etc/nginx/ssl/example.com.key \
  --fullchain-file /etc/nginx/ssl/fullchain.cer \
  --reloadcmd "systemctl reload nginx"

如果使用 ECC 证书,可能需要加上:

--ecc

acme.sh 可以在续期后更新部署文件,并执行配置的重载命令。

检查 Nginx:

nginx -t

重新加载:

systemctl reload nginx

二十、OpenSSL 常用证书检查命令

20.1 查看证书详细信息

openssl x509 -in example.com.cer -text -noout

20.2 查看证书有效期

openssl x509 -in example.com.cer -noout -dates

20.3 查看证书签发者

openssl x509 -in example.com.cer -noout -issuer

20.4 查看证书域名

openssl x509 \
  -in example.com.cer \
  -noout \
  -ext subjectAltName

20.5 查看 CSR

openssl req -in example.com.csr -text -noout

20.6 检查私钥

openssl pkey \
  -in example.com.key \
  -check \
  -noout

20.7 检查证书与私钥是否匹配

提取证书公钥并计算摘要:

openssl x509 -in example.com.cer -pubkey -noout |
openssl pkey -pubin -outform DER |
openssl dgst -sha256

提取私钥对应的公钥并计算摘要:

openssl pkey -in example.com.key -pubout -outform DER |
openssl dgst -sha256

两次摘要相同,说明证书公钥与私钥对应。

20.8 查看 fullchain 包含几张证书

grep -c 'BEGIN CERTIFICATE' fullchain.cer

20.9 查看 fullchain 中的证书信息

openssl crl2pkcs7 \
  -nocrl \
  -certfile fullchain.cer |
openssl pkcs7 \
  -print_certs \
  -noout

20.10 查看服务器实际发送的证书链

openssl s_client \
  -connect example.com:443 \
  -servername example.com \
  -showcerts

如果验证成功,可能显示:

Verify return code: 0 (ok)

这取决于本地信任库及相关验证条件。

20.11 验证本地证书链

openssl verify \
  -purpose sslserver \
  -verify_hostname example.com \
  -untrusted ca.cer \
  example.com.cer

需要确保 OpenSSL 能够访问适当的根 CA 信任库。


二十一、常见问题

21.1 证书就是公钥吗?

不是。

数字证书包含公钥、身份信息、有效期、签发者和数字签名等内容。

公钥只是证书的一部分。

21.2 证书中包含私钥吗?

普通 X.509 公钥证书不包含私钥。

但是 .p12、.pfx 等 PKCS#12 容器可能同时保存证书和私钥。

21.3 fullchain.cer 包含私钥吗?

不包含。

它通常只包含网站证书与中间 CA 证书链。

21.4 Let's Encrypt 是否知道网站私钥?

正常 ACME 申请流程中,网站私钥由客户端保管,不会提交给 Let's Encrypt。

21.5 根证书为什么不需要服务器发送?

因为客户端需要预先信任根证书。

服务器发送一个不受信任的根证书,不会让客户端自动信任它。

21.6 Nginx 的私钥是不是用来解密所有 HTTPS 请求?

对于 TLS 1.3,不是。

网站私钥主要用于握手中的身份认证签名。

HTTP 数据由 TLS 连接派生的对称流量密钥进行加密和解密。

21.7 如果网站私钥泄露会怎样?

攻击者可能利用泄露的私钥冒充网站身份,前提是还能够实施相应的连接攻击。

应立即更换密钥并重新签发证书,必要时吊销旧证书。

由于 TLS 1.3 使用临时密钥交换,攻击者通常不能仅凭泄露的长期证书私钥解密过去记录的安全会话。

21.8 HTTPS 是否能隐藏全部网络信息?

不能。

HTTPS 保护 HTTP 应用数据,但不保证隐藏:

  • 服务器 IP 地址。
  • 通信时间。
  • 数据包大小。
  • 流量模式。
  • 某些握手元数据。
  • 未启用 ECH 时可能暴露的 SNI。
  • 未加密的 DNS 查询。

二十二、DV、OV、EV 证书的区别

22.1 DV:域名验证型证书

DV(Domain Validation)只需要证明申请者拥有或控制对应域名。

例如申请:

www.example.com

CA 机构会要求申请者通过指定方式证明对该域名的控制权。

常见验证方式:

  • DNS TXT 记录验证。
  • DNS CNAME 记录验证。
  • HTTP 文件验证。
  • ACME DNS-01 / HTTP-01 自动验证。

验证流程:

申请 DV 证书
      |
      v
提交域名及 CSR
      |
      v
CA 要求验证域名控制权
      |
      v
添加 DNS 记录或 HTTP 验证文件
      |
      v
CA 验证成功
      |
      v
签发 DV 证书

特点:

  • 只验证域名控制权。
  • 不验证企业营业执照。
  • 不验证企业真实经营身份。
  • 可以高度自动化。
  • 签发速度通常最快。
  • 价格通常最低,也有免费产品。

适用场景:

  • 个人网站。
  • 博客。
  • 普通 HTTPS 网站。
  • API 服务。
  • 开发测试环境。
  • 不需要展示企业认证身份的业务系统。

22.2 OV:组织验证型证书

OV(Organization Validation)除了验证域名控制权,还需要验证申请企业或组织的合法身份。

CA 机构通常会核实:

  1. 企业或组织的法定名称。
  2. 企业注册信息。
  3. 企业是否真实、合法存在。
  4. 企业注册地址等组织信息。
  5. 申请者是否有权代表组织申请证书。

审核过程中可能需要企业提供相关证明材料,或通过可信的官方、第三方信息源完成核验。

验证流程:

申请 OV 证书
      |
      v
验证域名控制权
      |
      v
提交企业信息
      |
      v
CA 核验企业合法身份
      |
      v
核实相关组织信息和申请权限
      |
      v
审核通过
      |
      v
签发 OV 证书

特点:

  • 验证域名控制权。
  • 验证企业或组织真实身份。
  • 证书中包含经过验证的组织身份信息。
  • 审核流程比 DV 复杂。
  • 价格通常高于 DV。
  • 更适合需要企业身份认证的场景。

适用场景:

  • 企业官方网站。
  • 企业管理系统。
  • 商业服务平台。
  • SaaS 平台。
  • B2B 业务系统。
  • 需要提供组织身份信息的业务。

22.3 EV:扩展验证型证书

EV(Extended Validation)采用更严格的企业或组织身份审核标准。

除了 DV 和 OV 所要求的验证,EV 还会进一步核实企业的法律主体信息及申请授权。

审核内容通常包括:

  1. 域名控制权。
  2. 企业法定名称。
  3. 企业注册编号。
  4. 企业注册司法管辖区。
  5. 企业合法存在状态。
  6. 企业实际运营情况。
  7. 企业地址和联系方式。
  8. 申请人的身份与申请权限。
  9. 由经过验证的企业代表确认申请。

验证流程:

申请 EV 证书
      |
      v
验证域名控制权
      |
      v
验证企业合法身份
      |
      v
核实企业注册和运营信息
      |
      v
验证企业申请代表
      |
      v
完成扩展审核
      |
      v
签发 EV 证书

特点:

  • 身份审核要求最严格。
  • 能提供更高程度的企业身份保证。
  • 申请流程通常更复杂。
  • 签发时间可能更长。
  • 价格通常最高。
  • 适合对法律主体身份验证有较高要求的业务。

适用场景:

  • 银行和金融机构。
  • 大型企业。
  • 保险平台。
  • 重要商业交易平台。
  • 受监管行业。
  • 对组织身份审核有明确要求的业务。

注意:现代 Chrome、Firefox、Edge 等主流浏览器通常不会因为网站使用 EV 证书,就在地址栏显示绿色企业名称。

EV 的价值主要体现在更严格的身份验证,而不是浏览器地址栏的特殊显示效果。

三、DV、OV、EV 核心区别对比

对比项目 DV OV EV
中文名称 域名验证型 组织验证型 扩展验证型
域名控制权验证 支持 支持 支持
企业身份验证 不需要 需要 需要
企业合法性审核 不需要 需要 更严格
企业运营信息审核 不需要 视要求而定 更严格
企业代表授权验证 不需要组织身份审核 需要符合相应审核要求 更严格
证书包含企业身份 否 是 是
HTTPS 加密能力 相同条件下相同 相同条件下相同 相同条件下相同
签发速度 通常最快 较慢 通常最慢
申请复杂度 低 中 高
相对价格 低 中 高
个人申请 通常可以 需符合组织审核要求 需符合 EV 主体资格要求
企业官网 适用 适用 适用
身份验证保证级别 基础 较高 最高

说明:价格和签发时间不是 CA/B Forum 规定的固定数值,不同 CA、代理商和产品套餐可能存在明显差异。

二十三、最终总结

23.1 证书申请流程

网站管理员
    |
    v
安装 acme.sh
    |
    v
注册 ACME 账户
    |
    v
生成网站公钥和私钥
    |
    v
生成 CSR
    |
    v
向 Let's Encrypt 申请证书
    |
    v
HTTP-01 / DNS-01 域名验证
    |
    v
CA 验证通过
    |
    v
CA 签发网站证书
    |
    v
acme.sh 下载证书和中间证书链
    |
    v
部署 fullchain.cer 和 example.com.key
    |
    v
Nginx 提供 HTTPS 服务

23.2 证书文件关系

example.com.key
       |
       | 对应公钥写入 CSR
       v
example.com.csr
       |
       | 提交证书签名请求
       v
Let's Encrypt
       |
       | 验证并签发
       v
example.com.cer
       |
       | 加上中间 CA 证书链
       v
fullchain.cer
       |
       | 与网站私钥一起部署
       v
Nginx HTTPS

另外:

example.com.csr.conf
    |
    +-- 生成 CSR 使用的配置

example.com.conf
    |
    +-- acme.sh 证书申请、续期及部署配置

23.3 HTTPS 加密流程

Browser                         Nginx
   |                               |
   |-------- ClientHello --------->|
   |                               |
   |<------- ServerHello ----------|
   |                               |
   |     ECDHE 建立共享秘密         |
   |                               |
   |       HKDF 派生密钥            |
   |                               |
   |<------- Certificate ----------|
   |<------- CertificateVerify ----|
   |                               |
   |      浏览器验证服务器身份       |
   |                               |
   |------ Finished -------------->|
   |                               |
   |==== 加密 HTTP Request =======>|
   |                               |
   |<=== 加密 HTTP Response ========|
   |                               |

23.4 最重要的知识点

  1. CA:负责验证并签发数字证书。
  2. 根证书:作为客户端信任体系的信任锚。
  3. 中间证书:由上级 CA 签发,用于签发下级证书。
  4. 叶子证书:用于网站服务器身份认证。
  5. CSR:证书签名请求。
  6. 私钥:必须保密,用于证明服务器身份。
  7. fullchain.cer:通常包含网站证书和中间 CA 证书链。
  8. ECDHE:用于建立共享秘密。
  9. HKDF:用于派生 TLS 流量密钥。
  10. AES-GCM / ChaCha20-Poly1305:用于 HTTP 数据的认证加密。
  11. Nginx:通过 TLS 库处理握手、加密和解密。
  12. TLS 1.3:证书私钥主要用于服务器身份认证,而不是直接解密全部 HTTP 数据。

最终 Nginx 配置

ssl_certificate     /etc/nginx/ssl/fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/example.com.key;

一句话总结:

CA 通过数字签名建立域名与公钥之间的可信绑定;浏览器通过证书链和 TLS 握手验证服务器身份;浏览器与服务器通过 ECDHE 和密钥派生建立会话密钥,最后使用对称认证加密算法保护 HTTP 数据。


参考资料

  1. Let's Encrypt 官方网站
    https://letsencrypt.org/

  2. Let's Encrypt 工作原理
    https://letsencrypt.org/how-it-works/

  3. Let's Encrypt 域名验证方式
    https://letsencrypt.org/docs/challenge-types/

  4. acme.sh 官方项目
    https://github.com/acmesh-official/acme.sh

  5. Nginx HTTPS 官方文档
    https://nginx.org/en/docs/http/configuring_https_servers.html

  6. RFC 8446 — TLS 1.3
    https://www.rfc-editor.org/rfc/rfc8446

  7. RFC 8555 — ACME
    https://www.rfc-editor.org/rfc/rfc8555

  8. RFC 5280 — X.509 公钥基础设施
    https://www.rfc-editor.org/rfc/rfc5280

posted on 2026-10-08 19:22  心宇16969  阅读(14)  评论(0)    收藏  举报