Files
lislgosms/docs/fail2ban-assisted-blocking-design-20260814.md
T

19 KiB
Raw Blame History

Fail2ban 安全检测与人工封禁平台设计方案

版本:V1.0(需求评审稿)
日期:2026-08-14
范围:运营端自研 UI、安全检测、阈值配置、告警处置、人工封禁与解封
边界:第一版不自动封禁、不开放任意 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-clientsystemctl 或防火墙命令。
  • 自动将外部威胁情报加入封禁。
  • 删除原始告警和处置历史。

3. 总体架构

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 协议:blockunblockstatusapply_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
  • 聚合维度,只能从规则预置集合选择,例如 ipip+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

  • idcode(唯一)、namecategorydescription
  • enabledwindowSecondsthresholddistinctTargetThreshold
  • cooldownSecondsseveritygroupingMode
  • manualBlockAlloweddefaultBlockDurationSecondsmaxBlockDurationSeconds
  • configVersioneffectiveVersionapplyStatuslastApplyError
  • updatedByIdcreatedAtupdatedAt

6.2 SecurityDetectionEvent

  • ideventKey(唯一幂等键)、ruleCodesourceType
  • sourceIpaccountFingerprinttargetFingerprintrequestPathNormalized
  • occurredAtreceivedAtevidenceSummarymetadata
  • collectorInstanceIdruleVersion

metadata 使用后端安全 DTO,仅保存允许字段;禁止保存密钥和完整认证材料。

6.3 SecurityAlert

  • idalertNofingerprintruleIdruleSnapshot
  • sourceIpstatusseverity
  • firstOccurredAtlastOccurredAteventCountdistinctTargetCount
  • cooldownUntilassignedToIdhandledByIdhandledAthandleReason
  • blockIdcreatedAtupdatedAt

同一规则、IP、聚合维度和窗口桶使用唯一 fingerprint,重复采集只增加计数,不重复创建告警。

6.4 SecurityBlock

  • idoperationKey(唯一)、alertIdsourceIp
  • executorTypeexecutorTargetdurationSeconds
  • statusrequested/applying/blocked/unblock_requested/unblocked/expired/failed
  • startedAtexpiresAtverifiedAterrorMessage
  • requestedByIdrequestReasonunblockedByIdunblockReason
  • agentOperationIdcreatedAtupdatedAt

6.5 SecurityProtectedNetwork

  • IP/CIDR、名称、类型、适用入口、启停状态、来源和备注。
  • 系统内置保护项不可从页面删除,只允许通过受控发布更新。
  • 人工保护项新增、修改和停用均要求重新认证和审计。

7. 状态机与并发控制

7.1 告警状态

pending ──→ block_requested ──→ blocked ──→ unblocked
   │               └──────────→ block_failed
   ├──→ ignored
   ├──→ whitelisted
   └──→ expired
  • pending 仅表示达到检测阈值,绝不代表已被防火墙封禁。
  • 封禁按钮通过数据库条件更新原子认领,只有一名操作人能进入 block_requested
  • 代理执行成功后必须回读执行器状态,确认存在真实规则才写 blocked
  • 网络超时导致结果不确定时先查询 operationKey,不得盲目重复封禁。
  • 忽略、保护名单和封禁互斥;状态变化后旧页面操作返回 409。

7.2 封禁到期

  • 执行器负责真实到期解除;平台定时回读并同步 expired
  • 平台任务只做状态对账,不能仅靠数据库时间把记录标记为已解封。
  • 对账发现执行器缺失、额外规则或到期未解除时生成系统告警。

8. 后端接口

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 封禁。
  • 保护名单、重新认证、权限、幂等、并发和操作审计全部通过。
  • 只有回读执行器确认真实生效后,页面才显示“已封禁”。
  • 不发送短信、不修改通道账号/密码/启停状态、企业余额或客户连接。