恢复对帮助网站的验证访问

网络安全Beginner
立即练习

介绍

支持团队刚部署了帮助网站,但客户端拒绝建立 HTTPS 连接。HTTPS 使用 TLS 加密流量并证明响应服务器的身份。仅有加密并不能证明身份:客户端还必须确认请求的名称,并信任证书的签发者。

你将为真实的 Nginx 服务器修复合成的培训证书。只需具备基本终端操作经验;本实验会介绍证书检查与服务配置。Client 和 Server 是同一台 VM 上的独立会话和目录,并非两台计算机。Nginx 在预置容器中运行。可选的 HTTPS Monitor 展示内部 TLS 实时探测结果;浏览器自身的锁图标对应另一条外部连接。

获取受信任的参考文档

本步骤先从正常服务获取文档,再与故障帮助网站比较。主机名用于标识请求的服务。所有培训名称都以 .lab.test 结尾,仅用于本练习。

使用 Client 标签页。curl 获取 URL。--cacert root.crt 信任提供的证书颁发机构(CA);CA 负责签署证书。实验 CA 是培训信任锚,并非公共机构。--resolve 将指定名称和端口映射到 IP 地址,同时保留 TLS 和 HTTP 使用的名称。127.0.0.1 表示当前 VM;端口 8443 通往预置 Nginx 服务。--noproxy '*' 使请求直接发送;引号防止 shell 展开 *。--fail 拒绝 HTTP 错误,--output 保存实际服务文档以供后续使用。

curl --noproxy '*' --fail --cacert root.crt --resolve status.lab.test:8443:127.0.0.1 --output reference.txt https://status.lab.test:8443/

cat 显示文件内容:

cat reference.txt
status service: training content available

这次下载得到的是真实参考文档,而非报告。现在请求预期的帮助主机名。下面的命令应当失败并返回提示符;随后继续操作。

curl --noproxy '*' --cacert root.crt --resolve help.lab.test:8443:127.0.0.1 https://help.lab.test:8443/
curl: (60) SSL: no alternative certificate subject name matches target host name 'help.lab.test'
...

参考服务使用相同的 CA 和地址却正常工作。此错误明确指向名称不匹配,而非服务器停止运行。保留预期主机名:修改 URL 将测试另一个身份。

检查并组装证书链

本步骤将比较实际提供的身份与预置证书,并构建可用的服务器证书包。证书包含公钥和身份信息,配套私钥留在服务器上。切勿将私钥粘贴到报告中或发送给客户端。

在 Client 中检查服务器实际提供的证书。openssl s_client 建立 TLS 连接;-connect 指定地址,-servername 通过服务器名称指示(SNI)发送请求的主机名,使一个 Nginx 监听器能够承载多个网站。< /dev/null 结束交互输入。2>/dev/null 仅为本次检查隐藏连接诊断信息。管道 | 将证书传给 openssl x509;-noout 隐藏编码后的证书,其余选项显示指定字段。此检查本身并不能证明信任关系。

openssl s_client -connect 127.0.0.1:8443 -servername help.lab.test </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates -ext subjectAltName
subject=CN = legacy.lab.test
issuer=CN = LabEx Training Issuing CA
notBefore=...
notAfter=...
X509v3 Subject Alternative Name:
    DNS:legacy.lab.test

使用者可选名称(SAN)列出证书接受的主机名。issuer 标识签发者;日期限定有效期。初始化为当前 VM 生成全新证书:叶证书有效期为 365 天。日期有效不能弥补名称错误。

切换到 Server。openssl x509 -in 读取本地证书,而非网络响应:

openssl x509 -in certs/help.crt -noout -subject -issuer -dates -ext subjectAltName

其 SAN 为 DNS:help.lab.test,与请求一致。预期关系如下:

项目 用途
help.crt 和 help.key 帮助网站的证书和配套私钥
docs.crt 和 docs.key 文档网站的证书和配套私钥
issuing.crt 签署两个网站证书的中间 CA
../client/root.crt 客户端信任的根 CA

证书链为网站证书 → 中间 CA → 受信任的根 CA。Nginx 应先发送叶证书,再发送中间证书。客户端已信任根证书,无需发送它。使用 cat 构建公共证书包;> 将输出写入文件,替换已有内容。私钥不属于此证书包。

cat certs/help.crt certs/issuing.crt > certs/help-fullchain.pem

openssl verify 根据指定的受信任根验证证书包。-untrusted 将中间证书作为可能的链路,而非额外信任的根;-verify_hostname 检查预期名称。

openssl verify -CAfile ../client/root.crt -untrusted certs/help-fullchain.pem -verify_hostname help.lab.test certs/help-fullchain.pem
certs/help-fullchain.pem: OK

若失败,检查输入文件顺序和拼写,然后重复 cat 命令。此操作验证的是准备好的证书包;运行中的服务器还需要使用它。

应用帮助网站身份

本步骤让 Nginx 提供正确身份,同时保持状态网站正常。在 Server 中使用 cat 显示配置:

cat conf/help.conf

server_name 选择网站。ssl_certificate 指定公共证书链;ssl_certificate_key 指定私钥。以 /tls/ 开头的路径位于预置 Nginx 容器内部,对应当前目录的 certs/。return 200 行提供真实的培训帮助内容。保留监听器、名称和响应内容。

使用 nano 文本编辑器打开文件:

nano conf/help.conf

用方向键找到两个 TLS 指令。仅将这两行替换为:

    ssl_certificate /tls/help-fullchain.pem;
    ssl_certificate_key /tls/help.key;

分号用于结束 Nginx 指令。按 Ctrl+O 保存,按 Enter 确认,再按 Ctrl+X 退出。如果路径拼错,重新打开同一文件修正。

sudo 以管理员权限运行命令。docker exec https-edge 在预置服务容器内执行后续命令。nginx -t 测试配置而不应用它:

sudo docker exec https-edge nginx -t

查找 syntax is ok 和 test is successful。若测试失败,先修正提示的文件和行。nginx -s reload 请求运行中的服务加载测试过的配置:

sudo docker exec https-edge nginx -s reload

切换到 Client,重复对预期网站的请求。重新加载可能需要片刻;若仍看到旧证书,重试同一请求。

curl --noproxy '*' --fail --cacert root.crt --resolve help.lab.test:8443:127.0.0.1 https://help.lab.test:8443/
help service: training content available

还要保留参考网站的正常功能:

curl --noproxy '*' --fail --cacert root.crt --resolve status.lab.test:8443:127.0.0.1 https://status.lab.test:8443/

成功意味着在接受帮助响应前,已检查实际的主机名、证书链和有效日期。仅编辑未使用的证书文件无法得到此结果。

修复缺失的中间证书

本步骤将区分不完整证书链与刚才修复的名称不匹配。留在 Client 中,请求预置文档网站。下面的失败是预期现象:

curl --noproxy '*' --cacert root.crt --resolve docs.lab.test:8443:127.0.0.1 https://docs.lab.test:8443/
curl: (60) SSL certificate problem: unable to get local issuer certificate
...

两种失败都使用退出码 60;应阅读随附说明。用同样的命令格式检查实际提供的证书:

openssl s_client -connect 127.0.0.1:8443 -servername docs.lab.test </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates -ext subjectAltName

这次 SAN 是 DNS:docs.lab.test。名称正确,但 Nginx 只发送叶证书,客户端无法将其签发者连接到根。

进行一次受控比较:-k 跳过证书验证,说明信任关系仍损坏时也能获取内容:

curl --noproxy '*' -k --resolve docs.lab.test:8443:127.0.0.1 https://docs.lab.test:8443/

此时看到 docs service: training content available 并不代表修复。返回 Server,查看活动文件,再打开它:

cat conf/docs.conf
nano conf/docs.conf

预置的 docs-fullchain.pem 已按顺序包含叶证书和中间证书。仅替换 ssl_certificate 行:

    ssl_certificate /tls/docs-fullchain.pem;

保留 /tls/docs.key 作为私钥。按此前方法保存退出,再测试并重新加载:

sudo docker exec https-edge nginx -t
sudo docker exec https-edge nginx -s reload

在 Client 中请求三个预期名称,不使用 -k。循环依次将列出的值赋给 host;$host 插入该值,双引号使生成的每个参数保持完整。

for host in help docs status; do
  curl --noproxy '*' --fail --cacert root.crt --resolve "$host.lab.test:8443:127.0.0.1" "https://$host.lab.test:8443/"
done

应看到三个对应的服务响应。你也可以刷新 HTTPS Monitor,比较独立的实时探测结果。遇到错误时返回相应配置修正、测试并重新加载;不要修改客户端信任根或预期主机名。真实部署应通过组织的证书签发流程取得批准的证书;本练习提供合成候选证书,让你专注于诊断。

总结

你获取了受信任的参考文档,检查了实际证书名称和签发者,组装了叶证书与中间证书包,并通过测试后的 Nginx 重新加载应用配置。你在保持正常服务的同时修复了名称不匹配和不完整证书链。接下来的挑战会在另一个门户中组合这些判断。