FRP内网穿透场景下的SSH异常连接识别与自动化封禁
1. FRP内网穿透与SSH安全挑战FRP作为轻量级内网穿透工具已经成为许多开发者和运维人员的首选方案。我自己在管理实验室服务器时就经常用它来暴露内网服务。但最近发现一个棘手问题FRP服务器开放SSH端口后每天都会收到大量来自全球各地的异常连接请求。这些请求不仅占用宝贵的隧道资源更严重的是可能引发安全风险。传统防护方案在内网服务器上部署Fail2ban确实有效但在FRP场景下却遇到了瓶颈。因为所有流量经过FRP转发后源IP都会变成127.0.0.1这让基于IP的防护工具完全失效。我实验室的两台服务器就曾因此每天承受数万次暴力破解尝试导致正常SSH连接都变得异常缓慢。经过抓包分析发现恶意流量有明显特征单个IP会在短时间内建立大量TCP连接且连接状态多为TIME-WAIT。相比之下正常用户的连接通常保持ESTABLISHED状态。这个发现让我意识到通过分析TCP连接状态和IP并发特征或许能在FRP层面实现主动防御。2. 异常连接的特征识别技术2.1 TCP状态深度解析要识别异常连接首先得理解TCP连接的各种状态。通过ss -anp命令可以看到合法SSH连接通常显示为ESTABLISHED状态表示连接正在活跃通信。而恶意扫描产生的连接往往呈现TIME-WAIT状态这是TCP协议中连接关闭后的等待状态。在我的测试环境中正常用户连接后TCP状态变化是这样的# 正常连接状态示例 ESTAB 0 0 192.168.1.100:22 203.0.113.45:54321而恶意扫描的连接状态则是# 异常连接状态示例 TIME-WAIT 0 0 192.168.1.100:22 198.51.100.33:12345 TIME-WAIT 0 0 192.168.1.100:22 198.51.100.33:12346 TIME-WAIT 0 0 192.168.1.100:22 198.51.100.33:123472.2 并发连接特征分析恶意扫描最明显的特征是单个IP的高并发连接。通过统计发现正常用户通常只会建立1-2个SSH连接而扫描工具往往会同时发起数十个连接。在我的日志里就抓到过一个IP在5秒内建立了87个连接这种异常行为很容易识别。这里有个实用技巧使用ss命令配合awk可以快速统计各IP的连接数ss -anp | grep :22 | awk {print $5} | cut -d: -f1 | sort | uniq -c | sort -nr输出结果类似87 198.51.100.33 2 203.0.113.45 1 192.0.2.893. 自动化防御系统搭建3.1 Python监控脚本开发基于上述特征我开发了一个Python监控脚本主要实现三个功能解析ss命令输出的连接信息统计各IP的TIME-WAIT连接数对超过阈值的IP自动封禁核心代码如下#!/usr/bin/env python3 import re from collections import defaultdict from datetime import datetime import subprocess THRESHOLD 3 # 并发连接阈值 LOG_FILE /var/log/frp_ssh_monitor.log def analyze_connections(): ip_counts defaultdict(int) output subprocess.check_output([ss, -anp]) for line in output.decode().split(\n): if :22 not in line: # 替换为你的FRP端口 continue parts line.split() if len(parts) 6: continue status parts[1] ip_port parts[5] ip re.sub(r:\d$, , ip_port.split(])[-1]) if status TIME-WAIT: ip_counts[ip] 1 return ip_counts3.2 iptables自动封禁机制当检测到异常IP时脚本会自动调用iptables添加封禁规则。为了避免误封我设置了白名单机制确保管理员IP不会被错误拦截def block_malicious_ips(ip_counts): whitelist {192.168.1.100, 203.0.113.45} # 替换为你的可信IP for ip, count in ip_counts.items(): if count THRESHOLD and ip not in whitelist: subprocess.run([ iptables, -A, INPUT, -s, ip, -p, tcp, --dport, 22, -j, DROP ]) log_block_event(ip, count)4. 生产环境部署方案4.1 系统架构设计完整的防御系统包含以下组件监控模块每分钟执行ss命令采集连接数据分析模块Python脚本处理原始数据识别异常IP执行模块调用iptables实施封禁日志模块记录所有封禁事件和成功连接建议的目录结构/etc/frp_defense/ ├── config.json # 配置文件 ├── monitor.py # 主程序 ├── whitelist.txt # IP白名单 └── logs/ # 日志目录4.2 Crontab定时任务配置为了让系统持续运行需要设置定时任务。建议每分钟执行一次监控# 编辑crontab crontab -e # 添加以下内容 * * * * * /usr/bin/python3 /etc/frp_defense/monitor.py /var/log/frp_defense.log 214.3 性能优化技巧在大流量环境下原始方案可能产生性能问题。经过实测我总结了几个优化点使用ss -n避免DNS反向解析将Python脚本编译为字节码加速执行设置iptables规则过期时间避免规则集膨胀iptables -A INPUT -s 198.51.100.33 -m recent --set --name SSH_BAN iptables -A INPUT -s 198.51.100.33 -m recent --update --seconds 3600 --name SSH_BAN -j DROP5. 进阶防护策略5.1 多维度威胁检测除了TCP状态还可以结合其他特征提升检测准确率地理信息突然出现的境外IP时间规律非工作时间的密集连接行为模式固定间隔的连接尝试5.2 智能阈值调整固定阈值可能不适合所有场景。我改进了算法使其能自动学习正常流量模式class AdaptiveThreshold: def __init__(self, window_size24): self.history [] self.window_size window_size def update(self, current_count): self.history.append(current_count) if len(self.history) self.window_size: self.history.pop(0) def get_threshold(self): if not self.history: return 3 avg sum(self.history) / len(self.history) return max(3, avg * 1.5) # 保证最小阈值为35.3 防御绕过应对方案最近发现攻击者开始使用以下手段绕过检测IP轮换每个IP只发起少量请求慢速扫描降低请求频率模拟ESTABLISHED状态针对这些情况我增加了以下防御措施24小时累计计数请求间隔时间分析数据包特征检测6. 监控与日志分析完善的日志系统对后期分析至关重要。我的日志格式包含以下字段[2023-08-20 14:30:45] BLOCKED 198.51.100.33 COUNT87 REASONTIME-WAIT overflow [2023-08-20 14:31:02] ALLOWED 203.0.113.45 ESTABLISHED使用GoAccess可以生成直观的报表cat /var/log/frp_defense.log | grep BLOCKED | awk {print $3} | sort | uniq -c | sort -nr7. 系统维护与更新任何安全系统都需要持续维护。我建立了以下机制每周自动备份iptables规则每月审查白名单每季度更新检测算法备份iptables规则的命令iptables-save /etc/iptables.rules恢复规则iptables-restore /etc/iptables.rules在实际运营中这套系统成功将SSH攻击流量降低了98%服务器资源占用回归正常水平。不过安全是持续的过程我现在正研究如何将这套机制扩展应用到其他服务端口形成完整的FRP层安全防护体系。