feat: add Fail2ban security detection console

This commit is contained in:
hectorzhao
2026-08-14 10:58:18 +08:00
parent b78faa1aa2
commit d30d9ea4d0
45 changed files with 1967 additions and 18 deletions
+5
View File
@@ -1138,3 +1138,8 @@ global,不能错误归入client。`client-signature-*`、发送页、企业认
```
每次开始新拆分版本时,在本路线图基础上另写该版本的短实施计划,不直接把路线图当作可执行变更清单。
## 安全检测领域边界补充(2026-08-14)
- `api/src/security-detection/` 是安全事件、聚合告警、规则版本和人工封禁编排的唯一业务边界;登录、OpenAPI 和 Gateway 只上报固定类型的结构化事件,不复制聚合或封禁逻辑。
- `gateway/cmd/security-agent/` 是最小特权执行边界,不依赖 NestJS Service,不接受任意命令、路径、jail、action 或 shell 参数。该二进制与 `deploy/security/``tools/security/install-security-agent.sh` 作为同一发布单元评审。
- 前端 `src/apps/admin/security-detection/` 通过 `src/api/admin/security-detection.api.ts` 访问稳定门面,不直接访问 Fail2ban、Nginx、nftables 或安全代理。
@@ -0,0 +1,378 @@
# Fail2ban 安全检测与人工封禁平台设计方案
> 版本:V1.0(需求评审稿)<br>
> 日期:2026-08-14<br>
> 范围:运营端自研 UI、安全检测、阈值配置、告警处置、人工封禁与解封<br>
> 边界:第一版不自动封禁、不开放任意 Fail2ban/防火墙命令、不在线编辑正则表达式
## 1. 建设目标
在运营端“安全控制”下建设自研安全检测面板,统一接收 SSH、运营端登录、客户端登录、CMPP 入站和 HTTP API 的异常行为,按照可配置规则聚合为安全告警。平台管理员查看证据后,可人工执行固定时长封禁、解封、忽略或加入保护名单。
第一版采用“检测与执行分离”原则:
1. Fail2ban 和应用侧检测器只生成事件及告警,不自动修改防火墙。
2. 人工点击“封禁”后,后端重新校验告警、真实 IP、保护名单、执行目标和操作权限。
3. 只有受限安全代理可以执行系统级封禁;NestJS 不直接获得 root、通用 sudo 或任意 shell 能力。
4. PostgreSQL 保存配置、事件、告警、封禁事实和操作审计;页面不得使用 mock、静态数据或 localStorage 伪造状态。
## 2. 第一版范围
### 2.1 检测类型
| 规则编码 | 检测对象 | 事件来源 | 第一版默认建议值 | 默认风险 |
| --- | --- | --- | --- | --- |
| `admin_login_failure` | 运营端账号登录失败 | NestJS 结构化安全事件 | 同一 IP 10 分钟 8 次 | 中 |
| `client_login_failure` | 客户端账号登录失败 | NestJS 结构化安全事件 | 同一 IP 10 分钟 8 次 | 中 |
| `ssh_auth_failure` | SSH 12022 认证失败 | journald + Fail2ban filter | 同一 IP 10 分钟 6 次 | 高 |
| `cmpp_auth_failure` | CMPP 17890 未知账号、认证失败或不允许 IP | Gateway 结构化安全事件 | 同一 IP 5 分钟 5 次 | 高 |
| `cmpp_protocol_abuse` | 非法协议包、异常版本或高频无效连接 | Gateway 结构化安全事件 | 同一 IP 1 分钟 20 次 | 高 |
| `http_invalid_api_key` | HTTP API 错误或未知访问密钥 | NestJS HTTP API 鉴权事件 | 同一 IP 5 分钟 10 次 | 高 |
| `http_signature_failure` | HTTP API 签名缺失、格式错误或验签失败 | NestJS HTTP API 验签事件 | 同一 IP 5 分钟 10 次 | 高 |
| `http_replay_attempt` | nonce、时间戳或幂等凭证重放 | NestJS HTTP API 验签事件 | 同一 IP 10 分钟 3 次 | 严重 |
| `http_malicious_scan` | 扫描敏感路径、跨路径高频 404、明显漏洞探测 | Nginx 结构化日志 + Fail2ban filter | 同一 IP 1 分钟 20 次且涉及至少 8 个不同路径 | 高 |
表中数值只是首次安装默认值,必须保存到真实数据库并可在运营端配置。业务 400、正常参数校验失败、合法客户偶发时钟偏差、普通 404、供应商连接失败不得直接归类为攻击。
### 2.2 处置能力
- 查看检测总览、趋势、来源、风险等级、Top IP 和待处置告警。
- 查看告警详情、脱敏日志证据、规则快照和历史处置。
- 人工封禁固定时长:10 分钟、1 小时、24 小时、7 天。
- 人工解封、忽略告警、加入保护名单。
- 查看当前真实封禁、执行目标、到期时间和同步状态。
- 配置检测规则阈值、时间窗口、冷却时间、风险等级和启停状态。
- 查看 Fail2ban、事件采集器、安全代理、规则版本及封禁执行器健康状态。
### 2.3 第一版不做
- 自动封禁。
- 永久封禁或前端输入任意封禁秒数。
- 在线编辑 Fail2ban regex、日志路径、action、iptables/nftables 或 Nginx 配置文本。
- 从页面执行任意 shell、`fail2ban-client``systemctl` 或防火墙命令。
- 自动将外部威胁情报加入封禁。
- 删除原始告警和处置历史。
## 3. 总体架构
```text
sshd journal ── Fail2ban 检测 jail ─┐
Nginx access/error ─ Fail2ban jail ─┤
NestJS 登录/HTTP 鉴权安全事件 ──────┤
Go Gateway CMPP 安全事件 ───────────┤
Security Event Collector
PostgreSQL 事件、规则、告警、封禁
NestJS 运营端安全 API
自研运营端 UI
↓ 人工确认
Root Security Agent (Unix Socket)
↓ ↓
nftables/manual jail Nginx real-IP deny
```
### 3.1 组件职责
#### Fail2ban
- 读取 sshd 和 Nginx 等系统日志。
- 使用固定、随版本发布的 filter 识别失败行为。
- 根据已生效规则计算窗口与阈值。
- 触发“告警事件 action”,但不直接封禁。
- 不作为平台告警历史和真实封禁状态的唯一数据源。
#### 应用侧安全事件
NestJS 和 Gateway 对其掌握真实业务语义的事件直接产生结构化安全事件,避免只靠文本正则猜测:
- 登录入口、失败类型和真实请求 IP。
- HTTP API 密钥查找失败、签名失败、重放拒绝。
- CMPP 账号、AuthenticatorSource 校验、IP 白名单和协议异常。
任何安全事件不得记录明文密码、完整 API 密钥、签名密钥、AuthenticatorSource 或完整短信内容;账号、密钥标识只保存脱敏值或不可逆指纹。
#### Security Event Collector
- 通过受限 Unix Socket 或 root 写入、collector 只读的事件目录接收 Fail2ban 事件。
- 校验事件版本、规则编码、IP、时间和来源。
- 写入 PostgreSQL,并依据数据库规则做幂等聚合。
- 维护最后事件时间、丢弃数量和解析失败指标。
#### Root Security Agent
- 独立于 NestJS,以最小 root 权限运行。
- 仅监听本机 Unix Socket,不监听 TCP 公网端口。
- 只接受固定 JSON 协议:`block``unblock``status``apply_rule_version`
- 对规则编码、执行器、IPv4/IPv6、时长和幂等键做白名单校验。
- 使用无 shell 参数数组或原生库执行,不拼接命令。
- 原子生成平台专属配置文件,校验后才 reload;失败保留旧版本。
#### NestJS
- 读取真实 PostgreSQL 告警和配置。
- 执行 RBAC、近期重新认证、保护名单和状态校验。
- 创建封禁操作记录并调用本地安全代理。
- 根据代理回读结果确认真实封禁状态。
- 不以 root 运行,不直接写 `/etc/fail2ban/*` 或防火墙。
## 4. Cloudflare 与执行器选择
恢复 `CF-Connecting-IP` 只能让 Nginx/应用识别访客真实 IP,并不会改变到达服务器的 TCP 源地址。对 `sms.lisglo.com` 的 Cloudflare 橙云流量,nftables 封禁访客真实 IP 无效,误封 Cloudflare 节点反而可能中断全站。
第一版按入口固定执行器:
| 入口 | 网络形态 | 检测 IP | 人工封禁执行器 |
| --- | --- | --- | --- |
| 运营端、客户端 | Cloudflare 橙云 | 经过可信 Cloudflare 网段恢复的真实 IP | Nginx real-IP deny;未来可扩展 Cloudflare API |
| `api.lisglo.com` | 灰云直连 | TCP 源 IP | nftables/manual jail |
| SSH 12022 | 公网直连 | TCP 源 IP | nftables/manual jail |
| CMPP 17890 | 公网直连 | Gateway TCP 远端 IP | nftables/manual jail |
只有当请求 TCP 来源属于定期同步的 Cloudflare 官方网段时,才信任 `CF-Connecting-IP`。客户端直连源站时提供的同名 Header 必须忽略。配置上线前必须用真实请求证明日志、事件和页面展示 IP 一致。
## 5. 可配置规则
### 5.1 可配置字段
- 启用状态 `enabled`
- 统计窗口 `windowSeconds`
- 触发阈值 `threshold`
- 不同目标数量阈值 `distinctTargetThreshold`,仅恶意扫描等规则使用。
- 告警冷却时间 `cooldownSeconds`
- 风险等级 `severity`
- 聚合维度,只能从规则预置集合选择,例如 `ip``ip+accountFingerprint`
- 默认封禁时长和允许的最大封禁时长。
- 是否允许人工封禁;只读检测规则可以关闭封禁按钮。
### 5.2 不可由页面配置的字段
- filter 正则表达式。
- 日志文件路径和 journal unit。
- shell 命令、Fail2ban action、nftables 表/链。
- Unix Socket 路径、systemd 服务名。
- Cloudflare 可信网段来源。
- 规则到执行器的映射。
这些内容属于发布资产,必须通过代码评审、自动化测试和标准部署更新。
### 5.3 配置保护
- 每类规则设置服务端最小值、最大值和允许枚举;前端约束不能替代后端校验。
- 阈值修改使用乐观锁版本号,防止多人覆盖。
- 保存后生成新规则版本,安全代理先语法校验,再原子切换并 reload。
- reload 失败时数据库状态标记 `apply_failed`,保留旧生效版本,页面明确展示“已保存但未生效”。
- 每次变更保存操作人、原因、旧值、新值、生效版本、代理回执和时间。
- 配置修改要求 `security.rule.manage` 权限和近期重新认证。
## 6. 数据模型
### 6.1 `SecurityDetectionRule`
- `id``code`(唯一)、`name``category``description`
- `enabled``windowSeconds``threshold``distinctTargetThreshold`
- `cooldownSeconds``severity``groupingMode`
- `manualBlockAllowed``defaultBlockDurationSeconds``maxBlockDurationSeconds`
- `configVersion``effectiveVersion``applyStatus``lastApplyError`
- `updatedById``createdAt``updatedAt`
### 6.2 `SecurityDetectionEvent`
- `id``eventKey`(唯一幂等键)、`ruleCode``sourceType`
- `sourceIp``accountFingerprint``targetFingerprint``requestPathNormalized`
- `occurredAt``receivedAt``evidenceSummary``metadata`
- `collectorInstanceId``ruleVersion`
`metadata` 使用后端安全 DTO,仅保存允许字段;禁止保存密钥和完整认证材料。
### 6.3 `SecurityAlert`
- `id``alertNo``fingerprint``ruleId``ruleSnapshot`
- `sourceIp``status``severity`
- `firstOccurredAt``lastOccurredAt``eventCount``distinctTargetCount`
- `cooldownUntil``assignedToId``handledById``handledAt``handleReason`
- `blockId``createdAt``updatedAt`
同一规则、IP、聚合维度和窗口桶使用唯一 fingerprint,重复采集只增加计数,不重复创建告警。
### 6.4 `SecurityBlock`
- `id``operationKey`(唯一)、`alertId``sourceIp`
- `executorType``executorTarget``durationSeconds`
- `status``requested/applying/blocked/unblock_requested/unblocked/expired/failed`
- `startedAt``expiresAt``verifiedAt``errorMessage`
- `requestedById``requestReason``unblockedById``unblockReason`
- `agentOperationId``createdAt``updatedAt`
### 6.5 `SecurityProtectedNetwork`
- IP/CIDR、名称、类型、适用入口、启停状态、来源和备注。
- 系统内置保护项不可从页面删除,只允许通过受控发布更新。
- 人工保护项新增、修改和停用均要求重新认证和审计。
## 7. 状态机与并发控制
### 7.1 告警状态
```text
pending ──→ block_requested ──→ blocked ──→ unblocked
│ └──────────→ block_failed
├──→ ignored
├──→ whitelisted
└──→ expired
```
- `pending` 仅表示达到检测阈值,绝不代表已被防火墙封禁。
- 封禁按钮通过数据库条件更新原子认领,只有一名操作人能进入 `block_requested`
- 代理执行成功后必须回读执行器状态,确认存在真实规则才写 `blocked`
- 网络超时导致结果不确定时先查询 `operationKey`,不得盲目重复封禁。
- 忽略、保护名单和封禁互斥;状态变化后旧页面操作返回 409。
### 7.2 封禁到期
- 执行器负责真实到期解除;平台定时回读并同步 `expired`
- 平台任务只做状态对账,不能仅靠数据库时间把记录标记为已解封。
- 对账发现执行器缺失、额外规则或到期未解除时生成系统告警。
## 8. 后端接口
```text
GET /api/admin/security-detection/overview
GET /api/admin/security-detection/trends
GET /api/admin/security-detection/alerts
GET /api/admin/security-detection/alerts/:id
POST /api/admin/security-detection/alerts/:id/block
POST /api/admin/security-detection/alerts/:id/ignore
POST /api/admin/security-detection/alerts/:id/protect
GET /api/admin/security-detection/blocks
POST /api/admin/security-detection/blocks/:id/unblock
GET /api/admin/security-detection/rules
PUT /api/admin/security-detection/rules/:id
GET /api/admin/security-detection/protected-networks
GET /api/admin/security-detection/health
```
封禁请求只接受固定时长枚举和原因。IP、规则、入口和执行器全部从告警及服务端映射读取,禁止前端重传或覆盖。
## 9. 权限与审计
| 权限 | 能力 |
| --- | --- |
| `security.alert.read` | 查看面板、告警和脱敏证据 |
| `security.alert.handle` | 忽略告警、分派和填写处置说明 |
| `security.block.manage` | 人工封禁与解封 |
| `security.rule.manage` | 修改阈值、启停规则和保护名单 |
封禁、解封、修改规则和保护名单必须要求近期重新认证;所有动作写入 `OperationLog`,记录资源、操作人、IP、原因、旧值、新值、代理回执和最终结果。读取完整证据也应记录访问审计。
## 10. 自研 UI 信息架构
菜单位置:`安全控制 / 安全检测`
### 10.1 总览
- 待处置、高风险、当前真实封禁、24 小时攻击 IP、封禁失败五个指标。
- 24 小时/7 天检测事件与告警趋势。
- 按规则类型、入口和风险等级分布。
- Top 攻击 IP、Top 扫描路径、Top 被尝试账号指纹。
- Fail2ban、collector、agent、规则版本和执行器健康卡片。
### 10.2 告警中心
- 按关键词、IP、规则、风险、状态、入口和日期筛选,真实后端分页。
- 列表展示风险、IP、类型、触发数、不同目标数、首次/最近时间、状态和操作。
- 详情抽屉展示规则快照、聚合时间线、脱敏证据、关联告警和处置历史。
- 封禁确认弹窗展示执行器、影响入口、时长、保护名单结果、近期合法访问提示和必填原因。
### 10.3 规则配置
- 使用平台现有自研 Card、Table、Tag、Modal、Form、Pagination 和图表体系,不嵌入 Fail2ban 第三方面板。
- 每项配置展示当前生效值、待生效值、最后修改人和应用状态。
- 数字输入同时展示单位、允许范围和默认建议值。
- 保存前展示变更对比;应用失败不能显示成功 toast。
### 10.4 封禁与保护名单
- 独立展示真实封禁状态、执行器、到期时间、来源告警和操作人。
- 保护名单命中时封禁按钮禁用并说明原因。
- 不同执行器使用明确标签,避免把 Nginx deny 误称为防火墙封禁。
## 11. 检测准确性要求
### 11.1 HTTP API
- 错误密钥:只记录不可逆密钥指纹,不记录完整 Header 或密钥。
- 签名错误:区分缺失、格式错误、算法不支持、验签失败和时间偏差。
- 重放:只有 nonce/幂等凭证已被真实使用或时间戳明显重复时计入;正常幂等重试按既有接口语义处理。
- 恶意扫描:使用标准化路径,不保存 query 中的敏感值;规则需要“次数 + 不同路径数”双阈值,避免单个合法 404 被判攻击。
- 反向代理真实 IP 必须经过可信代理链验证,禁止直接信任客户端 Header。
### 11.2 CMPP
- 未知账号、错误 AuthenticatorSource、不允许 IP、停用企业/应用和协议异常分别分类。
- 不记录明文密码、完整 AuthenticatorSource 或平台配置密钥。
- 正常断线、心跳超时、最大连接数限制和服务重启恢复不计为恶意认证。
### 11.3 登录
- 账号锁定仍由现有账户安全逻辑负责,安全检测面板不替代账号锁定。
- 图形验证码错误、账号错误、密码错误和角色入口错误分别保存分类,但页面证据统一脱敏。
- 一个入口的登录失败不得清理另一个入口的有效会话。
## 12. 保留与隐私
- 原始检测事件默认在线保留 30 天,聚合告警、封禁记录和操作审计默认保留 180 天;最终期限在上线前由安全和运营确认。
- 清理使用小批量、可恢复任务;不得删除仍关联活动封禁、未完成处置或审计保留期内的数据。
- 页面和导出默认脱敏账号、路径参数、User-Agent 中的可识别信息。
- 第一版不提供原始日志全文导出。
## 13. 可用性与降级
- Fail2ban 不可用:页面显示检测源异常,已有告警仍可查看;相关来源不允许宣称“无攻击”。
- Collector 不可用:健康状态告警并记录事件积压;恢复后按事件键幂等补录。
- Security Agent 不可用:封禁按钮返回明确失败,不修改告警为已封禁。
- PostgreSQL 不可用:不允许执行无法审计的封禁操作。
- 规则应用失败:继续使用上一生效版本,页面显示失败版本与原因。
- Nginx 或 nftables 回读不一致:封禁状态标记异常并产生系统告警。
## 14. 部署前置条件
1.`cmpp-api.service` 改为专用非 root 用户并完成文件、日志、MinIO/local storage 权限回归。
2. 安装 Fail2ban,固定版本并使用 nftables 兼容 action。
3. 为 Nginx、sshd、Gateway 和 NestJS 建立结构化、脱敏且可测试的事件格式。
4. 验证 Cloudflare 可信 IP 网段、`real_ip_header` 和源站绕过防护。
5. 建立 root security agent、Unix Socket 权限、systemd 加固和固定协议。
6. 发布前备份 PostgreSQL、运行源码、环境文件、Fail2ban/Nginx 平台生成配置和 nftables 当前规则。
## 15. 分阶段实施建议
### 阶段 A:检测与只读面板
- 数据模型、默认规则、结构化事件、collector、Fail2ban alert-only jail。
- 总览、告警列表、详情、规则只读展示和健康状态。
- 使用真实日志、真实 PostgreSQL 和真实接口验收。
### 阶段 B:阈值配置
- 规则编辑、版本、后端边界、受控配置编译、校验、原子应用和回滚。
- 配置变更对比、近期认证和审计。
### 阶段 C:人工封禁
- Security Agent、执行器、固定时长封禁、解封、保护名单、幂等和状态对账。
- Cloudflare/Nginx 与直连/nftables 分入口验收。
阶段 A、B、C 可以作为同一第一版需求连续交付,但验收必须逐阶段通过,不能为了展示按钮而跳过权限隔离和真实执行验证。
## 16. 第一版完成标准
- 九类检测全部有真实事件来源、默认规则、可配置阈值和原子测试。
- 自研 UI 通过真实 API 展示面板、告警、规则、封禁和健康数据。
- HTTP 错误密钥、签名错误、重放和恶意扫描均纳入第一版。
- NestJS 非 root,无法执行任意系统命令或编辑 Fail2ban 配置。
- 人工封禁按入口选择正确执行器,Cloudflare 场景不使用无效的访客 IP nftables 封禁。
- 保护名单、重新认证、权限、幂等、并发和操作审计全部通过。
- 只有回读执行器确认真实生效后,页面才显示“已封禁”。
- 不发送短信、不修改通道账号/密码/启停状态、企业余额或客户连接。
@@ -0,0 +1,174 @@
# Fail2ban 安全检测与人工封禁第一版测试用例
> 版本:V1.0(设计评审用例)<br>
> 日期:2026-08-14<br>
> 关联设计:`docs/fail2ban-assisted-blocking-design-20260814.md`<br>
> 原则:真实后端、真实 PostgreSQL、真实日志与真实执行器;禁止 mock、静态数据和 localStorage 作为验收证据
## 1. 测试边界
- 自动化测试使用隔离的 Fail2ban/Nginx/nftables namespace 或测试节点,不得封禁测试执行机、预生产运维 IP、Cloudflare 节点或真实客户 IP。
- 预生产验收优先使用文档保留测试 IP 和短时封禁;所有人工封禁必须先确认回滚路径。
- 不发送、补发或重投短信,不修改通道账号、密码、启停状态、企业余额或客户连接。
- HTTP 密钥、签名、CMPP AuthenticatorSource、账号和日志证据必须脱敏。
## 2. 规则配置
| 编号 | 优先级 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- |
| TC-F2B-RULE-001 | P0 | 查询规则列表 | 返回九类第一版规则;数据来自 PostgreSQL;展示当前配置版本和生效版本 |
| TC-F2B-RULE-002 | P0 | 修改规则阈值、窗口、冷却时间和风险等级并保存 | 写入真实数据库,生成新版本,代理校验并应用成功;回读值一致;写操作日志 |
| TC-F2B-RULE-003 | P0 | 提交小于最小值、大于最大值、零、负数、小数、非数字或非法枚举 | 后端逐项拒绝,不生成规则版本,不依赖前端校验兜底 |
| TC-F2B-RULE-004 | P0 | 两名管理员基于同一旧版本并发保存不同阈值 | 仅一方成功;另一方返回版本冲突,不覆盖新配置 |
| TC-F2B-RULE-005 | P0 | 让新配置语法校验或 reload 失败 | 数据库标记 `apply_failed`;上一生效版本继续工作;页面不得提示已生效 |
| TC-F2B-RULE-006 | P1 | 停用一条规则后持续产生匹配日志 | 停用后不创建新告警;已有告警和历史事件保留 |
| TC-F2B-RULE-007 | P1 | 重新启用规则 | 新事件按当前版本统计,不错误合并停用期间日志 |
| TC-F2B-RULE-008 | P0 | 尝试通过接口提交 regex、日志路径、shell、action、jail 名或执行器 | DTO 不接受或后端拒绝;配置文件和系统命令不受影响 |
| TC-F2B-RULE-009 | P0 | 无 `security.rule.manage` 权限修改规则 | 返回 403,不写数据库、不调用安全代理 |
| TC-F2B-RULE-010 | P0 | 超过近期认证时间后修改规则 | 要求重新认证;重新认证成功后才能保存 |
## 3. 登录与 SSH 检测
| 编号 | 优先级 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- |
| TC-F2B-AUTH-001 | P0 | 同一测试 IP 在窗口内触发达到阈值的运营端密码错误 | 只生成一条聚合告警,计数准确,状态 `pending`,未自动封禁 |
| TC-F2B-AUTH-002 | P0 | 同一测试 IP 在客户端登录达到阈值 | 产生客户端规则告警,不与运营端规则错误合并 |
| TC-F2B-AUTH-003 | P1 | 失败次数低于阈值或分散在窗口外 | 保存检测事件但不产生达到阈值告警 |
| TC-F2B-AUTH-004 | P0 | 同一浏览器已有有效运营会话时,在客户端提交错误登录 | 产生正确检测事件;运营会话不被清除、广播退出或跳转 |
| TC-F2B-AUTH-005 | P0 | 检查事件、告警详情和日志 | 不含明文密码、密码散列、完整账号或验证码答案 |
| TC-F2B-SSH-001 | P0 | 从保留测试 IP 对 12022 触发达到阈值的 SSH 失败 | Fail2ban 检测 jail 产生事件和告警,但 nftables 未自动加入封禁 |
| TC-F2B-SSH-002 | P1 | SSH 登录成功、连接中断或握手超时 | 不错误计入认证失败规则 |
| TC-F2B-SSH-003 | P0 | 重启 Fail2ban/collector 后重放同一事件 | `eventKey` 幂等,不重复增加计数或创建告警 |
## 4. CMPP 检测
| 编号 | 优先级 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- |
| TC-F2B-CMPP-001 | P0 | 同一测试 IP 使用未知账号达到阈值 | 生成 `cmpp_auth_failure` 告警;保存脱敏账号指纹和真实 TCP IP |
| TC-F2B-CMPP-002 | P0 | 使用错误 AuthenticatorSource 达到阈值 | 认证继续按原协议拒绝;告警分类准确;不保存完整 AuthenticatorSource |
| TC-F2B-CMPP-003 | P0 | 从不允许 IP、停用企业或停用应用发起连接 | 原认证结果不变;事件分类可区分真实拒绝原因 |
| TC-F2B-CMPP-004 | P0 | 高频发送非法包、异常版本或短连接扫描 | 达到协议滥用规则阈值后形成告警,不污染普通认证失败统计 |
| TC-F2B-CMPP-005 | P1 | 正常断线、心跳超时、最大连接数限制或服务重启恢复 | 不作为恶意认证或协议滥用告警 |
| TC-F2B-CMPP-006 | P0 | 检查事件和页面证据 | 不包含平台密码、完整认证材料、短信正文或通道凭据 |
## 5. HTTP API 检测
| 编号 | 优先级 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- |
| TC-F2B-HTTP-001 | P0 | 同一 IP 使用不存在的 HTTP API 密钥达到阈值 | 生成 `http_invalid_api_key` 告警;仅保存不可逆密钥指纹 |
| TC-F2B-HTTP-002 | P0 | 使用存在但错误的签名达到阈值 | 生成 `http_signature_failure`,不与错误密钥混淆,不保存签名密钥或完整签名 Header |
| TC-F2B-HTTP-003 | P0 | 分别触发签名缺失、格式错误、算法不支持、验签失败和时间偏差 | 内部原因分类准确;页面使用安全文案;敏感细节不泄露给调用方 |
| TC-F2B-HTTP-004 | P0 | 重复使用已消费 nonce/签名请求达到阈值 | 生成 `http_replay_attempt` 严重告警;原接口仍按既有幂等/重放规则拒绝 |
| TC-F2B-HTTP-005 | P0 | 合法客户端按接口幂等协议重试同一业务请求 | 不误判为恶意重放;响应和业务幂等结果保持原语义 |
| TC-F2B-HTTP-006 | P0 | 请求常见敏感路径和漏洞路径,达到次数及不同路径双阈值 | 生成 `http_malicious_scan`;路径已标准化且 query 敏感值不保存 |
| TC-F2B-HTTP-007 | P0 | 对同一不存在业务路径重复请求,仅满足次数、不满足不同路径数 | 不触发恶意扫描告警 |
| TC-F2B-HTTP-008 | P1 | 产生普通业务 400、字段校验失败、合法 401/403 和单次 404 | 不错误计入恶意扫描或错误密钥规则 |
| TC-F2B-HTTP-009 | P0 | 从两个 IP 分别达到一半阈值 | 不跨 IP 错误聚合;每个 IP 独立计算 |
| TC-F2B-HTTP-010 | P0 | 修改 HTTP 规则阈值后继续产生事件 | 新事件使用新生效版本,告警规则快照可追溯当时阈值 |
## 6. Cloudflare 与真实 IP
| 编号 | 优先级 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- |
| TC-F2B-IP-001 | P0 | 经真实 Cloudflare 回源请求运营端和客户端 | 事件 IP 等于访客真实 IP,TCP 代理 IP 保留在安全元数据中但不作为攻击者 IP |
| TC-F2B-IP-002 | P0 | 直连源站并伪造 `CF-Connecting-IP` | Header 被忽略,事件使用真实 TCP 来源 IP |
| TC-F2B-IP-003 | P0 | 人工封禁 Cloudflare 入口告警 | 使用 Nginx real-IP deny,不调用访客 IP nftables action |
| TC-F2B-IP-004 | P0 | 人工封禁灰云 API、SSH 或 CMPP 告警 | 使用 nftables/manual jail,不修改 Nginx Cloudflare deny 列表 |
| TC-F2B-IP-005 | P0 | 尝试封禁 Cloudflare 官方节点、源站自身、回环、内网、运维和健康检查 IP | 后端和安全代理双重拒绝,记录保护名单命中,不产生真实封禁 |
| TC-F2B-IP-006 | P1 | Cloudflare 官方网段更新 | 使用受控来源更新并审计;旧配置切换原子化;失败保留旧可信网段 |
## 7. 告警聚合与状态机
| 编号 | 优先级 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- |
| TC-F2B-ALERT-001 | P0 | 同规则、IP、窗口内并发写入多条事件 | 唯一 fingerprint 生效,只创建一条告警,计数无丢失 |
| TC-F2B-ALERT-002 | P0 | 冷却时间内再次达到阈值 | 更新原告警计数和最近时间,不产生告警风暴 |
| TC-F2B-ALERT-003 | P1 | 冷却结束后再次达到阈值 | 按设计创建新告警或新周期,历史告警不覆盖 |
| TC-F2B-ALERT-004 | P0 | 对 `pending` 告警执行忽略 | 状态原子变为 `ignored`,保留事件和原因,封禁按钮不可再执行 |
| TC-F2B-ALERT-005 | P0 | 两名管理员同时对同一告警点击封禁和忽略 | 仅一个状态迁移成功,另一请求返回 409 |
| TC-F2B-ALERT-006 | P1 | 告警超过可处置期限 | 状态变为 `expired`;历史仍可查询;不能用旧告警封禁 |
## 8. 人工封禁与解封
| 编号 | 优先级 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- |
| TC-F2B-BLOCK-001 | P0 | 有权限管理员对待处理告警选择1小时、填写原因并确认 | 创建唯一操作记录,代理执行正确执行器,回读成功后状态才为 `blocked` |
| TC-F2B-BLOCK-002 | P0 | 前端篡改 IP、jail、action、执行器或时长 | 后端忽略未定义字段或拒绝请求;实际值只来自告警和固定映射 |
| TC-F2B-BLOCK-003 | P0 | 重复点击、网络超时重试或同一 `operationKey` 重放 | 代理和数据库幂等,仅存在一条真实封禁,不延长原期限 |
| TC-F2B-BLOCK-004 | P0 | 代理返回成功但执行器回读不存在规则 | 不标记 `blocked`;状态为失败/异常并生成系统告警 |
| TC-F2B-BLOCK-005 | P0 | Security Agent 停止或 Socket 不可用 | 明确返回封禁失败;告警不伪装已封禁;记录错误和审计 |
| TC-F2B-BLOCK-006 | P0 | PostgreSQL 不可用时点击封禁 | 拒绝无法审计的操作,不调用代理 |
| TC-F2B-BLOCK-007 | P0 | 无 `security.block.manage` 权限或近期认证过期 | 返回403或要求重新认证,不产生操作记录和系统封禁 |
| TC-F2B-BLOCK-008 | P0 | 对已封禁 IP执行解封并填写原因 | 调用原执行器解除,回读确认后变为 `unblocked`,完整记录操作人和原因 |
| TC-F2B-BLOCK-009 | P0 | 封禁自然到期 | 执行器真实解除;对账任务回读后更新 `expired`,不只依赖数据库时间 |
| TC-F2B-BLOCK-010 | P0 | 到期后执行器仍存在规则或平台记录与执行器不一致 | 标记同步异常并告警,不静默显示已解封 |
| TC-F2B-BLOCK-011 | P1 | 规则配置 `manualBlockAllowed=false` | 告警可查看,封禁按钮禁用,直接调用接口同样拒绝 |
## 9. 保护名单
| 编号 | 优先级 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- |
| TC-F2B-PROTECT-001 | P0 | 查询保护名单 | 返回真实数据库和系统内置项,展示类型、范围和来源 |
| TC-F2B-PROTECT-002 | P0 | 新增合法 IPv4、IPv6 或 CIDR 人工保护项 | 后端规范化、检查重叠并保存;要求权限、重新认证、原因和审计 |
| TC-F2B-PROTECT-003 | P0 | 提交非法、过宽、重复或与系统项冲突的网段 | 后端拒绝,现有保护项不变化 |
| TC-F2B-PROTECT-004 | P0 | 尝试删除系统内置保护项 | 拒绝;只能通过受控发布变更 |
| TC-F2B-PROTECT-005 | P0 | 待处理告警 IP 后续加入保护名单 | 告警更新为 `whitelisted` 或明确标记保护命中,不允许封禁 |
## 10. 自研 UI 与真实数据
| 编号 | 优先级 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- |
| TC-F2B-UI-001 | P0 | 进入“安全控制 / 安全检测” | 页面使用平台自研布局、组件和中文状态,不嵌入第三方 Fail2ban UI |
| TC-F2B-UI-002 | P0 | 对照 SQL/API 检查总览五项指标、趋势、分布和 Top IP | 页面与真实后端结果一致,无 mock、静态或 localStorage 数据 |
| TC-F2B-UI-003 | P0 | 使用 IP、规则、风险、状态、入口和日期组合筛选及分页 | 查询由后端完成;总数、页码、跨页结果准确 |
| TC-F2B-UI-004 | P0 | 打开告警详情 | 显示规则快照、聚合时间线、脱敏证据和处置历史;无密钥或认证材料泄露 |
| TC-F2B-UI-005 | P0 | 打开封禁确认弹窗 | 显示执行器、影响入口、固定时长、保护检查、风险提示和必填原因 |
| TC-F2B-UI-006 | P0 | 规则保存成功、保存但应用失败、版本冲突 | 三种状态分别准确提示;失败不得显示成功 toast |
| TC-F2B-UI-007 | P1 | 1440、1280、1024、768和375宽度验收 | 指标、图表、表格、筛选和弹窗无横向溢出;关键操作可见可用 |
| TC-F2B-UI-008 | P1 | 仅键盘和读屏操作页面 | 表单有 label,错误有关联说明,状态不只依赖颜色,弹窗焦点和按钮名称准确 |
| TC-F2B-UI-009 | P0 | 后端、collector 或 agent 不可用 | 页面显示明确降级和最后成功时间,不用空数据伪装“零攻击” |
## 11. 权限、进程与系统加固
| 编号 | 优先级 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- |
| TC-F2B-SEC-001 | P0 | 检查 `cmpp-api.service` 和运行进程 | NestJS 使用专用非 root 用户;有效 UID/GID 非0 |
| TC-F2B-SEC-002 | P0 | 检查 NestJS capabilities、sudoers、可写目录 | 无通用 sudo、无 `CAP_NET_ADMIN`/`CAP_SYS_ADMIN`;只能写明确业务和日志目录 |
| TC-F2B-SEC-003 | P0 | 以 NestJS 用户尝试读取/写入 `/etc/fail2ban`、运行防火墙命令或访问代理管理文件 | 全部被操作系统权限拒绝 |
| TC-F2B-SEC-004 | P0 | 检查 Security Agent Socket | 只在本机 Unix Socket,权限和用户组符合设计,无 TCP 监听 |
| TC-F2B-SEC-005 | P0 | 向 Agent 提交未知动作、非法 JSON、超长字段、shell 字符和非白名单规则 | 全部拒绝且无命令执行;记录限量安全日志 |
| TC-F2B-SEC-006 | P0 | 检查操作日志 | 规则变更、封禁、解封、忽略、保护名单、失败和回读异常均可追溯 |
| TC-F2B-SEC-007 | P1 | 查看告警详情和完整证据 | 读取动作按设计写访问审计;低权限用户只能看到脱敏数据 |
## 12. 可用性、恢复和数据保留
| 编号 | 优先级 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- |
| TC-F2B-OPS-001 | P0 | 停止 Fail2ban | 健康面板显示对应来源异常;已有告警可查;不得显示“当前无攻击” |
| TC-F2B-OPS-002 | P0 | Collector 暂停后恢复并重放积压 | 事件按幂等键补录,计数准确,无重复告警 |
| TC-F2B-OPS-003 | P0 | 重启 API、Gateway、Fail2ban、collector 和 agent | 已生效规则、活动封禁和告警状态恢复一致,不自动执行新封禁 |
| TC-F2B-OPS-004 | P0 | 发布失败触发回滚 | PostgreSQL、代码、环境、Fail2ban/Nginx生成配置和防火墙规则均有可验证恢复路径 |
| TC-F2B-OPS-005 | P1 | 执行30天事件、180天告警/审计保留任务 | 只删除到期且不受保护数据;活动封禁、未完成处置和审计期数据不删除 |
| TC-F2B-OPS-006 | P1 | 大量扫描事件压测 | Collector 有界处理,API与Gateway业务不被阻塞;告警聚合避免写放大 |
| TC-F2B-OPS-007 | P0 | 对比执行器、数据库和页面 | 当前封禁集合、到期时间和执行器类型一致;差异进入异常状态和告警 |
## 13. 发布验收证据
第一版发布前至少保留:
1. Fail2ban filter 单元样例,包含命中与不命中日志。
2. 九类规则的专项自动化结果。
3. API 权限、参数边界、并发、幂等和审计测试。
4. PostgreSQL migration 状态和表/索引/唯一约束核对。
5. NestJS 非 root、capabilities、sudoers 和文件权限证据。
6. Cloudflare 真实 IP、伪造 Header 和 Nginx 执行器真实验证。
7. 直连 API/SSH/CMPP 的隔离测试 IP nftables 封禁与解封证据。
8. Fail2ban、collector、agent、API、Gateway、Nginx、PostgreSQL 和 Redis 健康证据。
9. 自研 UI 桌面端、平板端和移动端截图以及控制台日志。
10. 发布前 PostgreSQL、运行源码、环境文件、生成配置和防火墙规则恢复资产校验。
## 14. 判定规则
- 任一 P0 失败:第一版不得发布。
- 检测达到阈值但未生成告警、未达到阈值却告警、错误 IP 聚合、密钥泄露、保护地址可被封禁、页面显示封禁而执行器未生效、NestJS 仍为 root或可执行任意系统命令,均按 P0 处理。
- 只验证 Fail2ban 命令输出、只验证前端样式或只写数据库不验证真实执行器,不能作为功能通过。
@@ -2070,3 +2070,11 @@
2. 运营看板删除“今日签名发送统计”和“今日签名发送统计 - 含引流”两个明细模块;“今日活跃签名”指标仍使用当天真实发送聚合。今日消费金额的主数字必须与今日发送总量使用相同字号、字重和深色层级。
3. 企业应用管理列表的状态、到达率、单价列在现有基础上缩窄约20%,提升大屏一次展示完整表格的概率;不得通过隐藏真实字段实现。
4. 移动、联通、电信数据展示统一使用全局`CarrierTag`低饱和标签,包括通道与通道组、监控、报备、签名、短信审核、任务号码、发送记录及客户端发送详情等页面。筛选/表单控件的选项文案、图表图例、导出文本和业务说明仍使用纯文本,避免破坏交互、可访问性和机器可读输出;可取得运营商集合的三网通道按三个运营商标签展示,只有历史通道级字段时使用中性的“三网”标签。
## Fail2ban 安全检测与人工封禁(2026-08-14)
- 运营端“安全控制”新增“安全检测与封禁”自研页面,数据必须来自真实 NestJS API 与 PostgreSQL,包含总览、告警中心、九类规则配置、人工封禁记录和保护名单;不得嵌入第三方面板或使用 Mock、静态数据、localStorage 伪造检测状态。
- 第一版检测运营端登录失败、客户端登录失败、SSH 认证失败、CMPP 认证失败、CMPP 协议滥用、HTTP 错误密钥、HTTP 签名错误、HTTP 重放及 HTTP 恶意扫描。规则阈值、窗口、冷却、风险级别、启停状态与封禁时长边界保存在数据库,并使用配置版本防止并发覆盖。
- 检测只产生事件与人工告警,绝不自动封禁。人工封禁只允许 10 分钟、1 小时、24 小时或 7 天;操作要求近期重新认证、必填原因、保护名单校验、数据库原子认领和操作审计。执行器由服务端按可信入口固定映射,浏览器不得提交 jail、action、shell 参数或自选执行器。
- NestJS 必须以专用非 root 用户运行,不得获得通用 sudo、任意 shell、直接编辑 `/etc/fail2ban/*` 或防火墙的能力。独立 root security agent 只监听本机 Unix Socket、接受固定 JSON 动作、使用参数数组执行固定操作,并在真实 nftables 或 Nginx deny 回读成功后才允许数据库标记 `blocked`
- 运营端/客户端的 Cloudflare 入口使用 Nginx real-IP deny;直连 HTTP API、SSH 与 CMPP 使用 nftables。只有可信代理 TCP 来源可以提供访客 IP;系统回环、私网、链路本地、组播和配置的运维/健康检查网段必须内置保护。
- 规则更新先保存待应用版本,由安全代理生成固定 Fail2ban 配置、执行语法校验并 reload;失败保留上一生效值并展示失败原因,不得显示为已生效。完整架构、状态机、字段、接口和安全边界以 `docs/fail2ban-assisted-blocking-design-20260814.md` 为准。
+16
View File
@@ -93,6 +93,22 @@ git reset --hard origin/main
bash tools/deploy/production-deploy.sh
```
### Fail2ban 安全检测发布前置条件
本功能包含新增 PostgreSQL migration、非 root API 身份、安全代理、Fail2ban、Nginx include 和 nftables 表,不能按普通前端热发布处理。发布前除平台标准 PostgreSQL、运行源码和环境文件恢复资产外,必须额外备份 `/etc/systemd/system/cmpp-api.service*``/etc/systemd/system/cmpp-security-agent.service``/etc/fail2ban``/etc/nginx``/etc/nftables.conf``/etc/nftables.d``/var/lib/cmpp-security-agent`,并逐项生成、复核 SHA-256。
发布脚本会构建 `cmpp-security-agent` 并运行 `tools/security/install-security-agent.sh`。安装器创建专用 `cmpp-api` 用户和 `cmpp-security` 组、写入 systemd 加固 drop-in、安装固定 Fail2ban filter/action、校验 Nginx/Fail2ban/nftables,但不会执行任何人工封禁。环境文件至少明确:
```bash
SECURITY_AGENT_SOCKET=/run/cmpp-security-agent/agent.sock
SECURITY_AGENT_TIMEOUT_MS=3000
SECURITY_EVENT_TOKEN=<至少32字节随机值,仅供Gateway和安全代理上报固定事件>
TRUSTED_PROXY_IPS=127.0.0.1,::1
SECURITY_BUILTIN_PROTECTED_NETWORKS=<运维出口CIDR,健康检查CIDR,源站公网IP>
```
正式 Nginx 的 `sms.lisglo.com` 运营端/客户端 server 块必须 `include /etc/nginx/snippets/cmpp-security-deny.conf;`;API 专用域名继续只开放客户接口。Cloudflare `real_ip_header` 及可信网段必须按官方来源单独维护和验证,禁止信任任意客户端 `CF-Connecting-IP``X-Forwarded-For`。发布后需证明 `cmpp-api` 进程用户不是 root、无 sudo 权限且无法写 `/etc/fail2ban`,安全代理 Socket 不监听 TCP,九类规则版本一致,Fail2ban 为 report-onlynftables/Nginx 回读与数据库状态一致。任何一项失败均不得开放人工封禁按钮。
部署脚本重启 Gateway、API 和 Nginx 后,会分别对 Gateway、API 健康接口执行最多 60 秒的逐秒就绪检查。Nest 初始化、活动通道恢复或生产数据量增加可能使 API 启动超过固定数秒;发布流程不得用单次固定延时把正常慢启动误判为失败。超过 60 秒仍不健康时才终止发布,并结合 systemd journal 和发布前数据库、源码、环境备份判断回滚方式。
## 账号和密钥
+6
View File
@@ -4650,3 +4650,9 @@ npm run verify:phase8
| TC-INFRA-MON-015 | 响应式与无障碍 | 在1536×1024、1280×800和390×844打开页面,操作范围和刷新按钮 | 桌面信息层级符合设计稿;窄屏无内容重叠和页面横向溢出;按钮有可读名称,活动范围和告警严重性不只依赖颜色表达 |
| TC-INFRA-MON-016 | 配置和部署幂等 | 在测试服务器重复执行监控安装脚本和配置校验 | 不重复创建系统用户,不开放公网端口;配置通过`promtool check config/rules`,服务保持activeCMPP API/Gateway不因安装被重启 |
| TC-INFRA-MON-017 | 业务数据隔离 | 运行监控24小时并检查PostgreSQL业务库和指标标签 | 监控时序只保存在Prometheus TSDB,业务PostgreSQL无高频指标写入;标签、日志和API响应不含手机号、短信正文、账号或密钥 |
## Fail2ban 安全检测与人工封禁测试矩阵(2026-08-14)
- 本模块必须执行 `docs/fail2ban-assisted-blocking-test-cases-20260814.md` 中 TC-F2B 全量用例,专项用例是本平台功能测试的组成部分,不是可选附录。
- P0 门禁至少覆盖:九类规则真实 PostgreSQL 默认值与版本冲突、阈值边界、规则应用失败保留旧生效值、登录/HTTP/CMPP/SSH/Nginx 真实事件脱敏、事件键幂等、窗口聚合并发、可信代理 IP、Cloudflare 与直连入口执行器映射、系统和人工保护网段、近期重新认证、重复封禁原子认领、代理超时/失败、真实执行器回读、非 root NestJS 及任意命令/参数注入拒绝。
- 集成验收必须在隔离测试节点或网络 namespace 使用文档保留 IP;不得封禁预生产运维出口、Cloudflare 节点或真实客户 IP。未安装真实 Fail2ban/nftables/Nginx 资产时,只能把相关用例标记阻塞,不得用 Mock 通过代替。
- UI 验收覆盖桌面与窄屏的总览、告警、规则、封禁记录、保护名单、加载、空数据、失败和规则未生效状态;所有数字与操作结果必须能从 API、数据库、agent 与执行器证据交叉验证。
+9
View File
@@ -3582,3 +3582,12 @@ git diff --check
- 专项Jest 1套/4项、API全量38套/467项通过,覆盖范围白名单、Prometheus HTTP响应契约解析、固定60秒step、服务别名、活动告警、不可用无陈旧数据及监控地址安全约束;全量Jest仍因仓库既有异步句柄使用`--forceExit`收尾。API正式TypeScript、前端TypeScript、Vite 8.1.5生产构建、两个Shell脚本语法及`git diff --check`通过;Vite仅保留既有约2.10MB单chunk提示。
- 浏览器优先检查现有页面:本地运营端无有效登录Session,被正常引导到带算术验证码的登录页;未绕过登录、未读取或填写验证码,因此登录后桌面与窄屏视觉验收尚未完成。真实Prometheus/Node Exporter集成和告警触发验收必须在明确授权安装的测试或预生产窗口执行,当前不以单测替代真实基础设施验收。
- 本轮代码、配置和文档保持未提交、未推送、未部署,没有发送、补发或重投短信,没有修改通道账号、密码、启停状态、企业余额、客户连接或预生产数据。既有构建缓存、`outputs/`和空文件`=`继续保护;并行会话新增的Fail2ban设计与测试文档不属于本需求,不修改、不归因。
# 2026-08-14 Fail2ban 安全检测与人工封禁第一版(本地实现完成、未发布)
- 新增真实 PostgreSQL 安全规则、事件、告警、封禁和保护网段模型及第88条 migration `20260814150000_add_security_detection`;九类默认规则覆盖运营端/客户端登录、SSH、CMPP认证与协议滥用、HTTP错误密钥/签名/重放和Nginx恶意扫描。应用事件按事件键幂等并使用PostgreSQL advisory transaction lock串行聚合;Fail2ban命中作为其自身窗口已达到阈值的聚合事件处理,不会再要求重复达到第二层阈值。
- 运营端新增“安全控制 / 安全检测与封禁”自研页面,使用真实API展示总览、告警、规则、封禁记录和保护名单;规则修改、封禁、解封、忽略和保护名单写操作要求近期重新认证。封禁时长为固定枚举,执行器由服务端按入口映射,浏览器不能传jail、action、shell或执行器参数;系统私网/回环等内置保护和人工CIDR保护在调用代理前拦截。
- 新增独立Go `cmpp-security-agent`、Unix Socket固定协议、report-only Fail2ban action/filter、Nginx real-IP deny、nftables timeout set和systemd加固。NestJS部署身份改为专用非root `cmpp-api`,安全事件入口新增独立内部令牌;agent不使用shell拼接,规则/Nginx配置校验或reload失败会恢复旧文件,只有真实执行器回读命中后数据库才标记`blocked`
- 登录、OpenAPI鉴权和Gateway已接入结构化安全事件;错误HTTP密钥只保存不可逆账号指纹,证据字段统一过滤password/secret/token/signature/access-key。反向代理地址只在TCP来源属于`TRUSTED_PROXY_IPS`时信任`X-Forwarded-For`,避免客户端伪造来源IP。
- Prisma schema validate、API与前端TypeScript、API全量40套/472项、Fail2ban专项和Gateway控制器3套/11项、Gateway全量`go test ./...`、Vite 8.1.5生产构建、3个Shell脚本语法和`git diff --check`通过;Vite仅有既有约2.11MiB单chunk提示,全量Jest仍使用`--forceExit`收尾既有异步句柄。
- 浏览器优先接管本地路由,`/admin/security-detection`在无有效Session时正确跳转运营端登录并保留返回地址,控制台error/warn为0;未读取、重置或猜测账号,登录后页面视觉与交互验收尚未完成。真实Fail2ban、Nginx、nftables、Unix Socket和第88条migration未在本机数据库或预生产安装/执行,必须在具备恢复资产和文档保留测试IP的授权发布窗口完成,当前不以Mock替代集成验收。
- 本轮未发送、补发或重投短信,未修改通道账号、密码、启停状态、企业余额、客户连接或预生产数据;`api/tsconfig.build.tsbuildinfo``tsconfig.tsbuildinfo``outputs/`和空文件`=`继续作为受保护项排除提交。