Smail/docs/静态安全告警复核记录.md
smail d6b74bcaad
Some checks are pending
Security Checks / security (push) Waiting to run
修复DNS签名参数复用并完成云端回归与安全复扫
2026-09-21 21:55:02 +08:00

13 KiB
Raw Permalink Blame History

静态安全告警复核记录

发布与 DNS 修复后的全项目复扫

2026 年 9 月 21 日,对包含发布回滚与 DNS 参数隔离修复的当前后端执行完整 Linux 目标扫描:GOOS=linux、GOARCH=amd64、CGO_ENABLED=0,扫描目录为 ./...,并发度为 1。 实际检查 84 个包、348 个非测试源码文件,共 56999 行;无包加载错误,工具退出 1,报告 38 条告警。

规则 数量
G115 2
G202 5
G304 20
G302 8
G306 2
G505 1

原始报告为 test-log/production-remediation-20260921/gosec-release-dns-final-linux-20260921.json,退出记录为 gosec-release-dns-final-exit-20260921.json。 按规则、文件及去除行号后的代码片段与管理员恢复批次的报告比较,告警集合一致,不只是总数相同。 报告中的忽略标记数量仍为原有的 5,没有新增批量忽略;不能把 38 条告警称为扫描通过。 619 份当前后端 Go 文件摘要在扫描期间未漂移,独立比对结果为 release-dns-final-recheck-20260921.json。

原有 7 条专项复核证据的范围保持不变,其他 31 条尚未整体关闭。 新增回滚测试和签名参数复用测试不构成 G304、G306 或 G505 的全量排除。 整体生产安全门禁继续未通过。

发布安装包局部复扫补充

2026 年 9 月 21 日,发布安装回滚整改后,仅对 internal/release 执行 Linux 目标复扫。 结果仍为 5 条告警:G304 四条、G306 一条,退出 1,无包加载错误,未使用忽略标记。 工具模块版本 v2.22.10,报告版本字段 dev;原始报告为 test-log/production-remediation-20260921/gosec-release-recheck-20260921.json。 回滚专项通过不代表这五条路径与权限告警已关闭;不能据此修改全项目历史扫描数量或宣称安全扫描清零。 缺陷反例、Windows 与云端 Linux 验证及剩余边界见 发布安装回滚补充验收.md。

9 月 21 日重启排空修复包复扫

在 f589f10 后端候选上修改 HTTP/HTTPS 停服逻辑后,仅复扫 ./listen/http_server:九个文件、2,035 行、告警零、包加载错误零、退出码零、nosec=0。这是本机针对 Linux 目标平台的变更包扫描,不是全项目再次扫描,也不是把全部历史告警清零。

证据:test-log/production-remediation-20260921/gosec-restart-http.json 及同名日志。JSON SHA-256 为 ec180df1a23d37ff6817c1013e5248bf1cbc231b418e4e6f3f403ea75747a4cd。此前全项目扫描仍为 38 条、退出码 1,剩余复核及历史凭据撤销门禁保持未完成。应用修复和实机证据见 数据库迁移重启补充验收.md。

结论与范围

本记录保留应用候选 8899e74、验收工具基线 ddc9652 的历史扫描,并补充基线 9e5496d 上管理员恢复整改后的候选。前一项只增加测试,后一项包含应用整改;均未替换正式程序。

原始安全扫描仍未通过,历史基线 44 条、管理员恢复整改后 38 条;告警数不等于可利用漏洞数,也不代表整个项目审计完成。

  • [✓] 最新 Linux 目标平台扫描完成并保留原始输出。
  • [✓] 五条 SQL 拼接告警和两条插件身份转换告警已有本轮源码复核及专项实机证据。
  • [✓] 管理员恢复专项已整改并取得云端回归证据;全项目减少六条告警,未增加扫描抑制。
  • 当前其余 31 条逐项整改或形成足以复审的排除依据。
  • [!] 未增加扫描抑制、降低等级或更改退出码;本轮证据不自动等同于生产放行。

历史扫描基线

北京时间 2026 年 9 月 21 日,Windows 主机执行 Linux/amd64、禁用 CGO 的目标平台扫描。本轮再次从可执行文件的 Go 模块构建信息核对工具版本为 gosec v2.22.10,报告展示版本仍为 dev;这不是云端原生执行的扫描。

项目 结果
扫描文件、行数 345、56,780
告警 44;高 5、中 37、低 2
Go 包加载错误 0
原有 nosec 5;本次没有增加
退出码 1
规则分布 G115 5、G202 5、G204 1、G304 20、G302 8、G306 2、G505 1、G104 2

原始文件:test-log/production-remediation-20260921/gosec-revocation-linux.log。 JSON 从上述日志末尾完整提取至同目录 gosec-revocation-linux.json;不能把提取过程描述为重新运行或扫描通过。

管理员恢复整改后的全项目复扫

北京时间 2026 年 9 月 21 日 03:47 至 04:16 左右,使用同一工具和 Linux/amd64 目标平台重新扫描。应用源码在扫描期间保持不变;候选主程序和云端三库回归见 管理员恢复安全补充验收.md。

项目 结果
扫描文件、行数 345、56,823
告警 38;高 2、中 36
Go 包加载错误 0
原有 nosec 5;未增加
扫描退出码 1
规则分布 G115 2、G202 5、G304 20、G302 8、G306 2、G505 1

原始输出为 test-log/production-remediation-20260921/gosec-admin-final-linux.log,完整提取 JSON 为同名 .json。管理员恢复的三条 G115、一条 G204 和两条 G104 已不再出现;其中关闭错误的显式忽略仅澄清意图,不能宣传为修复了两个已确认漏洞。旧七条专项证据仍有效,但扫描本身没有消除它们;其余三十一条仍未关闭。

根域名证书校验修复后的配置包复扫

随后在 37bb937 基线上修复共享证书校验遗漏根域名的问题,详见 根域名证书校验补充验收.md。本次仅重新扫描变更的 ./config 包:55 个文件、11,378 行、七条中等级告警(G304 五条、G302 两条),包加载错误零,原有 nosec 为 4,退出码 1。

原始文件为 gosec-apex-config.log,JSON 从同一完整日志提取。七条告警按规则、文件、行号、代码片段与上述全项目报告的配置包逐项比较完全一致;不增加忽略、不更改失败码。不能把变更包复扫描述为又一次全项目扫描,也不能认为未变告警已经排除。

已形成专项证据的七条告警

下表行号相对当前候选的 backend/。结论限于所列风险和代码路径,不涵盖整个迁移事务、所有输入来源、并发一致性或插件隔离能力。

规则与位置 源码复核依据 反例证据与边界
G202 services/dbmigration/sql_executor.go:239 SHOW FULL TABLES FROM 的数据库名称经过 quoteMySQLIdentifier;引用内的反引号成对转义 引用函数边界测试、真实 MySQL 特殊表名读写;不是所有数据库命名规则的完整验收
G202 services/dbmigration/sql_executor.go:278 源和目标数据库、表名分别引用,再拼接固定的 INSERT INTO 和 SELECT 语法 带结束引号、分号和删除语句的名称仍作为单一标识符,哨兵表保留
G202 services/dbmigration/sql_executor.go:365 数据库、表、约束、列逐项引用;外键动作由 listMySQLForeignKeys 调用白名单校验后返回 25 组带分号、注释、空字符或额外动作的后缀全部拒绝;未执行非法外键 DDL
G202 services/dbmigration/portable_data.go:192 只有经过引用的表名参与拼接;序列值通过 $1::regclass 绑定,不拼接序列内容 PostgreSQL 真实标识符测试通过;这不是对所有序列数值边界的验证
G202 services/dbmigration/portable_data.go:237 表名经过 PostgreSQL 标识符引用;序列名称和计数分别通过 $1、$2 绑定 PostgreSQL 引号、分号及中文表名实机通过;不替代完整迁移与故障注入验收
G115 hooks/plugin_isolation_linux.go:97,UID 转换 转换值仅来自 pluginIdentity,其返回前要求解析成功且介于 1 与 65534 UID 的 12 组输入覆盖合法边界、零、负数、上界外、溢出及非数字
G115 hooks/plugin_isolation_linux.go:97,GID 转换 与 UID 使用相同校验函数,错误时在构建进程凭据之前返回 GID 独立执行同样 12 组输入;不是整个插件沙箱的安全证明

这些证据支持“当前列出的路径已有约束,不能直接认定可利用注入或截断”。原始扫描没有消除这七条;正式排除仍需按清单复审,禁止添加整文件或整规则忽略。

历史待办三十七条及当前状态

下表保留旧扫描位置以便追溯。G115 三条、G204 一条、G104 两条已在管理员恢复专项中处理;当前仍需逐项复核的是 G304、G302、G306、G505,共三十一条。管理员恢复两条 G304 的新位置为 invocation_linux.go:123、:135。

规则 数量 位置及待办
G115 3 管理员恢复的 transport_unix.go:89、invocation_linux.go:50、terminal_linux.go:72;分别复核有效 UID、终端设备号和文件描述符转换。不能直接把有符号终端设备号改为拒绝负数
G204 1 services/adminreset/password_linux.go:86;复核外部进程名称、参数和执行环境的来源及调用边界
G304 20 运行目录 2、手动 SSL 2、迁移 1、管理员恢复 2、发布 4、插件隔离 4、配置与证书存储 5;逐项核对可信目录、符号链接、权限和竞态,不以路径来自配置为安全依据
G302 8 运行目录 2、管理员控制目录 1、插件目录及可执行文件 3、配置和 SSL 存储 2;区分目录执行位、二进制执行位与普通敏感文件,不能统一改成 0600
G306 2 发布清单与内嵌插件写入权限;需要复核实际文件种类、父目录以及现有文件权限
G505 1 DNS 签名代码的 SHA-1 导入;需核对具体协议用途与官方兼容要求,不擅自替换签名算法,也不将其视为密码哈希使用
G104 2 services/adminreset/invocation_linux.go:54,81;复核终端文件关闭失败的处理与恢复边界

完整位置、告警代码片段、置信度以原始 JSON 为准。上述分组不是批量排除结论。

实机执行与证据

新增测试文件:

  • backend/services/dbmigration/identifier_security_test.go
  • backend/hooks/plugin_identity_linux_test.go

本地数据库迁移包执行 node test/run.mjs backend -race -count=1 -p 1 ./services/dbmigration 两轮通过。初轮日志为 test-log/run-2026-09-20T18-29-14-906Z-25388/;补充脱敏错误分类后最终轮为 test-log/run-2026-09-20T18-41-49-136Z-34592/,耗时 9.604 秒。本地没有专用实库连接的用例会跳过,不计为实机通过。

交叉编译后的 Linux 测试程序上传云服务器,逐一校验 SHA-256,再以非特权 smail 身份、192 MiB 内存上限、禁用交换空间、50% CPU 配额和 120 秒运行上限执行。使用全新空数据库和随机专用账号,不改写正式数据库;凭据只通过管道与子进程环境传递,不写入证据文件或命令行。

最终实机证据:/var/tmp/smail-review-security-20260921/20260921-023702/。

检查 实际结果
SQL 引用边界 两种引用方式共 20 组输入通过
非法外键动作后缀 五种合法动作分别追加五种非法后缀,25 组拒绝断言通过
MySQL 7 个真实表名分别建表、写入、读取,哨兵数据始终为预设值
PostgreSQL 独立空库执行相同 7 组真实读写与哨兵检查
插件身份 UID/GID 合计 24 组通过
跳过、退出码 两项正式专项均无跳过、退出零;日志分别含 25 条 PASS 记录,含父测试,不能称为各 25 个顶层测试
资源峰值 数据库专项 9.6 MiB,插件专项 20.7 MiB;不用于推导生产容量
收尾 专用 SQL 账号锁定,无运行中的专项单元;正式服务及其他五个保护服务进程标识保持不变

最终测试二进制:

  • 数据库 identifier-db-v2.test:e57e771b236e6941cef292a219a3f09a47e89fda65d3083b7de7856b40aeb20e。
  • 插件 identifier-hooks.test:23fa5b14524c02ec49bde341d7f6886b6b58cf56387db03281968c19aa9e83ea。

十份有效下载文件位于 test-log/production-remediation-20260921/security-evidence/,摘要在 index.json,包括失败记录,不能全部计作通过证据。

保留的失败与环境修正

  1. 023145:PrivateTmp=yes 隐藏了 /var/tmp 下测试程序,业务测试未启动。增加仅测试目录的只读映射后重跑,没有放宽正式目录隔离。
  2. 023255:数据库辅助工具使用 postgres,配置类型为 postgresql,环境变量未对应,PostgreSQL 用例跳过。外层验收因存在跳过而失败,随后修正工具侧映射;没有把退出零当成全部通过。
  3. 023355:PostgreSQL 驱动尝试探测服务用户默认客户端证书,但其主目录 /opt/smail 按设计不可访问。初始测试错误把查询失败与非空数据库合并显示;现区分文件访问失败、查询失败与非空库,错误信息不输出凭据。
  4. 023702/homeguard.log:同一隔离条件下单独重现 stat postgresql.crt 失败。正式专项将可选客户端证书路径设置为私有临时目录中明确不存在的文件,保留 TLS sslmode=require,不访问正式证书、不禁用 TLS;随后两种数据库均通过。

homeguard 是预期失败的环境反例,不是数据库正向通过。仍保留失败单元状态供复核,没有运行中的测试进程,也没有重置或隐藏系统失败记录。