L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Productivité · SKILL.md

detecting-port-scanning-with-fail2ban

detecting-port-scanning-with-fail2ban

使用自定义过滤器和动作配置 Fail2ban,检测端口扫描活动、SSH 暴力破解尝试和网络侦察,自动封禁攻击 IP 并向安全团队告警可疑的网络探测行为。

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: detecting-port-scanning-with-fail2ban description: > 使用自定义过滤器和动作配置 Fail2ban,检测端口扫描活动、SSH 暴力破解尝试和网络侦察,自动封禁攻击 IP 并向安全团队告警可疑的网络探测行为。 domain: cybersecurity subdomain: network-security tags: [network-security, fail2ban, port-scanning, intrusion-prevention, automated-defense] version: "1.0" author: mahipal license: Apache-2.0

使用 Fail2ban 检测端口扫描

适用场景

  • 自动封禁对互联网暴露服务器执行端口扫描的 IP 地址
  • 通过自动 IP 封禁防御 SSH、HTTP、FTP 及其他服务的暴力破解攻击
  • 为日志文件中组织特定的攻击模式创建自定义检测过滤器
  • 在流量到达 IDS/IPS 进行深度分析之前,减少自动扫描机器人产生的噪声
  • 在网络监控的基础上增加基于主机的自动响应,实现纵深防御

不适用场景:作为唯一的网络安全控制;防御来自大量源 IP 的分布式攻击;替代正确的防火墙规则和网络分段。

前置条件

  • 已安装 Fail2ban 0.11+(fail2ban-client --version)
  • 用于 iptables/nftables 操作的 root/sudo 访问权限
  • 服务将连接尝试记录到可解析的日志文件(syslog、auth.log、access.log)
  • 安装并运行 iptables 或 nftables 作为主机防火墙
  • 可选:SMTP 服务器用于封禁事件的邮件通知

工作流程

步骤 1:安装和配置 Fail2ban

# 安装 Fail2ban
sudo apt install -y fail2ban

# 创建本地配置(不要直接编辑 jail.conf)
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

# 配置全局默认值
sudo tee /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
# 封禁时长(默认 1 小时,对重复违规者逐步升级)
bantime = 3600
# 检测窗口
findtime = 600
# 封禁前的最大失败次数
maxretry = 5
# 使用 iptables 的封禁动作
banaction = iptables-multiport
banaction_allports = iptables-allports
# 邮件通知
destemail = security@example.com
sender = fail2ban@example.com
mta = sendmail
action = %(action_mwl)s

# 忽略内网
ignoreip = 127.0.0.1/8 ::1 10.10.0.0/16

# 在可用时使用 systemd journal 后端
backend = systemd

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 7200
findtime = 300

[sshd-ddos]
enabled = true
port = ssh
filter = sshd-ddos
logpath = /var/log/auth.log
maxretry = 6
bantime = 3600
EOF

步骤 2:创建自定义端口扫描检测过滤器

# 为丢弃的连接创建 iptables 日志规则
sudo iptables -N PORTSCAN
sudo iptables -A PORTSCAN -j LOG --log-prefix "PORTSCAN_DETECTED: " --log-level 4
sudo iptables -A PORTSCAN -j DROP

# 记录到关闭端口的 SYN 数据包(表明有扫描)
sudo iptables -A INPUT -p tcp --tcp-flags SYN,ACK,FIN,RST SYN -m state --state NEW \
  -m recent --name portscan --set
sudo iptables -A INPUT -p tcp --tcp-flags SYN,ACK,FIN,RST SYN -m state --state NEW \
  -m recent --name portscan --rcheck --seconds 10 --hitcount 20 -j PORTSCAN

# 为端口扫描创建 Fail2ban 过滤器
sudo tee /etc/fail2ban/filter.d/portscan.conf << 'EOF'
[Definition]
# 匹配 iptables 端口扫描日志条目
failregex = PORTSCAN_DETECTED: .* SRC=<HOST> DST=\S+ .* DPT=\d+
ignoreregex =
datepattern = {^LN-BEG}
EOF

# 为通过内核日志检测 Nmap 创建 Fail2ban 过滤器
sudo tee /etc/fail2ban/filter.d/nmap-scan.conf << 'EOF'
[Definition]
# 检测来自同一来源的多个端口的快速连接尝试
failregex = kernel: \[.*\] PORTSCAN_DETECTED: .* SRC=<HOST>
            iptables: .* PORTSCAN .* SRC=<HOST>
ignoreregex =
datepattern = {^LN-BEG}
EOF

# 为 HTTP 扫描/探测创建过滤器
sudo tee /etc/fail2ban/filter.d/http-scan.conf << 'EOF'
[Definition]
# 检测探测常见漏洞的扫描器
failregex = ^<HOST> .* "(GET|POST|HEAD) /(wp-login|wp-admin|phpmyadmin|admin|.env|xmlrpc|wp-content/uploads).*" (403|404|444)
            ^<HOST> .* "(GET|POST) /.*\.(php|asp|aspx|jsp|cgi)\?.*" (403|404)
            ^<HOST> .* "() .*" 400
            ^<HOST> .* "(GET|POST) /.*" 400
ignoreregex =
datepattern = {^LN-BEG}
EOF

步骤 3:为端口扫描配置 Jail

# 将端口扫描 jail 添加到 jail.local
sudo tee -a /etc/fail2ban/jail.local << 'EOF'

[portscan]
enabled = true
filter = portscan
logpath = /var/log/kern.log
maxretry = 10
findtime = 60
bantime = 86400
banaction = iptables-allports
action = %(action_mwl)s

[nmap-scan]
enabled = true
filter = nmap-scan
logpath = /var/log/kern.log
maxretry = 5
findtime = 30
bantime = 86400
banaction = iptables-allports
action = %(action_mwl)s

[http-scan]
enabled = true
filter = http-scan
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 300
bantime = 3600
banaction = iptables-multiport
port = http,https

[recidive]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
bantime = 604800
findtime = 86400
maxretry = 3
banaction = iptables-allports
action = %(action_mwl)s
EOF

步骤 4:配置高级封禁动作

# 创建自定义动作,封禁并发送 Webhook 通知
sudo tee /etc/fail2ban/action.d/iptables-webhook.conf << 'EOF'
[Definition]
actionstart = <iptables> -N f2b-<name>
              <iptables> -A f2b-<name> -j RETURN
              <iptables> -I <chain> -p <protocol> -j f2b-<name>

actionstop = <iptables> -D <chain> -p <protocol> -j f2b-<name>
             <iptables> -F f2b-<name>
             <iptables> -X f2b-<name>

actioncheck = <iptables> -n -L <chain> | grep -q 'f2b-<name>[ \t]'

actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>
            curl -s -X POST "<webhook_url>" \
              -H "Content-Type: application/json" \
              -d '{"text":"[Fail2ban] Banned <ip> from <name> jail (failures: <failures>)"}'

actionunban = <iptables> -D f2b-<name> -s <ip> -j <blocktype>

[Init]
chain = INPUT
blocktype = DROP
webhook_url = https://hooks.slack.com/services/XXXX/YYYY/ZZZZ
EOF

# 为重复违规者创建递进封禁动作
sudo tee /etc/fail2ban/action.d/escalating-ban.conf << 'EOF'
[Definition]
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j DROP
            echo "$(date) BAN <ip> jail=<name> failures=<failures> bantime=<bantime>" >> /var/log/fail2ban-bans.log

actionunban = <iptables> -D f2b-<name> -s <ip> -j DROP
              echo "$(date) UNBAN <ip> jail=<name>" >> /var/log/fail2ban-bans.log
EOF

步骤 5:测试和验证检测

# 重启 Fail2ban
sudo systemctl restart fail2ban

# 验证 jail 是否激活
sudo fail2ban-client status
sudo fail2ban-client status sshd
sudo fail2ban-client status portscan

# 用正则表达式检查测试端口扫描过滤器
sudo fail2ban-regex /var/log/kern.log /etc/fail2ban/filter.d/portscan.conf

# 测试 HTTP 扫描过滤器
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/http-scan.conf

# 从测试机器模拟端口扫描(已授权)
# 在测试机器上执行:
nmap -sS -p 1-1000 <target_ip>

# 验证扫描器被封禁
sudo fail2ban-client status portscan
# 应显示测试 IP 在封禁列表中

# 检查 iptables 中的封禁规则
sudo iptables -L f2b-portscan -n

# 解封测试 IP
sudo fail2ban-client set portscan unbanip <test_ip>

步骤 6:监控和维护

# 实时查看封禁活动
sudo tail -f /var/log/fail2ban.log | grep -E "Ban|Unban"

# 生成每日摘要报告
sudo tee /usr/local/bin/fail2ban-report.sh << 'SCRIPT'
#!/bin/bash
echo "=== Fail2ban 每日报告 $(date) ==="
echo ""
echo "活跃 Jail:"
sudo fail2ban-client status | grep "Jail list"
echo ""
echo "当前封禁 IP:"
for jail in $(sudo fail2ban-client status | grep "Jail list" | sed 's/.*://;s/,//g'); do
    count=$(sudo fail2ban-client status "$jail" | grep "Currently banned" | awk '{print $NF}')
    if [ "$count" -gt 0 ]; then
        echo "  $jail: $count 已封禁"
        sudo fail2ban-client status "$jail" | grep "Banned IP"
    fi
done
echo ""
echo "过去 24 小时——按 Jail 统计封禁数:"
grep "Ban " /var/log/fail2ban.log | grep "$(date +%Y-%m-%d)" | awk '{print $NF}' | sort | uniq -c | sort -rn
SCRIPT
chmod +x /usr/local/bin/fail2ban-report.sh

# 定时每日报告
echo "0 8 * * * root /usr/local/bin/fail2ban-report.sh | mail -s 'Fail2ban Report' security@example.com" | sudo tee /etc/cron.d/fail2ban-report

# 跨重启持久化 iptables 规则
sudo apt install iptables-persistent
sudo netfilter-persistent save

核心概念

术语定义
JailFail2ban 配置单元,将过滤器(检测内容)、动作(执行操作)和参数(阈值、时间)组合在一起,用于特定服务
Filter(过滤器)Fail2ban 应用于日志文件的正则表达式模式,用于识别认证失败、扫描或其他恶意活动
Recidive Jail元 Jail,监控 Fail2ban 自身日志以发现重复违规者,对多次被封禁的 IP 应用递进封禁时长
Find TimeFail2ban 统计匹配日志条目的时间窗口(秒);在 findtime 内达到 maxretry 次失败则触发封禁
Ban ActionIP 被封禁时执行的命令或脚本,通常添加防火墙规则,也可扩展为 Webhook、SIEM 告警或黑名单更新
Ignore IP永不封禁的 IP 地址或 CIDR 范围白名单,防止锁定可信网络和监控系统

工具与系统

  • Fail2ban 0.11+:基于日志解析的入侵防御框架,根据对任意日志文件的模式匹配来封禁 IP 地址
  • iptables/nftables:Fail2ban 封禁动作用于在网络层封锁攻击 IP 的 Linux 内核防火墙
  • fail2ban-regex:测试工具,用于在部署到生产前对实际日志文件验证过滤器正则表达式
  • fail2ban-client:命令行管理工具,用于查询 jail 状态、手动封禁/解封 IP 以及重新加载配置
  • rsyslog/syslog-ng:生成 Fail2ban 监控的日志文件的系统日志守护进程

常见场景

场景:防御公开 Web 服务器上的自动扫描

背景:某公司运营着一台公开的 Web 服务器,每天收到数千次自动扫描尝试,机器人探测 /wp-admin、/phpmyadmin、/.env 等易受攻击的路径。安全团队希望在允许合法流量通过的同时自动封锁扫描器。服务器在 Ubuntu 22.04 上运行 Nginx。

方法:

  1. 安装 Fail2ban 并配置其监控 Nginx 访问日志中的扫描模式(对已知漏洞路径的 404/403 响应)
  2. 创建自定义 http-scan 过滤器,匹配常见扫描器签名和漏洞探测 URI
  3. 将 maxretry 设为 10,findtime 为 5 分钟,首次违规的 bantime 为 1 小时
  4. 启用 recidive jail,对重复违规者将封禁时长升级为 7 天
  5. 配置 Webhook 通知至 Slack,实时可见封禁活动
  6. 为到关闭端口的 SYN 数据包添加 iptables 日志规则,检测端口扫描
  7. 创建每日报告脚本,显示封禁 IP、攻击模式和地理分布

常见陷阱:

  • maxretry 设置过低(如 1-2),导致输错 URL 的合法用户被封禁
  • 未将监控系统(Nagios、UptimeRobot)加入白名单,其健康检查可能触发过滤器
  • 忘记持久化 iptables 规则,重启后所有封禁丢失
  • 部署前未用 fail2ban-regex 测试过滤器,导致无匹配或大量误报

输出格式

## Fail2ban 端口扫描防御报告

**服务器**:web-prod-01(203.0.113.50)
**报告周期**:2024-03-15 00:00 至 2024-03-16 00:00 UTC

### 活跃 Jail

| Jail | 过滤器 | 最大重试 | 封禁时长 | 当前封禁 |
|------|--------|-----------|----------|------------------|
| sshd | sshd | 3 | 2 小时 | 12 个 IP |
| portscan | portscan | 10 | 24 小时 | 47 个 IP |
| http-scan | http-scan | 10 | 1 小时 | 89 个 IP |
| recidive | recidive | 3 | 7 天 | 8 个 IP |

### 24 小时摘要
- 封禁事件总数:347
- 唯一 IP 封禁数:156
- 主要攻击来源:CN(67 个 IP),RU(34 个 IP),US(21 个 IP)
- 最频繁攻击服务:HTTP 扫描(214 次封禁)
- 重复违规升级:8 个 IP 被封禁 7 天

### 前 5 封禁 IP
| IP 地址 | Jail | 封禁次数 | 首次发现 | 最后发现 |
|------------|------|-----------|------------|-----------|
| 45.33.32.156 | portscan | 12 | 00:15 | 23:47 |
| 198.51.100.23 | http-scan | 8 | 02:30 | 18:22 |
| 203.0.113.100 | sshd | 6 | 05:12 | 21:33 |
Skills enregistrées