运维安全
Linux 环境下使用 OpenSSL 查看、导出与验证 TLS 证书
挖矿木马自助清理指南
本文档使用 MrDoc 发布
-
+
首页
Linux 环境下使用 OpenSSL 查看、导出与验证 TLS 证书
[标准领域知识] 将 PFX 文件转换为 PEM 文件,并不等于完成证书部署准备。完整的处理过程应包括证书信息检查、私钥导出、证书与私钥匹配、证书链组装、访问名称校验以及 Nginx 配置验证。 [标准领域知识] 证书文件名、文件扩展名及证书的 Common Name(CN)不能单独证明证书适用于某个域名或 IP 地址。访问名称应依据 Subject Alternative Name(SAN)扩展进行核对。 ## 一、证书文件与编码格式 [标准领域知识] 常见证书文件及其用途如下。 | 文件或格式 | 说明 | |---|---| | PFX / P12 | PKCS#12 容器,通常包含私钥、服务器证书以及 CA 证书,可通过密码保护 | | PEM | 使用 Base64 编码并带有起止标记的文本格式,可保存证书、私钥或多个证书 | | DER | 二进制编码格式,常用于保存单张证书 | | CRT / CER | 常见证书扩展名,实际内容可能采用 PEM 或 DER 编码 | | KEY | 常见私钥扩展名,实际编码格式及是否加密应以文件内容为准 | [标准领域知识] Nginx 的 `ssl_certificate` 用于指定 PEM 格式的证书文件,`ssl_certificate_key` 用于指定私钥文件。服务器证书与中间 CA 证书可以按顺序放在同一个 PEM 文件中。 ## 二、准备操作环境 [标准领域知识] 以下命令以 Linux、Bash 和 OpenSSL 3.x 为基准。首先检查 OpenSSL 版本: ```bash openssl version -a ``` [标准领域知识] 在独立目录中处理证书,并限制新建文件的访问权限: ```bash mkdir -p ~/certificate-work chmod 700 ~/certificate-work cd ~/certificate-work umask 077 set -euo pipefail ``` [标准领域知识] 设置待处理的 PFX 文件路径。路径包含空格或特殊字符时,应使用引号: ```bash PFX='/path/to/server.pfx' test -r "$PFX" ``` [标准领域知识] 下文通过交互提示输入 PFX 密码,不将密码写入命令参数。命令中的输入、输出文件应使用不同路径。 ## 三、查看 PFX 容器信息 [标准领域知识] 使用以下命令检查 PFX 容器结构及完整性校验信息: ```bash openssl pkcs12 \ -in "$PFX" \ -info \ -noout ``` [标准领域知识] 该命令主要用于查看容器使用的加密算法、MAC 信息及证书包、私钥包等结构,不替代服务器证书的详细检查。 [标准领域知识] OpenSSL 3.x 处理部分旧版 PFX 文件时,可能因旧加密算法未启用而出现 `unsupported` 错误。确认错误涉及旧算法后,可增加 `-legacy` 参数重新读取: ```bash openssl pkcs12 \ -legacy \ -in "$PFX" \ -info \ -noout ``` [标准领域知识] 如果必须使用 `-legacy` 才能读取该文件,后续读取同一 PFX 的导出命令也应增加该参数。 ## 四、导出全部证书与私钥 ### 4.1 导出全部证书 [标准领域知识] 先导出 PFX 中的全部证书,避免依赖容器中的排列顺序判断服务器证书: ```bash openssl pkcs12 \ -in "$PFX" \ -nokeys \ -out all-certificates.pem ``` [标准领域知识] `-clcerts` 和 `-cacerts` 可用于按容器属性筛选证书,但筛选结果仍需核对。服务器证书的最终选取应结合证书内容以及证书与私钥的匹配结果。 ### 4.2 导出未加密私钥 [标准领域知识] 在 OpenSSL 3.x 中,可使用 `-noenc` 导出未加密私钥: ```bash openssl pkcs12 \ -in "$PFX" \ -nocerts \ -noenc \ -out private-key-export.pem ``` [标准领域知识] 将导出结果规范化为独立的 PEM 私钥文件: ```bash openssl pkey \ -in private-key-export.pem \ -out server.key chmod 600 server.key ``` [标准领域知识] OpenSSL 1.1.1 使用 `-nodes` 实现对应的未加密私钥导出操作: ```bash openssl pkcs12 \ -in "$PFX" \ -nocerts \ -nodes \ -out private-key-export.pem ``` [标准领域知识] 上述两种导出方式按 OpenSSL 版本选择一种执行。未加密私钥无需在 Nginx 启动时输入私钥口令,其文件读取权限应限定给实际需要加载私钥的账户。 [标准领域知识] 如果 PFX 中包含多组私钥和证书,应分别处理各组对象,不能直接假定其只包含一套服务器身份材料。 ## 五、拆分并查看证书 ### 5.1 将证书拆分为独立文件 [标准领域知识] 以下命令从导出结果中提取每个证书块,并分别保存: ```bash mkdir certs awk ' /-----BEGIN CERTIFICATE-----/ { n++ file = sprintf("certs/cert-%02d.pem", n) } file != "" { print > file } /-----END CERTIFICATE-----/ { close(file) file = "" } ' all-certificates.pem ``` ### 5.2 查看证书主题、签发者和有效期 [标准领域知识] 逐一检查拆分后的证书: ```bash for cert in certs/cert-*.pem; do printf '\n文件:%s\n' "$cert" openssl x509 \ -in "$cert" \ -noout \ -subject \ -issuer \ -serial \ -dates done ``` [标准领域知识] 主要字段含义如下。 | 字段 | 含义 | |---|---| | `subject` | 证书主体 | | `issuer` | 证书签发者 | | `serial` | 签发机构分配的证书序列号 | | `notBefore` | 证书有效期起始时间 | | `notAfter` | 证书有效期终止时间 | [标准领域知识] `openssl x509 -dates` 的时间输出通常标注为 GMT,解释时应以输出中的时区标记为准。 ### 5.3 查看完整扩展信息 ```bash openssl x509 \ -in certs/cert-01.pem \ -noout \ -text ``` [标准领域知识] 重点检查以下扩展: | 扩展 | 检查内容 | |---|---| | Subject Alternative Name | 证书包含的 DNS 名称和 IP 地址 | | Basic Constraints | 是否为 CA 证书 | | Key Usage | 密钥允许的用途 | | Extended Key Usage | 是否存在用途限制,以及是否允许 TLS 服务器认证 | | Subject Key Identifier | 当前证书的公钥标识 | | Authority Key Identifier | 签发者密钥标识 | [标准领域知识] 主体名称与签发者名称相同,仅能说明证书属于自颁发形式;是否为有效的自签名证书,还需检查签名。 ## 六、验证证书与私钥是否匹配 [标准领域知识] 比较证书公钥与私钥所对应公钥的 DER 编码,可同时适用于 RSA、EC 等常见密钥类型,避免仅适用于 RSA 的模数比较方法。 ### 6.1 提取私钥对应的公钥 ```bash openssl pkey \ -in server.key \ -pubout \ -outform DER \ -out private-public.der ``` ### 6.2 查找匹配证书 [标准领域知识] 以下脚本逐一提取证书公钥并进行字节比较,要求恰好找到一张匹配证书: ```bash matched_count=0 matched_cert='' for cert in certs/cert-*.pem; do openssl x509 \ -in "$cert" \ -pubkey \ -noout \ -out certificate-public.pem openssl pkey \ -pubin \ -in certificate-public.pem \ -outform DER \ -out certificate-public.der if cmp -s private-public.der certificate-public.der; then printf '公钥匹配:%s\n' "$cert" matched_count=$((matched_count + 1)) matched_cert="$cert" fi done if [ "$matched_count" -ne 1 ]; then printf '匹配证书数量为 %s,需要进一步核对。\n' \ "$matched_count" >&2 exit 1 fi openssl x509 \ -in "$matched_cert" \ -outform PEM \ -out server.pem ``` [标准领域知识] 公钥匹配说明证书中的公钥与私钥相对应,不证明该证书已满足服务器用途、访问名称、有效期或信任链要求。选出证书后,仍需继续验证这些条件。 ### 6.3 检查私钥结构 ```bash openssl pkey \ -in server.key \ -check \ -noout ``` [标准领域知识] 应结合命令退出状态和检查输出判断私钥结构是否有效。 ## 七、查看绑定的域名和 IP 地址 [标准领域知识] 查看服务器证书中的 SAN 扩展: ```bash openssl x509 \ -in server.pem \ -noout \ -ext subjectAltName ``` [事实] 本次处理的证书包含以下 SAN 条目: ```text DNS:t1.cloud.com DNS:t2.cloud.cn IP Address:10.1.1.1 IP Address:10.1.2.1 ``` [事实] 该证书的 CN 为 `10.9.77.83`,SAN 中还列出了两个域名及其他四个 IP 地址,因此仅查看 CN 会遗漏访问名称信息。 [标准领域知识] 通过域名访问服务时,应校验对应的 DNS SAN;通过 IP 地址访问时,应校验对应的 IP Address SAN。Nginx 的 `server_name` 配置不会改变证书中的 SAN 内容。 ## 八、识别并组装证书链 [标准领域知识] 证书链通常由服务器证书、一个或多个中间 CA 证书以及根 CA 证书构成。Nginx 对外发送的证书文件应将服务器证书置于首位,随后按签发关系依次放置中间 CA 证书。 [标准领域知识] 可使用统一的名称输出格式辅助核对签发关系: ```bash for cert in certs/cert-*.pem; do printf '\n文件:%s\n' "$cert" openssl x509 \ -in "$cert" \ -noout \ -subject \ -issuer \ -nameopt RFC2253 \ -ext basicConstraints,subjectKeyIdentifier,authorityKeyIdentifier done ``` [标准领域知识] 识别上级证书时,应综合检查 `issuer` 与 `subject`、CA 属性及密钥标识。名称对应仅用于筛选候选证书,实际签发关系应通过签名和证书链验证确认。 [标准领域知识] 根据检查结果,将对应文件整理为以下名称: ```text server.pem 服务器证书 intermediate.pem 中间 CA 证书 root-ca.pem 根 CA 证书 ``` [标准领域知识] 对于只有一级中间 CA 的情况,组装 Nginx 使用的证书链: ```bash cat server.pem intermediate.pem > fullchain.pem ``` [标准领域知识] 对于存在多级中间 CA 的情况,应从直接签发服务器证书的中间 CA 开始,逐级向上排列: ```bash cat \ server.pem \ intermediate-issuing.pem \ intermediate-upper.pem \ > fullchain.pem ``` [标准领域知识] 根 CA 证书通常不需要放入 Nginx 对外发送的证书链。客户端是否信任该根 CA,由客户端的信任配置决定;服务器发送根 CA 不会自动建立信任。 ## 九、验证证书链、用途和访问名称 ### 9.1 验证证书链及服务器用途 [标准领域知识] 对于一级中间 CA,可执行: ```bash openssl verify \ -CAfile root-ca.pem \ -untrusted intermediate.pem \ -purpose sslserver \ server.pem ``` [标准领域知识] 验证通过时,输出形式如下: ```text server.pem: OK ``` [标准领域知识] `-CAfile` 指定本次验证信任的 CA 证书,`-untrusted` 提供用于构建证书链的中间证书,`-purpose sslserver` 检查证书链是否适用于 TLS 服务器用途。 [标准领域知识] 多级中间 CA 应先合并为中间证书集合,再通过 `-untrusted` 指定: ```bash cat \ intermediate-issuing.pem \ intermediate-upper.pem \ > intermediates.pem openssl verify \ -CAfile root-ca.pem \ -untrusted intermediates.pem \ -purpose sslserver \ server.pem ``` ### 9.2 验证域名 [标准领域知识] 对本次证书中的域名,可执行: ```bash openssl verify \ -CAfile root-ca.pem \ -untrusted intermediate.pem \ -purpose sslserver \ -verify_hostname t1.cloud.com \ server.pem ``` ### 9.3 验证 IP 地址 ```bash openssl verify \ -CAfile root-ca.pem \ -untrusted intermediate.pem \ -purpose sslserver \ -verify_ip 10.9.77.83 \ server.pem ``` [标准领域知识] 指定根 CA 后验证通过,表明证书在该信任配置和本次检查条件下通过验证,不代表所有浏览器或客户端均已信任该根 CA。 [标准领域知识] 上述命令默认不执行完整的吊销状态检查。需要检查 CRL 或 OCSP 时,应另行配置相应的吊销验证流程。 ## 十、检查有效期与证书指纹 ### 10.1 查看有效期 ```bash openssl x509 \ -in server.pem \ -noout \ -dates ``` [计算得出] 本次证书的有效期换算为北京时间如下: ```text 生效时间:2026-10-19 18:37:05 失效时间:2029-10-18 18:37:05 ``` ### 10.2 检查未来 30 天内是否到期 ```bash if openssl x509 \ -in server.pem \ -noout \ -checkend 2592000; then printf '证书在未来 30 天内不会到期。\n' else printf '证书将在未来 30 天内到期,或证书读取失败。\n' >&2 fi ``` [计算得出] `2592000` 秒等于 30 天。 [标准领域知识] `-checkend` 主要检查证书到期时间,不能替代完整的证书链、用途和名称验证。 ### 10.3 查看 SHA-256 指纹 ```bash openssl x509 \ -in server.pem \ -noout \ -fingerprint \ -sha256 ``` [标准领域知识] 证书指纹可用于核对不同位置的证书是否为同一张证书,不证明私钥匹配、证书受信任或服务端已正确加载。 ## 十一、配置并验证 Nginx ### 11.1 安装证书文件 [标准领域知识] 以下示例适用于由 root 启动并读取私钥的常见 Nginx 部署方式: ```bash sudo install -d -m 700 /etc/nginx/ssl sudo install -m 644 \ fullchain.pem \ /etc/nginx/ssl/fullchain.pem sudo install -m 600 \ server.key \ /etc/nginx/ssl/server.key ``` [标准领域知识] 如果 Nginx 以非 root 账户运行,应根据实际运行账户配置证书目录和私钥的属主、属组及读取权限。 ### 11.2 配置 HTTPS 服务 ```nginx server { listen 443 ssl; server_name t1.cloud.com; ssl_certificate /etc/nginx/ssl/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/server.key; ssl_protocols TLSv1.2 TLSv1.3; location / { root /usr/share/nginx/html; index index.html; } } ``` [标准领域知识] 示例中的域名、站点目录及协议配置应与实际服务环境一致。 ### 11.3 检查配置并重新加载 ```bash sudo nginx -t ``` [标准领域知识] 配置检查通过后,再重新加载服务: ```bash sudo systemctl reload nginx ``` [标准领域知识] `nginx -t` 用于检查配置语法并尝试打开配置引用的文件,不等同于客户端已经成功完成 TLS 握手。 ## 十二、验证服务端实际提供的证书 ### 12.1 使用 OpenSSL 验证在线服务 [标准领域知识] 将连接地址、SNI 名称和校验名称分别指定,可验证目标服务器在指定域名下实际提供的证书: ```bash openssl s_client \ -connect 10.1.2.1:443 \ -servername t1.cloud.com \ -verify_hostname t1.cloud.com \ -verify_return_error \ -CAfile root-ca.pem \ -showcerts \ </dev/null ``` [标准领域知识] 参数含义如下。 | 参数 | 用途 | |---|---| | `-connect` | 指定实际连接的 IP 地址和端口 | | `-servername` | 发送 SNI,供服务器选择对应站点和证书 | | `-verify_hostname` | 校验证书是否适用于指定域名 | | `-verify_return_error` | 将证书验证错误作为握手失败处理 | | `-CAfile` | 指定验证时使用的信任 CA | | `-showcerts` | 显示服务端实际发送的证书列表 | [标准领域知识] 仅使用 `-showcerts` 或观察到握手建立,不能证明证书名称及信任链验证通过。应同时检查命令退出状态及验证结果。 ### 12.2 使用 curl 验证 HTTPS 请求 [标准领域知识] 尚未配置 DNS 解析时,可通过 `--resolve` 指定目标 IP,同时保留 URL 域名用于 SNI 和证书名称校验: ```bash curl \ --cacert root-ca.pem \ --resolve t1.cloud.com:443:10.1.2.1 \ -I \ https://t1.cloud.com/ ``` [标准领域知识] 验证证书时不应增加 `-k` 或 `--insecure`,因为这些参数会跳过服务端证书校验。 [标准领域知识] HTTP 响应状态与 TLS 验证属于不同检查层次。例如,收到 `401`、`403` 或 `405` 响应时,应分别检查应用认证、访问控制或请求方法,不能直接将其判定为证书验证失败。 ## 十三、检查结果的判定边界 [标准领域知识] 不同检查操作能够证明的内容如下。 | 检查操作 | 能够确认的内容 | |---|---| | `openssl x509 -text` | 证书字段及扩展内容 | | `openssl pkey -check` | 私钥结构检查结果 | | 证书公钥与私钥公钥比较 | 证书与私钥是否匹配 | | `openssl verify` | 指定信任配置下的证书链验证结果 | | `-verify_hostname` / `-verify_ip` | 指定访问名称是否匹配 | | `nginx -t` | Nginx 配置检查结果 | | `openssl s_client` 配合验证参数 | 目标服务实际握手及证书验证结果 | | `curl --cacert` | HTTPS 请求过程中的证书验证及 HTTP 响应结果 | [标准领域知识] 证书处理完成后,应保留服务器证书、私钥、所需中间证书及验证记录,并按管理要求清理额外的私钥副本。正式验收应以实际服务地址、实际访问名称及目标客户端的信任配置为依据。
Nathan
2026年11月4日 13:17
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文件
Docx文件
分享
链接
类型
密码
更新密码