rfxn/brute-force-detection

GitHub: rfxn/brute-force-detection

一款基于指数衰减压力评分模型的 Linux 暴力破解检测与自动封禁工具,通过解析服务日志区分人为失误与自动化攻击,实现精准的 IP 封禁和多层告警。

Stars: 26 | Forks: 12

# 暴力破解检测 (BFD)

Brute Force Detection (BFD)

CI Version License: GPL v2 Shell Platform

基于日志的暴力破解检测和针对 Linux 服务器的自动 IP 封禁。 基于压力的评分机制允许人类犯错,同时能彻底阻止机器人 — 57 条服务规则,8 个防火墙后端,IPv4/IPv6,GeoIP 丰富化, 多渠道告警,以及具有约 10 秒检测延迟的持续监控模式。 *版权所有 (C) 1999-2026 [R-fx Networks](https://www.rfxn.com) · Ryan MacDonald · [GPL v2](COPYING.GPL)* ## 2.0.2 版本更新内容 - **CDN/受信代理子系统** — 针对提供商的 IP 段数据库,支持 ignore/exclude/derate(忽略/排除/降权)处理模式,`bfd --cdn` CLI,自动 cron.daily 刷新 - **结构化审计事件** — 12 种新增审计事件类型,涵盖封禁升级、告警发送、检测触发和扫描生命周期 - **定期威胁报告** — 通过所有告警渠道按日/周/月定时发送报告,并附带趋势对比 - **Pressure 配置迁移** — `pressure.conf` 和 `pressure-country.conf` 迁移至空格分隔格式,并兼容旧版双格式解析 - **多渠道告警修复** — 按渠道分发防止了 Slack/Telegram/Discord 之间的交叉污染 ## 目录 - [1. 介绍](#1-introduction) - [1.1 支持的系统](#11-supported-systems) - [2. 安装](#2-installation) - [2.1 调度](#21-scheduling) - [2.2 升级](#22-upgrading) - [3. 配置](#3-configuration) - [3.1 压力模型 (检测)](#31-pressure-model-detection) - [3.2 邮件告警](#32-email-alerts) - [3.3 封禁](#33-banning) - [3.4 累犯处理](#34-repeat-offender-handling) - [3.5 IPv6](#35-ipv6) - [3.6 日志路径](#36-log-paths) - [3.7 高级](#37-advanced) - [3.8 国家/地区权重](#38-country-weighting) - [3.9 SMTP 中继](#39-smtp-relay) - [3.10 邮件模板](#310-email-templates) - [3.11 Slack 告警](#311-slack-alerts) - [3.12 Telegram 告警](#312-telegram-alerts) - [3.13 Discord 告警](#313-discord-alerts) - [4. 使用方法](#4-usage) - [4.1 Dry Run (试运行)](#41-dry-run) - [4.2 健康检查](#42-health-check) - [4.3 威胁活动](#43-threat-activity) - [4.4 Watch 模式 (监控模式)](#44-watch-mode) - [4.5 清除封禁](#45-flush-bans) - [4.6 结构化输出](#46-structured-output) - [4.7 扫描模式](#47-scan-mode) - [4.8 事件与调查](#48-events-and-investigation) - [4.9 退出码](#49-exit-codes) - [5. 防火墙](#5-firewall) - [6. 规则引擎](#6-rule-engine) - [6.1 规则目录](#61-rule-catalog) - [6.2 规则自定义](#62-rule-customization) - [7. 忽略列表](#7-ignore-lists) - [8. CDN / 受信代理](#8-cdn--trusted-proxy) - [8.1 配置](#81-configuration) - [8.2 提供商配置](#82-provider-configuration) - [8.3 处理模式](#83-treatment-modes) - [8.4 CLI 命令](#84-cli-commands) - [8.5 自动更新](#85-automatic-updates) - [8.6 添加自定义提供商](#86-adding-custom-providers) - [9. 定期报告](#9-periodic-reports) - [10. 封禁管理](#10-ban-management) - [11. IPv6](#11-ipv6) - [集成](#integration) - [故障排除](#troubleshooting) - [许可证](#license) - [支持](#support) ## 快速开始 ``` # 安装(以 root 身份) ./install.sh # 配置 — 设置你的防火墙 ban 命令 vi /usr/local/bfd/conf.bfd # 验证 — watch 模式应当正在运行(由安装程序自动启用) systemctl status bfd-watch # systemd bfd -c # health check # Dry run — 检测而不进行 ban bfd -d # 带输出运行 bfd -s # 查看主要攻击者和 ban 状态 bfd -a # 管理 ban bfd -l # list active bans bfd -b 192.0.2.1 sshd # manually ban an IP bfd -u 192.0.2.1 # unban an IP ``` ## 1. 介绍 Brute Force Detection (BFD) 是一个模块化的 shell 脚本,用于解析应用程序日志并检测身份验证失败。它内置了 57 条服务规则,涵盖 SSH、邮件、FTP、Web、数据库、控制面板、DNS、VPN、VoIP、代理和消息服务。每条规则都声明了兼容 fail2ban 的 `` 正则表达式模式;引擎负责处理日志读取、IP 提取、IPv6 规范化和验证。 传统的基于计数的工具会在固定的失败次数时进行封禁——这迫使运维人员在快速捕获攻击者或容忍合法失误之间做出选择——与此不同,BFD 使用 **指数衰减压力评分**。每次失败都会按服务严重程度增加权重不等的压力,并且压力会通过可配置的半衰期随时间衰减。一个在几分钟内多次输错密码的用户,其产生的压力会自然消退,远低于触发阈值。而不断猛烈攻击同一服务的机器人,其产生压力的速度会超过衰减速度,几乎立即触发阈值。这样既能减少对真实用户的误判,又能对实际攻击做出更快的响应。 BFD 使用日志跟踪系统,因此日志只会从上次读取的位置开始解析。这极大地提高了性能,因为我们不必持续读取相同的日志数据。日志跟踪系统兼容 syslog/logrotate 风格的日志轮转——它能在轮转发生时进行检测,并从新日志文件和已轮转的日志文件中获取最新数据。 **检测** - 57 条带有兼容 fail2ban 的 `` 正则表达式模式的服务规则 - 指数衰减压力评分——人为的输入错误会逐渐消退,机器人的攻击会立即触发 - 按服务划分的严重性权重(SSH=3,控制面板=5,嘈杂的服务=1) - 按规则和全局跨服务的压力触发阈值 - 可选的基于国家/地区的压力倍数 - 具有轮转感知的增量日志解析 **封禁** - 带有自动过期和防火墙规则清理的临时封禁 - 累犯升级(线性、倍增或有上限的增长) - 8 个带有自动检测功能的防火墙后端(APF, CSF, firewalld, UFW, nftables, iptables, route, custom) - 具有完整状态跟踪的手动 ban/unban CLI **IPv4/IPv6** - 双栈检测和封禁,无需修改规则 - 为需要独立处理 IPv6 的防火墙 (ip6tables) 提供单独的 IPv6 封禁命令 - 自动排除两个地址系列的本地地址 **运维** - 用于无损诊断的健康检查模式 (`bfd -c`) - 用于在不封禁的情况下测试规则的 Dry-run 模式 (`bfd -d`) - 用于详细的按规则和按封禁输出的 Verbose 模式 (`bfd --verbose`) - 威胁活动报告,包含摘要、双间隔服务明细和封禁状态 (`bfd -a`) - 每次运行的统计日志记录(检查的规则、解析的事件、执行的封禁) - 批量邮件告警,包含丰富的上下文(封禁类型、持续时间、历史记录)和按规则的路由 - 手册页 (`man bfd`) 和 bash tab 补全会自动安装 ### 1.1 支持的系统 BFD 可以在任何带有 bash 4.1+ 和标准 GNU 实用程序 的 Linux 发行版上运行。它已在以下系统上经过测试和支持: **RHEL 系列:** - CentOS 6, 7 - Rocky Linux 8, 9, 10 **Debian 系列:** - Ubuntu 20.04, 24.04 (CI 测试);14.04 (通过 12.04 目标进行深度传统 CI 测试) - Debian 12 日志路径在运行时自动检测: - RHEL: `/var/log/secure`, `/var/log/messages`, `/var/log/maillog` - Debian/Ubuntu: `/var/log/auth.log`, `/var/log/syslog`, `/var/log/mail.log` BFD 需要 root 权限。除了基本系统之外,不需要任何额外的依赖。 ## 2. 安装 包含的 `install.sh` 脚本会处理所有的安装任务: ``` ./install.sh ``` 这将: - 将 BFD 安装到 `/usr/local/bfd` - 将 `bfd` 命令放置在 `/usr/local/sbin/bfd` - 自动启用 watch 模式,以实现约 10 秒的检测延迟(systemd 或 SysVinit) - 安装一个 2 分钟的 cronjob 作为后备(在 watch 模式运行时跳过) - 如果是升级,则从之前的安装中导入设置并重启 watch 模式 覆盖前会备份以前的安装。 - **安装路径:** `/usr/local/bfd` - **可执行文件路径:** `/usr/local/sbin/bfd` 通过环境变量自定义安装路径: ``` INSTALL_PATH=/opt/bfd BIN_PATH=/usr/sbin/bfd ./install.sh ``` ### 2.1 调度 **Watch 模式 (推荐):** BFD 的 watch 模式作为持久化守护进程运行,每隔 `WATCH_INTERVAL` 秒(默认为 10 秒)轮询一次新的日志数据。检测延迟约为 10 秒,与 fail2ban 及其他基于守护进程的工具相当。 安装程序会在全新安装时自动启用并启动 watch 模式。 在升级时,现有的调度选择会被保留——如果 watch 模式之前正在 运行,它将被重启;如果启用了 `bfd.timer`,它将保持活动状态。 要手动管理 watch 模式: ``` # systemd (Rocky 8+, Debian 12, Ubuntu 20+) systemctl enable --now bfd-watch.service # SysVinit (CentOS 6/7, Ubuntu 14.04) service bfd-watch start chkconfig bfd-watch on # enable at boot (RHEL) ``` **Cron (自动后备):** 安装程序会在 `/etc/cron.d/bfd` 中放置一个 cronjob,在静默模式下每 2 分钟运行一次 BFD。这作为后备手段——当 watch 模式处于活动状态时,cron 运行会检测到锁并静默跳过。如果 watch 守护进程退出,cron 会在 2 分钟内自动恢复检测。 使用 watch 模式时无需移除 cron 条目。 ### 2.2 升级 从以前的 BFD 安装(包括 v1.5-2)升级时,`install.sh` 会自动: - 将现有安装备份到 `/usr/local/bfd.bk.DDMMYYYY-EPOCH`(符号链接为 `/usr/local/bfd.bk.last` 以便访问) - 运行 `importconf` 来合并您的配置并保留状态 **importconf 自动迁移的内容:** | 类别 | 详情 | |----------|---------| | 用户配置 | `conf.bfd` 的值合并到新模板上 | | 旧版变量名 | `TRIG` → `PRESSURE_TRIP`, `TRIG_WINDOW` → `PRESSURE_HALF_LIFE`, `TRIG_GLOBAL` → `PRESSURE_TRIP_GLOBAL`, `BAN_DURATION` → `BAN_TTL`, `BAN_PERMANENT_*` → `BAN_ESCALATE_*` | | 按规则覆盖 | 从之前的安装中保留 `pressure.conf`;旧的冒号格式自动转换为空格格式 | | 防火墙后端 | 如果检测到 2.0.1 之前版本的 `BAN_COMMAND`,则设置为 `"custom"` | | 封禁状态 | `bans.active`, `bans.history`, `pressure.dat` | | 日志跟踪状态 | tlog 字节偏移量,journal 游标 | | 告警模板 | `alert/` partials(保留用户修改过的部分),旧版 `alert.bfd` | | 忽略列表 | `ignore.hosts` | **升级后验证:** ``` bfd -c # health check and diagnostics bfd --status # show current ban/event summary ``` **回滚:** 如果升级导致问题,请从备份中恢复: ``` bfd --flush-all # clear any new bans rm -rf /usr/local/bfd cp -a /usr/local/bfd.bk.last /usr/local/bfd ``` ## 3. 配置 主配置文件是 `/usr/local/bfd/conf.bfd`。文件中每个选项的正上方都有描述性注释。首次运行前,请从头到尾查看该文件。 使用 `bfd -c` 可以验证您的配置而不会封禁任何内容。 ### 3.1 压力模型 (检测) BFD 使用指数衰减压力评分:每次失败的登录都会根据服务严重性增加不同权重的压力,并且压力会通过半衰期随时间衰减。当累积的压力超过触发阈值时,就会触发封禁。这可以自然地将人为失误与自动化攻击区分开来——几分钟内的几次输入错误会无害地衰减消失,而来自机器人的快速连续失败积累的速度远快于其衰减的速度。 ``` pressure = SUM { weight * 2^(-(now - event_time) / half_life) } ``` **示例** (SSH 规则:=3, trip=15, half-life=300s): - **Bot 攻击** — 1 秒内失败 7 次: pressure = 3×7 = 21.0 → 超过 15 → **封禁** - **人为输入错误** — 4 分钟内失败 5 次: 早期的事件会衰减,总计 ≈ 11.1 → 低于 15 → **不封禁** | 变量 | 默认值 | 描述 | |----------|---------|-------------| | `PRESSURE_TRIP` | `20` | 触发封禁所需的累积压力;按规则覆盖可在规则文件或 `pressure.conf` 中进行 | | `PRESSURE_HALF_LIFE` | `300` | 半衰期,以秒为单位(压力衰减的速度);越短 = 越宽容 | 按规则的权重在 `pressure.conf`(集中配置)或各个规则文件中通过 `PRESSURE_WEIGHT` 进行配置。权重越高 = 压力积累越快。默认级别:5(控制面板),3(SSH/VPN/数据库/关键服务),2(邮件/FTP/Web),1(嘈杂/通用服务)。 `pressure.conf` 使用以空格分隔的 `key=value` 格式: ``` sshd weight=3 trip=20 postfix weight=2 trip=20 skip_alert=1 ``` ### 3.2 邮件告警 | 变量 | 默认值 | 描述 | |----------|---------|-------------| | `EMAIL_ALERTS` | `0` | 发送邮件告警 (0 = 关闭, 1 = 开启) | | `EMAIL_ADDRESS` | `root` | 告警接收者,以逗号分隔 | | `EMAIL_SUBJECT` | `Brute Force Warning for $HOSTNAME` | 主题行 (批量发送时自动附加 `(N bans)`) | | `EMAIL_LOGLINES` | `5` | 告警正文和事件视图中每个主机的日志行数 | | `EMAIL_FORMAT` | `text` | 邮件正文格式: `text` (纯文本), `html` (仅 HTML), `both` (多部分 text+HTML) | | `EMAIL_DIGEST` | `cycle` | 摘要模式: `cycle` (每次运行发送一封邮件), `timed` (按间隔积累并发送) | | `EMAIL_DIGEST_INTERVAL` | `900` | 当 `EMAIL_DIGEST="timed"` 时的摘要刷新间隔(以秒为单位,默认 15 分钟) | | `EMAIL_REPUTATION_LINKS` | *(空)* | 告警中的 IP 信誉链接,以逗号分隔: `abuseipdb`, `shodan`, `virustotal`, `ipinfo`, `greynoise` | 告警是 **批量处理** 的:一个检查周期内的多个封禁会为每个收件人生成一封邮件,而不是每次封禁生成一封。每个告警包含主机、服务、带有阈值的压力分、带有持续时间和过期时间的封禁类型(临时/永久/升级)、国家/地区代码、累犯历史、IP 信誉链接、压力可视化条以及源日志行。 **摘要模式**:在 `cycle` 模式(默认)下,每次检测运行结束时发送一封邮件。在 `timed` 模式下,告警会在多次运行中积累,并在 `EMAIL_DIGEST_INTERVAL` 到期时刷新——这减少了活跃服务器上的邮件量。Watch 模式在每次迭代时检查假脱机队列;Cron 模式则在每次运行时检查。积累的告警会在关机和每日轮换时强制刷新。 **格式选项**:`text` 通过 `mail` 发送纯文本。`html` 通过 `sendmail` 发送 HTML。`both` 通过 `sendmail` 发送包含纯文本和 HTML 两部分的多部分 MIME 消息,以便收件人的电子邮件客户端显示其偏好的格式。如果 `sendmail` 不可用,`html` 和 `both` 将回退为通过 `mail` 仅发送纯文本。 邮件模板是可自定义的——参见 [第 3.10 节](#310-email-templates)。单个规则可以通过在规则文件中设置 `SKIP_ALERT="1"` 来抑制告警。在规则文件中设置 `RULE_EMAIL="addr"` 可以将该规则的告警路由到不同的收件人。 ### 3.3 封禁 | 变量 | 默认值 | 描述 | |----------|---------|-------------| | `FIREWALL` | `auto` | 防火墙后端;参见 [第 5 节](#5-firewall) | | `BAN_TTL` | `600` | 封禁持续时间,以秒为单位(0 = 永久)。临时封禁会自动过期 | | `BAN_COMMAND` | APF deny | 当 `FIREWALL="custom"` 时执行的命令。参见 [第 5 节](#5-firewall) | | `UNBAN_COMMAND` | APF unban | 反向操作命令。临时封禁自动过期所必需 | 在 ban/unban 命令中可以使用变量 `$ATTACK_HOST`、`$MOD`(服务名称)和 `$PORTS`(来自规则文件)。 ### 3.4 累犯处理 这四个设置形成了一个管道:`BAN_ESCALATION` 控制封禁持续时间如何增长,`BAN_ESCALATION_CAP` 限制该增长,`BAN_ESCALATE_AFTER` 在达到计数后翻转为永久封禁,而 `BAN_ESCALATE_WINDOW` 是上述所有设定的回溯窗口。 | 变量 | 默认值 | 描述 | |----------|---------|-------------| | `BAN_ESCALATION` | `none` | 持续时间增长方式: `none` (固定), `linear` (10m, 20m, 30m...), `double` (10m, 20m, 40m, 80m...) | | `BAN_ESCALATION_CAP` | `86400` | 最大升级持续时间,以秒为单位 (0 = 无上限) | | `BAN_ESCALATE_AFTER` | `5` | 翻转为永久封禁前的临时封禁次数 (0 = 从不) | | `BAN_ESCALATE_WINDOW` | `86400` | 用于计算重复违规的回溯窗口,以秒为单位 | **示例** (当 `BAN_TTL="600"` 时): - **固定 10m 封禁,第 5 次后永久:** `ESCALATION=none`, `ESCALATE_AFTER=5` → 10m, 10m, 10m, 10m, 10m → 永久 - **倍增封禁,第 5 次后永久:** `ESCALATION=double`, `ESCALATE_AFTER=5` → 10m, 20m, 40m, 80m, 160m → 永久 - **线性增长,有上限,永远不永久:** `ESCALATION=linear`, `CAP=3600`, `ESCALATE_AFTER=0` → 10m, 20m, 30m... 1h, 1h, 1h (始终临时) ### 3.5 IPv6 | 变量 | 默认值 | 描述 | |----------|---------|-------------| | `BAN_COMMAND_V6` | *(空)* | 特定于 IPv6 的封禁命令。当为空时,`BAN_COMMAND` 将用于这两种地址系列 | | `UNBAN_COMMAND_V6` | *(空)* | 特定于 IPv6 的解封命令。当为空时,`UNBAN_COMMAND` 将用于这两种 | 当使用原生处理双协议的工具(带有 `inet` family 的 nft, APF, ip route)时,请保留为空。对于需要独立的 IPv4/IPv6 命令的工具 (iptables/ip6tables),请显式设置。参见 [IPv6](#11-ipv6)。 ### 3.6 日志路径 | 变量 | 默认值 | 描述 | |----------|---------|-------------| | `AUTH_LOG_PATH` | `/var/log/secure` | 认证日志 (自动检测:Debian 上为 `/var/log/auth.log`) | | `KERNEL_LOG_PATH` | `/var/log/messages` | 内核/syslog (自动检测:Debian 上为 `/var/log/syslog`) | | `MAIL_LOG_PATH` | `/var/log/maillog` | 邮件日志 (自动检测:Debian 上为 `/var/log/mail.log`) | | `BFD_LOG_PATH` | `/var/log/bfd/bfd.log` | BFD 自身的应用程序日志 | 日志路径会根据发行版自动检测。如果您的系统使用非标准路径,请在 `conf.bfd` 中覆盖。 ### 3.7 高级 | 变量 | 默认值 | 描述 | |----------|---------|-------------| | `PRESSURE_TRIP_GLOBAL` | `0` | 跨服务聚合压力触发阈值 (0 = 禁用) | | `SUBNET_TRIG` | `0` | 从同一子网触发子网封禁的唯一 IP 数 (0 = 禁用) | | `SUBNET_MASK` | `24` | 用于分布式检测的 IPv4 子网掩码 | | `SUBNET_MASK_V6` | `48` | IPv6 子网掩码 (必须是 16 的倍数) | | `WATCH_INTERVAL` | `10` | Watch 模式的轮询间隔,以秒为单位 | | `SCAN_MAX_LINES` | `50000` | 扫描模式下每个日志的最大行数;0 = 无限制 | | `SCAN_TIMEOUT` | `120` | 扫描期间每个规则的 Journal 超时时间,以秒为单位 | | `OUTPUT_SYSLOG` | `1` | 记录到 syslog (0 = 关闭, 1 = 开启) | | `LOG_IDLE_SUPPRESS` | `1` | 抑制来自 syslog 的空闲 (0 事件) 运行完成消息 (0 = 关闭, 1 = 开启) | | `LOG_FORMAT` | `classic` | 日志格式: `classic` (syslog 样式) 或 `json` (JSONL) | | `LOG_LEVEL` | `1` | 最低严重性: 0=debug, 1=info, 2=warn, 3=error | | `APOOL_RETENTION_DAYS` | `365` | 攻击池条目的最大保留天数 | | `APOOL_MAX_LINES` | `500000` | 攻击池文件中的最大行数 | 附加变量(`LOG_SOURCE`、`LOCK_FILE_TIMEOUT`、`BAN_RETRY_COUNT`、`OUTPUT_SYSLOG_FILE`)在 `internals.conf` 中具有合理的默认值,可以通过将它们添加到 `conf.bfd` 来覆盖。 **JSON 日志格式**:当 `LOG_FORMAT="json"` 时,每条日志行都是一个 JSON 对象,包含的字段有:`ts` (ISO 8601)、`host`、`app`、`pid` (integer)、`level` (debug/info/warn/error/critical)、`tag` (服务名称,如果存在则从 `{tag}` 前缀中提取)、`msg`。示例: ``` {"ts":"2026-02-27T14:30:00+0000","host":"srv1","app":"bfd","pid":1234,"level":"info","tag":"sshd","msg":"192.0.2.1 exceeded login failures"} ``` ### 3.8 国家/地区权重 当 `pressure-country.conf` 包含未注释的条目时,国家/地区权重会自动激活。无需切换——如果文件有条目,就会应用它们;如果所有条目都被注释掉(默认),国家/地区权重就会关闭。 国家/地区数据库将 IP 地址映射到 2 个字母的国家/地区代码。IPv4 范围存储在 `ipcountry.dat`(整数范围格式)中,IPv6 范围存储在 `ipcountry6.dat`(十六进制范围格式)中。两者都在安装时(后台)自动下载,并在数据超过 30 天时通过 `cron.daily` 刷新。可以使用 `update-ipcountry.sh` 手动更新,该脚本会从 ipverse.net(备用 ipdeny.com)下载按国家/地区的 CIDR 区域,并将它们转换为 BFD 的查找格式。IPv4 和 IPv6 地址都会被解析为国家/地区代码。 倍数文件(`pressure-country.conf`)使用以空格分隔的 `CC N` 格式,其中 N 是 weight×10(例如,`CN 20` 表示 2.0× 权重,`US 10` 表示 1.0× = 无变化)。未列出的国家/地区默认为 1.0×。为了向后兼容,也接受旧版的 `CC=N` 格式。 ### 3.9 SMTP 中继 默认情况下,BFD 通过本地 MTA (`mail` 或 `sendmail`) 发送告警。对于没有本地 MTA 的服务器或通过外部邮件服务路由的服务,BFD 支持通过 `curl` 进行经过身份验证的 SMTP 中继。 | 变量 | 默认值 | 描述 | |----------|---------|-------------| | `SMTP_RELAY` | *(空)* | SMTP 中继服务器 URL (空 = 使用本地 MTA) | | `SMTP_FROM` | *(空)* | 发件人地址 (设置 `SMTP_RELAY` 时必需) | | `SMTP_USER` *(空)* | SMTP 认证用户名 | | `SMTP_PASS` | *(空)* | SMTP 认证密码 | **URL 格式:** | 格式 | 示例 | 描述 | |--------|---------|-------------| | `smtps://host:465` | `smtps://smtp.gmail.com:465` | 隐式 TLS (Gmail 等) | | `smtp://host:587` | `smtp://relay.example.com:587` | STARTTLS (大多数中继服务) | | `smtp://host:25` | `smtp://relay.internal:25` | Plain (内部中继) | **示例 — Gmail SMTP 中继:** ``` SMTP_RELAY="smtps://smtp.gmail.com:465" SMTP_FROM="alerts@example.com" SMTP_USER="alerts@example.com" SMTP_PASS="app-password-here" ``` 所有目标发行版上都存在 `curl`,并且原生处理 TLS/认证。凭据存储在 `conf.bfd` 中(权限 640,属于 root)。使用 `bfd -c` 验证中继配置。 ### 3.10 邮件模板 告警邮件是从 BFD 安装路径(`/usr/local/bfd/alert/`)下的 `alert/` 目录中可自定义的模板片段渲染而来的。模板使用 `{{VAR}}` mustache 风格的占位符,在渲染时通过基于安全的 awk 引擎进行替换——没有执行 shell 代码,因此模板不会引入安全风险。 **模板文件:** | 文件 | 描述 | |------|-------------| | `text.header.tpl` | 文本: 横幅,主机名,时间戳 | | `text.entry.tpl` | 文本: 每次封禁的详细信息块 | | `text.summary.tpl` | 文本: 摘要统计信息 | | `text.footer.tpl` | 文本: 版本,项目链接 | | `html.header.tpl` | HTML: 横幅和主机名栏 | | `html.entry.tpl` | HTML: 带有压力详情的每次封禁卡片 | | `html.summary.tpl` | HTML: 聚合统计表格 | | `html.footer.tpl` | HTML: 页脚和结束标签 | 条目模板在每个封禁渲染一次。摘要模板仅当一封邮件中批量处理多个封禁时才会包含。页眉和页脚包裹整个消息。 要进行自定义,请将所需的片段复制到 `alert/custom.d/` 中并编辑副本。BFD 会首先为每个片段检查 `custom.d/`,如果不存在则回退到自带的默认设置。`custom.d/` 中的模板在升级时会自动保留。 **关键模板变量:** | 变量 | 示例 | 描述 | |----------|---------|-------------| | `{{HOSTNAME}}` | `web01.example.com` | 系统主机名 | | `{{HOST}}` | `192.0.2.1` | 被封禁的 IP 地址 | | `{{SERVICE}}` | `sshd` | 服务名称 | | `{{PRESSURE}}` | `21.4` | 压力分 | | `{{FAIL_COUNT_DISPLAY}}` | `7` | 此周期检测到的登录失败尝试次数 | | `{{BAN_TYPE}}` | `Temporary` | 封禁类型 (Temporary/Permanent/Escalated) | | `{{BAN_DURATION_DETAIL}}` | `10m` | 人类可读的持续时间 | | `{{COUNTRY_FLAG}}` | `CN` | 2 个字母的国家/地区代码 | | `{{COUNTRY_DISPLAY}}` | `China (CN)` | 带有代码的国家/地区名称(降级为仅显示代码) | | `{{SOURCE_LOGS_SECTION_TEXT}}` | *(日志行)* | 经过清理的源日志摘录 | | `{{REPUTATION_SECTION_TEXT}}` | `AbuseIPDB: https://...` | 文本格式的信誉链接 | 有关完整的变量参考,请参见附带的模板文件。 消息渠道(Slack, Telegram, Discord)拥有它们自己的模板片段: | 文件 | 描述 | |------|-------------| | `slack.message.tpl` | Slack Block Kit JSON 包装器 | | `slack.entry.tpl` | Slack 每次封禁的部分 | | `telegram.message.tpl` | Telegram MarkdownV2 包装器 | | `telegram.entry.tpl` | Telegram 每次封禁的块 | | `discord.message.tpl` | Discord embed JSON 包装器 | | `discord.entry.tpl` | Discord 每次封禁的 embed 字段 | 定期报告(参见 [第 9 节](#9-periodic-reports)) 使用它们自己的模板片段: | 文件 | 描述 | |------|-------------| | `report.html.header.tpl` | HTML 报告页眉和样式 | | `report.html.body.tpl` | HTML 报告正文和表格 | | `report.text.header.tpl` | 纯文本报告页眉 | | `report.text.body.tpl` | 纯文本报告正文 | | `report.slack.message.tpl` | Slack 报告摘要 | | `report.telegram.message.tpl` | Telegram 报告摘要 | | `report.discord.message.tpl` | Discord 报告摘要 | ### 3.11 Slack 告警 BFD 可以通过传入 Webhooks 或 Bot API 向 Slack 频道发送告警通知。 | 变量 | 默认值 | 描述 | |----------|---------|-------------| | `SLACK_ALERTS` | `0` | 启用 Slack 告警 (`1` = 启用) | | `SLACK_MODE` | `webhook` | 投递模式: `webhook` 或 `bot` | | `SLACK_WEBHOOK_URL` | *(空)* | 传入 Webhook URL (webhook 模式) | | `SLACK_TOKEN` | *(空)* | Bot API token, `xoxb-...` (bot 模式) | | `SLACK_CHANNEL` | *(空)* | 频道 ID 或 `#name` (bot 模式) | **Webhook 模式** 更简单——在 [Slack Incoming Webhooks](https://api.slack.com/messaging/webhooks) 创建一个 Webhook 并粘贴 URL 即可。**Bot 模式** 支持文件上传并使用 [Slack Web API](https://api.slack.com/methods/chat.postMessage)。 要求 PATH 中包含 `curl`。使用 `bfd --test-alert slack` 进行测试。 ### 3.12 Telegram 告警 BFD 可以通过 Telegram Bot API 发送告警通知。 | 变量 | 默认值 | 描述 | |----------|---------|-------------| | `TELEGRAM_ALERTS` | `0` | 启用 Telegram 告警 (`1` = 启用) | | `TELEGRAM_BOT_TOKEN` | *(空)* | 来自 [@BotFather](https://t.me/BotFather) 的 Bot Token | | `TELEGRAM_CHAT_ID` | *(空)* | 聊天、群组或频道 ID | 使用 `@userinfobot` 或 `getUpdates` API 端点查找您的聊天 ID。消息使用 MarkdownV2 格式发送。 要求 PATH 中包含 `curl`。使用 `bfd --test-alert telegram` 进行测试。 ### 3.13 Discord 告警 BFD 可以通过 Webhooks 向 Discord 频道发送告警通知。 | 变量 | 默认值 | 描述 | |----------|---------|-------------| | `DISCORD_ALERTS` | `0` | 启用 Discord 告警 (`1` = 启用) | | `DISCORD_WEBHOOK_URL` | *(空)* | 来自 服务器设置 > 整合 的 Webhook URL | 告警渲染为 Discord embeds,包含每次封禁的字段和摘要页脚。 要求 PATH 中包含 `curl`。使用 `bfd --test-alert discord` 进行测试。 ## 4. 使用方法 `/usr/local/sbin/bfd` 命令提供以下选项: ``` usage: bfd [OPTION] Run Modes: -s, --standard run detection cycle with output -q, --quiet run detection cycle silently -d, --dryrun run detection without banning -w, --watch run continuous watch mode (foreground) Ban Management: -b, --ban IP [SERVICE] manually ban an IP (permanent) -u, --unban IP unban an IP address --flush-temp remove all temporary bans --flush-all remove all bans Reporting: Supports: --json --csv -l, --list list active bans -a, --activity [IP|STR] threat activity and IP investigation -e, --events [IP|CIDR] [N] event history, IP or subnet detail (N=log lines) System: -S, --status [SERVICE] operational status overview -C, --config [VAR] show active configuration -R, --rules [RULE] list rules or show rule detail (--active) -c, --check health check diagnostics Testing: -T, --test RULE [FILE|-] test rule patterns against log or stdin --test-pattern PAT [FILE|-] test raw pattern against log or stdin --test-alert TYPE send test alert (email,slack,telegram,discord) Scan Mode: --scan [RULE] [-d] full-log scan (all rules or specific rule) --max-lines=N max lines per log during scan (default 50000) --scan-timeout=N journal timeout per rule during scan (default 120) Output Modifiers: --json JSON output (with -l, -e, -a) --csv CSV output (with -l, -e, -a) --sort=MODE sort events: count (default), time, ip --limit=N max IPs to display (default 100, 0=all) --24h events from last 24 hours (default) --7d events from last 7 days --30d events from last 30 days --active show only active rules (with -R) -V, --verbose detailed output (with -s, -d, -c, -S, --scan) General: -v, --version display version -h, --help display this help (see bfd.1 for full docs) ``` **`-s|--standard`** 和 **`-q|--quiet`** 选项运行完整的检测和封禁周期。标准模式打印输出;静默模式抑制输出(由 cron 使用)。两者都会解析日志,根据触发阈值计算压力,并执行封禁。 ### 4.1 Dry Run (试运行) **`-d|--dryrun`** 选项运行完整的检测,但只记录“将要封禁”而不是执行封禁命令。使用此选项可以安全地测试规则,验证您的配置,并查看 BFD 会执行什么操作而不会影响生产环境。 ``` bfd -d ``` ### 4.2 健康检查 **`-c|--check`** 选项对您的整个 BFD 安装执行无损诊断检查: - 验证配置(必需变量,合理的值) - 检查日志文件路径是否存在且可读 - 验证封禁命令二进制文件是否存在且可执行 - 当 `BAN_TTL > 0` 时,如果 `UNBAN_COMMAND` 为空则发出警告 - 如果配置了 `BAN_COMMAND_V6`,则检查其二进制文件 - 扫描所有规则:报告活动与非活动状态、压力权重/触发阈值、端口、日志路径 - 显示压力模型摘要(半衰期,触发阈值,全局触发阈值) - 验证 tlog(日志跟踪脚本)是否可执行 - 检查状态目录是否存在且权限正确 - 报告锁文件状态 - 计算活动封禁数 ``` bfd -c ``` 输出使用 `[PASS]`、`[WARN]`、`[FAIL]` 和 `[SKIP]`(非活动规则)指示符,并附带最终摘要。 ### 4.3 威胁活动 **`-a|--activity`** 选项显示带有聚合摘要、热门威胁 IP 和按服务细分的威胁活动报告: ``` bfd -a # show threat activity report bfd --activity # same as above bfd -a 192.0.2 # search for a specific string ``` 报告包括: - **威胁活动摘要** — 24 小时和 7 天时间窗口内的唯一 IP 数和总计数,以及活动封禁数 - **Top 25 威胁 IP (24h)** — 事件计数,IP,压力,国家/地区,首次/最后一次出现时间,服务,封禁状态(活动封禁显示 `BANNED(perm)` 或 `BANNED(Xm)`,以前的封禁显示 `prev:N`) - **Top 25 威胁 IP (7d)** — 相同格式,7 天时间窗口 - **按服务划分的威胁明细 (24h / 7d)** — 双间隔计数,唯一 IP,以及每个服务的热门国家/地区 ### 4.4 Watch 模式 **`-w|--watch`** 选项将 BFD 作为连续守护进程运行,每隔 `WATCH_INTERVAL` 秒(默认为 10 秒)轮询一次新的日志数据。这是 **推荐的操作模式**——检测延迟约为 10 秒,与 fail2ban 及其他基于守护进程的工具相当。 ``` bfd --watch ``` Watch 模式在其整个生命周期内持有一个锁,因此当 watch 模式处于活动状态时,基于 cron 的运行 (`bfd -q`) 将静默跳过。如果 watch 守护进程意外退出(OOM,崩溃),cron 会自动检测到失效的 PID 并在一个周期内(约 2 分钟)恢复检测。无需修改 cron。 **信号处理:** | 信号 | 动作 | |--------|--------| | `SIGTERM` / `SIGINT` | 干净关闭(移除锁文件) | | `SIGHUP` | 无需重启即可重新加载 `conf.bfd`、`internals.conf` 和 `pressure.conf`(允许更改 `WATCH_INTERVAL`、`PRESSURE_TRIP`、封禁命令等) | **服务管理:** ``` # systemd (Rocky 8+, Debian 12, Ubuntu 20+) systemctl enable --now bfd-watch.service systemctl reload bfd-watch # send SIGHUP systemctl status bfd-watch ``` 这与 `bfd.timer` 冲突——systemd 阻止同时启用两者。 ``` # SysVinit (CentOS 6/7, Ubuntu 14.04) service bfd-watch start service bfd-watch reload # send SIGHUP service bfd-watch status chkconfig bfd-watch on # enable at boot (RHEL) ``` **配置:** | 变量 | 默认值 | 描述 | |----------|---------|-------------| | `WATCH_INTERVAL` | `10` | Watch 模式的轮询间隔,以秒为单位 | ### 4.5 清除封禁 一次性移除多个封禁: ``` bfd --flush-temp # remove all temporary bans (keep permanent) bfd --flush-all # remove all bans (temporary + permanent) ``` 被清除的封禁会记录在封禁历史中。 ### 4.6 结构化输出 将 `--json` 或 `--csv` 与 `-l`、`-e` 或 `-a` 结合使用,以获取机器可读的输出: ``` bfd -l --json # active bans as JSON bfd -l --csv # active bans as CSV bfd -e --json # active events as JSON bfd -e 192.0.2.1 --csv # per-IP events as CSV bfd -a --json # threat activity as JSON bfd -a 192.0.2.1 --csv # IP report as CSV ``` **JSON** 输出对象数组(或用于 IP 详情和 CIDR 的嵌套对象): ``` [{"ip": "...", "pressure": 18.4, "pressure_trip": 20, "events": 5, "services": ["sshd"], ...}] ``` **CSV** 输出带有标题行: ``` ip,pressure,pressure_trip,events,services,first_seen,last_seen,status ``` 结构化输出中的时间戳使用 ISO 8601 格式 (`YYYY-MM-DDTHH:MM:SS`)。 JSON 中的压力值是无引号的数字。 ### 4.7 扫描模式 扫描模式通过检测管道处理**完整的当前日志文件**,绕过增量的 tlog 读取器。这适用于: - **首次安装:** 立即捕获现有的攻击者,而不是等待新的日志事件。 - **规则更改:** 将新规则追溯应用于现有日志数据。 - **恢复:** 在检测空白期(守护进程停机,cron 禁用)后处理遗漏的事件。 - **取证审查:** 结合 `-d` (dry-run) 使用,查看在不封禁的情况下能检测到什么。 ``` bfd --scan # scan all active rules against full logs bfd --scan sshd # scan a specific rule only bfd --scan -d # dry-run: detect without banning or advancing cursors bfd --scan --max-lines=100000 # override line limit bfd --scan --scan-timeout=60 # override journal timeout ``` 在非 dry-run 的扫描之后,tlog 游会前进到当前日志位置,以便下一次常规运行全新开始。在 dry-run 模式下,游标不会被修改。 **安全限制:** `SCAN_MAX_LINES`(默认 50000)限制了每个日志文件处理的行数。`SCAN_TIMEOUT`(默认 120 秒)限制了 journal 读取的时间。设置 `--max-lines=0` 可实现无限制(在处理大型日志时需谨慎)。两者均可在 `conf.bfd` 中配置或在命令行上覆盖。 **锁行为:** 扫描获取与常规运行相同的全局锁。如果 watch 模式正在运行,请先停止它 (`systemctl stop bfd-watch`),运行扫描,然后再重新启动。 ### 4.8 事件与调查 `--events` 命令提供事件历史记录和 IP 调查,从记录了所有检测到的认证失败(包括触发封禁的和低于触发阈值的观察)的攻击池读取,并具有可配置的保留期(默认:365 天): ``` bfd --events # event list — top 100 IPs, last 24h bfd --events --7d --sort=time # last 7 days, newest first bfd --events --limit=0 --30d # all IPs from last 30 days bfd --events 192.0.2.1 # IP investigation — history + pressure + logs bfd --events 192.0.2.0/24 # CIDR report — subnet-scoped view ``` **事件列表**(无参数)显示具有失败次数、服务、国家/地区、首次/最后一次出现时间和封禁状态的 IP。默认:按计数降序排列的前 100 个 IP,24 小时时间窗口。使用 `--limit=N` 更改输出上限(`0` 表示无限制),使用 `--sort=time` 或 `--sort=ip` 更改排序,使用 `--7d` 或 `--30d` 扩大时间窗口。 **IP 调查** 显示一份综合报告:来自攻击池的历史失败计数(总计和按服务细分)、如果 IP 具有活动压力的实时压力详情,以及来自触发服务的日志样本。 **CIDR 模式** 过滤到子网(IPv4,掩码 8-32),并包含带有匹配计数、事件总数和封禁计数的汇总行。 所有三种模式都支持 `--json` 和 `--csv`: ``` bfd --events --json # event list as JSON array bfd --events 192.0.2.1 --json # IP detail as single JSON object bfd --events 10.0.0.0/8 --csv # CIDR as CSV ``` ### 4.9 退出码 | 代码 | 含义 | |------|---------| | 0 | 成功 | | 1 | 配置错误(无效配置,未知选项) | | 2 | 锁错误(另一个实例正在运行) | | 3 | 先决条件错误(缺少 tlog,规则目录) | *权威参考请参见 `man bfd`(1) §EXIT CODES。* ## 5. 防火墙 BFD 支持通过 `FIREWALL="auto"`(默认)进行自动防火墙检测。当设置为 auto 时,BFD 会按优先级顺序探测已安装的防火墙:APF > CSF > firewalld > UFW > nftables > iptables > ip route。 | `FIREWALL` 值 | 描述 | |------------------|-------------| | `auto` | 自动检测 (默认) | | `apf` | Advanced Policy Firewall | | `csf` | ConfigServer Security & Firewall | | `firewalld` | firewalld rich rules | | `ufw` | Uncomplicated Firewall | | `nftables` | nftables sets (inet bfd table) | | `iptables` | iptables/ip6tables chains | | `route` | ip route blackhole | | `custom` | 用户自定义的 BAN_COMMAND/UNBAN_COMMAND | 当配置了 `FIREWALL="auto"` 或指定的后端时,BFD 会原生处理 ban/unban——`BAN_COMMAND` 和 `UNBAN_COMMAND` 仅在 `FIREWALL="custom"` 时使用。 以下示例适用于 `FIREWALL="custom"` 模式。变量 `$ATTACK_HOST` 会在封禁时替换为违规 IP 地址。对于临时封禁,还需将 `UNBAN_COMMAND` 设置为反向操作。 **APF:** ``` BAN_COMMAND="/etc/apf/apf -d $ATTACK_HOST {bfd.$MOD}" UNBAN_COMMAND="/etc/apf/apf -u $ATTACK_HOST" ``` **iptables (CentOS 6/7, Ubuntu 14-20):** ``` BAN_COMMAND="/sbin/iptables -I INPUT -s $ATTACK_HOST -j DROP" UNBAN_COMMAND="/sbin/iptables -D INPUT -s $ATTACK_HOST -j DROP" ``` **firewalld (Rocky 8+, CentOS 7):** ``` BAN_COMMAND="/usr/bin/firewall-cmd --add-rich-rule='rule family=ipv4 source address=$ATTACK_HOST drop'" UNBAN_COMMAND="/usr/bin/firewall-cmd --remove-rich-rule='rule family=ipv4 source address=$ATTACK_HOST drop'" ``` **nftables (Rocky 9+, Debian 12, Ubuntu 22+):** ``` BAN_COMMAND="/usr/sbin/nft add rule inet filter input ip saddr $ATTACK_HOST drop" UNBAN_COMMAND="/usr/sbin/nft delete rule inet filter input handle $(/usr/sbin/nft -a list chain inet filter input | grep $ATTACK_HOST | awk '{print $NF}')" ``` **ip route null-route (所有发行版):** ``` BAN_COMMAND="/sbin/ip route add blackhole $ATTACK_HOST/32" UNBAN_COMMAND="/sbin/ip route del blackhole $ATTACK_HOST/32" ``` **特定端口阻止 (使用规则文件中的 `$PORTS`):** ``` BAN_COMMAND="/sbin/iptables -I INPUT -s $ATTACK_HOST -p tcp -m multiport --dports $PORTS -j DROP" UNBAN_COMMAND="/sbin/iptables -D INPUT -s $ATTACK_HOST -p tcp -m multiport --dports $PORTS -j DROP" ``` **IPv6 防火墙命令** — 如果您的防火墙需要针对 IPv6 使用单独的命令,请设置 `BAN_COMMAND_V6`(对于处理双协议的工具,请保留为空): ``` BAN_COMMAND_V6="/sbin/ip6tables -I INPUT -s $ATTACK_HOST -j DROP" UNBAN_COMMAND_V6="/sbin/ip6tables -D INPUT -s $ATTACK_HOST -j DROP" ``` ## 6. 规则引擎 规则位于 `/usr/local/bfd/rules/`。每条规则都是一个 shell 片段,它声明了服务名称、必需的二进制文件、日志路径以及用于匹配身份验证失败的正则表达式模式。 每条规则会根据特定应用程序二进制文件 (`PREREQ`) 的存在而自动启用。例如,如果 `/usr/sbin/sshd` 存在,sshd 规则就会激活。无需手动激活——安装应用程序后,BFD 就会检测到它。 使用 `bfd -c` 可以查看您的系统上哪些规则处于活动状态。 ### 6.1 规则目录 BFD 附带 57 条规则: | 类别 | 规则 | |----------|-------| | **SSH** | sshd, dropbear | | **Mail** | dovecot, courier, postfix, postscreen, sendmail, exim_authfail, exim_nxuser, vpopmail, cyrus-imap, sogo | | **FTP** | vsftpd, vsftpd2, proftpd, pure-ftpd | | **Web** | apache-auth, nginx-http-auth, mod_sec, wordpress, roundcube, http_401, lighttpd, phpmyadmin, gitea, nextcloud, vaultwarden, drupal, jellyfin | | **Panel** | cpanel, plesk, webmin, directadmin, interworx, cockpit, gitlab, grafana, proxmox, guacamole | | **Auth** | pam_generic, xrdp | | **Database** | mysqld-auth, postgresql, mongodb | | **DNS** | named, powerdns | | **VPN** | openvpnas, openvpn | | **VoIP** | asterisk_badauth, asterisk_iax, asterisk_nopeer, freeswitch | | **Proxy** | haproxy, squid | | **Messaging** | ejabberd | | **Legacy** | rh_imapd, rh_ipop3d | ### 6.2 规则自定义 每个规则文件支持以下变量: | 变量 | 描述 | |----------|-------------| | `PREREQ` | 必需的二进制文件或文件的路径。仅当此文件存在时规则才处于活动状态 | | `LOG_FILE` | 要监控的日志文件路径(使用配置变量如 `$AUTH_LOG_PATH`) | | `MATCHED_HOSTS` | 提取的 IP 列表 — 使用 `` 模式的 tlog + extract_hosts 管道 | | `PRESSURE_WEIGHT` | 按服务的压力权重(覆盖 `pressure.conf`;越高 = 积累越快) | | `PRESSURE_TRIP` | 按服务的触发阈值(覆盖 `pressure.conf` 和全局 `PRESSURE_TRIP`) | | `PORTS` | 用于特定端口阻止的服务端口(例如,sshd 为 `"22"`) | | `SKIP_ALERT` | 设置为 `"1"` 以抑制此服务的电子邮件告警 | | `RULE_EMAIL` | 覆盖此规则告警的 `EMAIL_ADDRESS`(按规则路由) | | `LOG_TAG` | 用于 tlog 状态文件命名和 journal 过滤器分发的跟踪标签(例如,`"sshd"`,`"dovecot"`) | | `IGNOREREGEX` | 匹配此 ERE 模式的行将在 IP 提取之前被排除(兼容 fail2ban) | 要自定义规则的压力权重和触发阈值: ``` # 在 /usr/local/bfd/rules/sshd 中 — 使 SSH 失败计数增至三倍 PRESSURE_WEIGHT="3" PRESSURE_TRIP="15" ``` 集中式的按规则覆盖(无需编辑规则文件)放在 `/usr/local/bfd/pressure.conf` 中(以空格分隔的 `key=value` 格式;语法参见 [压力模型](#31-pressure-model-detection))。 ## 7. 忽略列表 BFD 提供了两种机制来将地址排除在封禁之外: - **`/usr/local/bfd/ignore.hosts`** — 永不封禁的 IP,每行一个。支持 IPv4 和 IPv6 地址。 - **`/usr/local/bfd/exclude.files`** — 包含要忽略的 IP 的附加文件。每行一个文件路径;每个引用的文件都包含要排除的 IP。 BFD 会自动检测本地 IPv4 和 IPv6 地址(包括 `::1`)并将它们排除在封禁之外。本地地址排除无需手动配置。 ## 8. CDN / 受信代理 当 BFD 监控位于 CDN 或反向代理(例如,Cloudflare,AWS CloudFront)后面的服务时,日志可能包含代理的 IP 而不是真实的客户端 IP。如果不了解 CDN IP 范围,BFD 可能会封禁 CDN 基础设施——从而阻止所有代理的流量。 CDN 子系统会自动获取提供商的 IP 范围,并在检测期间应用按提供商设定的处理方式。 ### 8.1 配置 CDN 默认会自动检测——只需在 `cdn-providers.conf` 中取消注释提供商即可。 要强制开启/关闭,请在 `conf.bfd` 中设置: ``` CDN_ENABLE="auto" # auto-detect from cdn-providers.conf (default) CDN_ENABLE="1" # force on regardless of provider config CDN_ENABLE="0" # force off CDN_UPDATE_DAYS="7" # refresh interval (days); 0 = manual only ``` ### 8.2 提供商配置 编辑 `cdn-providers.conf` 以启用提供商。以空格分隔的格式: ``` # 名称 处理方式 乘数 格式 URL_V4 URL_V6 cloudflare ignore 10 text https://www.cloudflare.com/ips-v4/ https://www.cloudflare.com/ips-v6/ aws-cloudfront derate 3 json https://d7uri8nf7uskq.cloudfront.net/tools/list-cloudfront-ips - fastly exclude 10 json https://api.fastly.com/public-ip-list - ``` 字段: - **NAME**: 提供商标识符 (字母数字 + 连字符) - **TREATMENT**: `ignore` (完全不可见), `exclude` (可见但从不封禁), `derate` (降低压力) - **MULT**: 压力倍数 (10=1.0x, 5=0.5x, 3=0.3x) — 仅适用于 `derate` - **FORMAT**: `text` (每行一个 CIDR) 或 `json` (自动提取 CIDRs) - **URL_V4/URL_V6**: 提供商 IP 范围 URL (`-` 表示无) ### 8.3 处理模式 | 模式 | 检测 | 事件 | 压力 | 封禁 | |------|-----------|--------|----------|-----| | `ignore` | 跳过 | 无 | 无 | 否 | | `exclude` | 已处理 | 已记录 (`cdn-exclude`) | 已积累 | 否 | | `derate` | 已处理 | 已记录 | 通过 MULT 减少 | 是 (如果达到阈值) | ### 8.4 CLI 命令 ``` bfd --cdn # list all providers with status bfd --cdn cloudflare # show CIDRs for a provider bfd --cdn update # force refresh all provider ranges bfd --cdn check 172.70.34.1 # check if an IP matches a CDN range bfd --cdn --json # JSON output ``` ### 8.5 自动更新 `cron.daily` 会根据 `CDN_UPDATE_DAYS` 检查 CDN 数据库的期限,并在过期时刷新。手动刷新:`bfd --cdn update` 或直接运行 `update-cdn-providers.sh`。 ### 8.6 添加自定义提供商 向 `cdn-providers.conf` 中添加一行,包含任何以纯文本 CIDRs 或 JSON 发布 IP 范围的提供商: ``` my-proxy derate 5 text https://example.com/ip-ranges.txt - ``` ## 9. 定期报告 BFD 可以生成通过所有配置的告警渠道(电子邮件,Slack,Telegram,Discord)发送的定时威胁报告: ``` bfd --report # daily report (default) bfd --report weekly # last 7 days bfd --report monthly # last 30 days ``` 报告包括: - **威胁摘要:** 唯一 IP 数,事件总数,封禁数,活动封禁数 - **热门威胁 IP** 包含国家/地区代码,实时压力和封禁状态 - **按服务细分** 包含事件计数和热门国家/地区 - **趋势对比** 与之前等效的时间窗口相比 **定时发送** 在 `conf.bfd` 中配置: | 变量 | 默认值 | 描述 | |----------|---------|-------------| | `REPORT_ENABLED` | `0` | 启用定期报告 (0 = 关闭, 1 = 开启) | | `REPORT_INTERVALS` | `"daily"` | 以逗号分隔的间隔: `daily`, `weekly`, `monthly` | | `REPORT_CHANNELS` | *(空)* | 投递渠道 (空 = 所有已启用的告警渠道) | | `REPORT_EMAIL_ADDRESS` | *(空)* | 报告电子邮件收件人 (空 = `EMAIL_ADDRESS`) | | `REPORT_EMAIL_SUBJECT` | *(模板)* | 电子邮件主题 (`{{INTERVAL}}` 和 `{{HOSTNAME}}` 在发送时展开) | | `REPORT_TOP_N` | `25` | 报告表格中的最大 IP 数 | 当 `REPORT_ENABLED=1` 时,`cron.daily` 会每天触发日报,在周一触发周报,在 1 号触发月报。也可以随时从 CLI 按需生成报告。 ## 10. 封禁管理 封禁可以是临时的(在 `BAN_TTL` 秒后自动过期)或永久的(`BAN_TTL=0`)。临时封禁需要设置 `UNBAN_COMMAND`,以便在过期时自动移除防火墙规则。 在 `B_ESCALATE_WINDOW` 秒内发生 `BAN_ESCALATE_AFTER` 次临时封禁的累犯将被升级为永久封禁。 **CLI 命令:** ``` bfd -l # list all active bans (service, ports, expiry) bfd -u 192.0.2.1 # unban an IP address bfd -b 192.0.2.1 # manually ban an IP permanently bfd -b 192.0.2.1 sshd # manually ban with a service label ``` **状态文件** 位于 `/usr/local/bfd/tmp/`: | 文件 | 描述 | |------|-------------| | `bans.active` | 当前活动的封禁 (时间戳,过期时间,IP,服务,端口) | | `bans.history` | 所有 ban/unban 事件的追加式日志 | | `pressure.dat` | 压力评分工作区 (时间戳,IP,服务,权重);每约 10 个半衰期修剪一次 | **状态文件** 位于 `/usr/local/bfd/stats/`: | 文件 | 描述 | |------|-------------| | `attack.pool` | 统一事件存储 — 所有检测到的认证失败(封禁,升级,观察)及结果 | `bfd -a` (威胁活动) 和 `bfd -e` (事件) 都从攻击池读取。低于触发阈值的观察 (ACTION=observed) 会与封禁决定一起记录,以便事件历史记录在压力衰减周期中持续存在。每个 IP 都会显示其当前是否被封禁、其封禁类型(永久或剩余时间)以及历史封禁次数。 ## 11. IPv6 BFD 自动检测并封禁 IPv4 和 IPv6 地址。规则无需修改——提取引擎可以处理这两种地址系列。IPv6 地址在计数和比较之前会进行规范化。 对于原生处理双协议的防火墙(带有 `inet` family 的 nft,APF,ip route),请将 `BAN_COMMAND_V6` 保留为空——所有地址将使用 `BAN_COMMAND`。 对于需要单独命令的防火墙,请设置 `BAN_COMMAND_V6` 和 `UNBAN_COMMAND_V6`: ``` BAN_COMMAND_V6="/sbin/ip6tables -I INPUT -s $ATTACK_HOST -j DROP" UNBAN_COMMAND_V6="/sbin/ip6tables -D INPUT -s $ATTACK_HOST -j DROP" ``` 本地 IPv6 地址(包括 `::1` 和所有链路本地地址)会被自动检测并排除在封禁之外。 ## 集成 BFD 通过标准接口与现有基础设施集成。 **防火墙后端** — 从 8 个后端(APF, CSF, firewalld, UFW, nftables, iptables, route, custom)自动检测或由用户选择。参见 [防火墙](#5-firewall)。 **日志系统** — 通过 tlog 从 syslog 文件或 systemd journal 读取。轮转感知:检测 logrotate 并从当前文件和已轮转文件中获取尾部数据。 **告警渠道** — 电子邮件(本地 MTA 或 SMTP 中继),Slack(webhook 或 Bot API),Telegram(Bot API),Discord(webhooks)。所有渠道都支持批量摘要发送和可自定义的模板。 **结构化输出** — 在 `-l`、`-e` 和 `-a` 后附加 `--json` 和 `--csv`,以供 SIEM、日志聚合器或自动化管道消费。 **CDN 感知** — 带有可配置处理方式(ignore, exclude, derate)的按提供商 IP 范围数据库可防止封禁 CDN 基础设施。参见 [CDN / 受信代理](#8-cdn--trusted-proxy)。 **调度** — Watch 模式(systemd/SysVinit 守护进程,约 10 秒延迟)或 Cron(2 分钟后备)。两者通过锁协调安全共存。 ## 故障排除 首先运行 `bfd -c`——它会在单次无损检查中验证配置、日志路径、防火墙二进制文件、规则状态、状态目录和活动封禁。 | 症状 | 原因与修复 | |---------|-------------| | "locked subsystem, already running?" | 上一次 BFD 运行仍处于活动状态或已被杀死。锁会在 300 秒后自动清除 | | "BAN_COMMAND binary not found" | 配置的防火墙工具未安装。在 `conf.bfd` 中更新 `BAN_COMMAND` | | 规则未触发 | 检查日志路径是否存在,以及应用程序是否正在写入预期的文件。使用 `bfd -d` 在不封禁的情况下测试检测。使用 `bfd -c` 查看哪些规则处于活动状态 | | Debian/Ubuntu 上的日志路径错误 | 日志路径是自动检测的,但可以在 `conf.bfd` 中覆盖:`AUTH_LOG_PATH`, `MAIL_LOG_PATH`, `KERNEL_LOG_PATH` | | "UNBAN_COMMAND is empty" | 在 `conf.bfd` 中设置 `UNBAN_COMMAND` 以便临时封禁在过期时自动移除防火墙规则 | | IPv6 地址未被检测到 | IPv6 支持是自动的。如果使用 ip6tables,请在 `conf.bfd` 中设置 `BAN_COMMAND_V6` | ## 许可证 BFD 由 Ryan MacDonald [ryan@rfxn.com] 以志愿者形式开发和提供支持。 BFD (Brute Force Detection) 在 GNU 通用公共许可证 (GPL) 下分发,对使用或再分发没有限制。BFD 版权声明和 GNU GPL "COPYING.GPL" 包含在发行版的顶级目录中。衍生作品必须按照 GNU GPL 的要求注明出处。 ## 支持 BFD 源代码仓库位于:https://github.com/rfxn/brute-force-detection 错误、功能请求和一般问题可以作为 GitHub issues 提交,或发送至 proj@rfxn.com。报告问题时,请附上 `bfd -c` 的输出以帮助诊断配置问题。 官方项目页面位于:https://www.rfxn.com/projects/brute-force-detection/
标签:Bot检测, CDN代理, Cutter, Elastic, GeoIP, IPv4/IPv6, IP封禁, Linux服务器, PB级数据处理, 免杀技术, 入侵防御, 压力评分, 告警系统, 威胁情报, 安全运维, 审计日志, 封禁升级, 应用安全, 开发者工具, 暴力破解检测, 红队行动, 网络安全, 自动化防御, 趋势报告, 防火墙后端, 隐私保护