项目

配置 SSL 证书(HTTPS)

网站需要 SSL 证书来保护用户数据安全、验证所有权、防止攻击者伪造网站版本,并赢得用户的信任。

本文档介绍如何为你的应用程序获取和使用 SSL 证书(HTTPS)。

从证书颁发机构获取 SSL 证书

你可以从证书颁发机构(CA)获取 SSL 证书,例如 Let's EncryptCloudflare 等。

获得证书后,你需要配置 Web 服务器以使用它。以下参考资料展示了如何配置 Web 服务器以使用证书:

如何从 Let's Encrypt 获取免费 SSL 证书?

Let's Encrypt 是一个免费、自动化且开放的证书颁发机构(CA)。它提供数字证书,使网站能够启用 HTTPS(SSL/TLS)。为获取免费的 SSL 证书,我们将使用 acme.sh 和 Cloudflare DNS API 从 Let's Encrypt 获取免费 SSL 证书。

如果在执行以下步骤时遇到任何问题,可阅读 acme.sh 教程。

安装 acme.sh

确保你的终端中已安装 curl 命令,然后在终端中运行以下命令:

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

Cloudflare DNS API 令牌

你需要创建一个 API 令牌,该令牌应具备以下权限之一:

(i) 仅能编辑单个特定的 DNS 区域;或
(ii) 能编辑多个 DNS 区域。

你可以通过 Cloudflare 个人资料页面中的 API 令牌部分创建此令牌。创建令牌时,在“权限”下选择“区域”>“DNS”>“编辑”,在“区域资源”下仅包含你需要执行 ACME DNS 质询的特定 DNS 区域。

API 令牌是一个 40 位字符串,可包含大小写字母、数字和下划线。必须通过将环境变量 CF_Token 设置为其值来提供给 acme.sh,例如运行 export CF_Token="Y_jpG9AnfQmuX5Ss9M_qaNab6SQwme3HWXNDzRWs"

(i) 单个 DNS 区域
必须向 acme.sh 提供需要编辑的 DNS 区域的区域 ID。这是一个 32 位十六进制字符串(例如 763eac4f1bcebd8b5c95e9fc50d010b4),不要与区域名称(例如 example.com)混淆。该区域 ID 可以在 Cloudflare 控制台中,于区域概览页面的右侧边栏找到。

通过将环境变量 CF_Zone_ID 设置为此区域 ID 来提供此信息,例如运行 export CF_Zone_ID="763eac4f1bcebd8b5c95e9fc50d010b4"

(ii) 多个 DNS 区域
必须向 acme.sh 提供相关 DNS 区域所属的 Cloudflare 账户的账户 ID。这是一个 32 位十六进制字符串,不要与其他账户标识符混淆,例如账户邮箱地址(例如 alice@example.com)或全局 API 密钥(也是一个 32 位十六进制字符串)。该账户 ID 可以在 Cloudflare 控制台中找到:登录后位于 URL 的末尾,或在你任意区域的概览页面的右侧边栏中,位于区域 ID 下方。

通过将环境变量 CF_Account_ID 设置为此账户 ID 来提供此信息,例如运行 export CF_Account_ID="763eac4f1bcebd8b5c95e9fc50d010b4"

签发证书

> export CF_Token='your_token'
> export CF_Account_ID='your_account_id'
> export CF_Zone_ID='your_zone_id'
> acme.sh --issue --dns dns_cf -d getabp.net

[Info] 域名已更改。
[Info] 使用 CA:https://acme.zerossl.com/v2/DV90
[Info] 单域名='getabp.net'
[Info] 获取域名='getabp.net' 的 webroot
[Info] 为域名 _acme-challenge.getabp.net 添加 TXT 值:1uEeVFfmwXM7N21Wi9PitgEnhJbl4W4dHeRkapGkRSs
[Info] 添加记录
[Info] 已添加,成功
[Info] TXT 记录已成功添加。
[Info] 现在检查每个 DNS 记录。先等待 20 秒。
[Info] 你可以使用 '--dnssleep' 来禁用公共 DNS 检查。
[Info] 参见:https://github.com/acmesh-official/acme.sh/wiki/dnscheck
[Info] 检查 getabp.net 的 _acme-challenge.getabp.net
[Info] 域名 getabp.net 的 '_acme-challenge.getabp.net' 成功。
[Info] 所有检查成功
[Info] 验证:getabp.net
[Info] 处理中。CA 正在处理你的订单,请稍等。(1/30)
[Info] 成功
[Info] 移除 DNS 记录。
[Info] 移除域名的 TXT 记录:1uEeVFfmwXM7N21Wi9PitgEnhJbl4W4dHeRkapGkRSs,对应域名:_acme-challenge.getabp.net
[Info] 已成功移除
[Info] 验证完成,开始签名。
[Info] 让我们完成订单。
[Info] Le_OrderFinalize='https://acme.zerossl.com/v2/DV90/order/1AP31vqE7rzxCmvpDsDgvA/finalize'
[Info] 订单状态为 'processing',让我们稍等再重试。
[Info] 等待 15 秒后重试
[Info] 轮询订单状态:https://acme.zerossl.com/v2/DV90/order/1AP31vqE7rzxCmvpDsDgvA
[Info] 下载证书。
[Info] Le_LinkCert='https://acme.zerossl.com/v2/DV90/cert/o1jBkRs8LVVBiEZShd4Yow'
[Info] 证书成功。
-----BEGIN CERTIFICATE-----
MIID9jCCA3ygAwIBAgIQbJr7iNOSnkMXJjkwngvQRzAKBggqhkjOPQQDAzBLMQsw
CQYDVQQGEwJBVDEQMA4GA1UEChMHWmVyb1NTTDEqMCgGA1UEAxMhWmVyb1NTTCBF
Q0MgRG9tYWluIFNlY3VyZSBTaXRlIENBMB4XDTI0MDkyODAwMDAwMFoXDTI0MTIy
NzIzNTk1OVowFTETMBEGA1UEAxMKZ2V0YWJwLm5ldDBZMBMGByqGSM49AgEGCCqG
SM49AwEHA0IABJ.....io0Kq3W2o0eAgXDVXw2QJ6RlZKi0RGha/D92u/OAqvjX0I4
YEPRRgAm6l2oLg==
-----END CERTIFICATE-----
[Info] 你的证书位于:getabp.net.cer
[Info] 你的证书密钥位于:getabp.net.key
[Info] 中间 CA 证书位于:ca.cer
[Info] 完整链证书位于:fullchain.cer

将证书转换为 PFX 格式(IIS 格式)

openssl pkcs12 -export \
  -in getabp.net.cer \
  -inkey getabp.net.key \
  -out getabp.net.pfx \
  -passout pass:

如果你想为 PFX 文件设置密码,可以使用 -passout pass:your_password 来设置密码。

常见异常

如果你遇到以下异常,意味着你的证书未被客户端信任或证书无效。
当你尝试访问网站时,可能会在浏览器中看到以下 SSL 证书错误:

---> System.Net.Http.HttpRequestException: 无法建立 SSL 连接,请参阅内部异常。
---> System.Security.Authentication.AuthenticationException: 根据验证过程,远程证书无效:RemoteCertificateNameMismatch
---> System.Net.Http.HttpRequestException: 无法建立 SSL 连接,请参阅内部异常。
---> System.Security.Authentication.AuthenticationException: 由于证书链中的错误,远程证书无效:UntrustedRoot

参考资料

在本文档中