Smail/docs/根域名证书校验补充验收.md
smail 2e520eb5a8
Some checks are pending
Security Checks / security (push) Waiting to run
统一根域名与泛域名证书校验并补充云端反例验收
2026-09-21 04:38:46 +08:00

7.3 KiB
Raw Blame History

根域名证书校验补充验收

结论与范围

北京时间 2026 年 9 月 21 日,在已提交并推送的 37bb937 基线上补充验收。发现并修复自动 DNS 证书的校验不一致:申请时要求根域名和泛域名,但运行时共用的域名列表遗漏根域名。正式程序没有替换,其他项目没有停止,用户原有云端测试报告没有修改。

这是一个已实机复现并修复的证书覆盖缺口,不代表真实 DNS 续期或整体验收通过。

需求与任务清单

  • [✓] 自动 DNS 证书在申请、配置复验、加载和导出阶段均要求根域名与泛域名。
  • [✓] 在云服务器保留整改前失败反例,再用新编译测试程序验证修复。
  • [✓] 无效新证书不替换有效导出文件;热加载失败时保留尚有效的内存证书。
  • [✓] 后续完整证书仍可热加载,外部证书管理模式的既有兼容测试通过。
  • [✓] 云端配置证书专项 21 个顶层测试、SSL 初始化包 26 个顶层测试,均零跳过通过。
  • [✓] 本地运行时校验与热加载专项竞态回归通过。
  • [✓] 最新前端、插件和 Linux 程序已编译,三库空数据实机回归通过。
  • [✓] 配置包静态安全复扫完成,原有七条告警未增加;扫描退出 1,不计为安全门禁通过。
  • [!] 公网 DNS 挑战、自动续期、真实 CA 换证和全协议热加载仍需单独实机验收。

整改前反例

测试通过托管存储准备有效期内、密钥配对正确但仅包含 *.example.com 的测试证书,故意不在准备阶段校验域名,模拟已有文件的加载场景。没有使用正式私钥或修改正式证书。

云端目录:/var/tmp/smail-review-ssl-apex-20260921/20260921-042413-before/。

  • 配置引用复验错误接受缺少根域名的证书。
  • 当前及旧自动 DNS 配置的运行时加载均错误接受。
  • 导出错误接受该证书,并替换已导出的有效证书包。
  • 根域名加泛域名的正向用例通过;只有根域名的反例已能正确拒绝。

本轮两个顶层测试失败,零跳过,云端测试退出 1。日志完整保留在 test-log/production-remediation-20260921/ssl-apex-before/。这是一个共享校验列表缺口的多路径表现,不按断言数宣传漏洞数量。

修复和回归

backend/config/ssl_custom.go 的 validationCertificateDomains 在自动 DNS 项目托管模式明确加入根域名,继续要求泛域名及已配置的服务域名。保留既有文件安全、证书密钥匹配、有效期和强度校验,不改变手动证书入口、管理责任或 DNS 记录。

新增 backend/config/ssl_apex_test.go,覆盖配置复验、当前及旧配置加载、导出文件内容和身份保留,以及内存证书的拒绝与后续恢复。热加载测试调用实际运行时证书回调,但不是外部客户端对全部邮件协议的换证演练。

云端轮次 目录后缀 结果
最终配置证书专项 20260921-042721-final 21 个顶层测试通过,零跳过,退出零
SSL 初始化完整包 20260921-042935-setup-all 26 个顶层测试通过,零跳过,退出零

测试使用非特权 smail、独立临时目录及私有网络,正式目录不可访问;内存上限 256 MiB、CPU 配额 50%、禁用交换空间、运行时间上限 300 秒。最终配置证书专项执行输出记录内存峰值 8.1 MiB,不据此推导生产容量。

本地命令为 node test/run.mjs backend -race -count=1 -p 1 -run '^TestProjectDNS(Runtime|Reload)' ./config,通过。日志目录 test-log/run-2026-09-20T20-28-01-801Z-38632/ 使用 UTC 文件名,不是北京时间日期。

候选产物

前端、Telegram 界面、三个 Linux 插件、Linux 主程序与管理员工具重新编译。版本为 review-apex-20260921,内嵌源码标识为 37bb937c4040ae35a9393c418b9d7679f7bd436d-dirty,不冒充已发布版本。

产物 SHA-256
主程序 bb451caf67f6421253c5b4edddc6fce9961ac04613c4fe3166db36a465291939
管理员工具 e5b540a23f598f892f23b17f59e2f97c7560f8c3dca317ba6b6cdf2d67485821
最终配置测试程序 6d2cda0c4f3483bb05de86b8067588e27689f80043bd17b3e501e38cbbedacb4
SSL 初始化测试程序 263126767560b5e09eccbc415eff5de4192c9c5babc6b16d90417f904a81db4d

构建日志和摘要位于 test-log/production-remediation-20260921/build-apex.log、apex-build-manifest.json;配置目录 94 个 Go 文件的摘要记录在 apex-config-source-manifest.json。

最新候选三库实机回归

同一主程序上传至 /var/tmp/smail-review-apex-20260921/,每轮创建新的空数据隔离实例,以 192 MiB 内存限额验证直接 TLS 拓扑。

数据库 实例目录后缀 结果
SQLite smail-review-runtime-20260921-043114 通过;只有 smail.db,完整性检查正常
MySQL smail-review-runtime-20260921-043229 通过;配置历史与业务同库,SQLite 文件零个
PostgreSQL smail-review-runtime-20260921-043411 通过;配置历史与业务同库,SQLite 文件零个

覆盖空库初始化、中文邮件和附件、IMAP APPEND/EXPUNGE、HTTP 旧会话撤销、协议码及客户端码撤销后的旧连接拒绝、过载恢复。三轮均无 OOM、资源采集错误或清理错误;SQL 测试账号已锁定,桥接已停止。

证据为 apex-runtime-results.json、apex-runtime-evidence/ 和 apex-evidence-index.json,共十二份下载文件的摘要已经逐一复核。apex-live-final.json 再次确认六个保护服务和正式程序摘要未变,没有运行中的本轮隔离服务。该回归使用隔离域名和手动测试证书,不冒充公网域名验收、真实自动续期或新候选的 Nginx 正向复验。

静态扫描边界

Windows 主机设置 Linux/amd64、禁用 CGO,对 ./config 运行原有 gosec v2.22.10。55 个文件、11,378 行,包加载错误零,原有 nosec 为 4;七条告警均为中等级,G304 五条、G302 两条,退出码 1。逐条按规则、文件、行号和代码片段与上一轮全项目报告中的配置包比较,集合完全一致。

原始日志为 gosec-apex-config.log,完整提取的 JSON 为 gosec-apex-config.json,SHA-256 为 7c0eed5bd0cb48ab5fd926c431a8155671c5f8418aaeaa9830e49512c2ca7db9。扫描后配置目录九十四个源码文件与构建时清单一致。这里只复扫变更包,不把它说成又一次全项目扫描;上一候选全项目三十八条仍是未通过记录,其他待办没有关闭。

保留的工具失败与证据边界

首次修复后,两个测试已经退出零,但验收辅助工具无条件再次停止已被 systemd 回收的短时单元,收到退出 5,将该轮判为失败;原始记录保留在 ssl-apex-after/,没有改成通过。

后续辅助工具额外读取 LoadState、ActiveState、MainPID,仅在进程为零、状态不活动且明确 not-found 时接受该停止返回值;其他停止错误仍拒绝。新建隔离轮次重新执行后通过。失败记录没有重置,正式服务进程标识和正式主程序摘要均保持不变。

原有浏览器、凭据轮换、外部邮件最终收件、迁移进程重启、容量和异机灾备等门禁仍保留,详见 生产补充验收记录.md。