FRP作为高性能内网穿透工具,广泛运用在高校和企业的内网服务器穿透,让内部服务器可以通过外网访问内部资源。但是FRP给运维人员带来便利的同时,也暗藏被Hacker爆破攻击的风险。传统防止SSH被扫描爆破的方法有很多,比如关闭密码认证只允许ssh密钥认证、Fail2ban封掉扫描机器ip等等。但是由于FRP服务器无法区分异常流量,目前已有的方法只能在内网服务器部署,大量来自攻击者的流量仍会占据大量FRP隧道资源。同时来自FRP服务器的流量来源ip都是127.0.0.1
,难以用Fail2ban过滤。因此针对上述难题,我设计了一种针对异常流量的过滤策略,避免FRP端口暴露导致的ssh爆破安全问题和网络拥塞问题。
实验室的导师来自2个大学,有两个不同地区的服务器通过FRP做了内网穿透,外网端口分别是23
和24
。由于Fail2ban无法区分来自127.0.0.1
的非法访问流量,我们将在FRP服务器结合Crontab和iptables过滤非法扫描爆破的ip。
非法流量特征:
ss -anp | grep ":port"
(port切换为你的frps开放的ip),会发现合法的ip显示的状态是ESTAB
;TIME-WAIT
并且同时大量同ip并发连接。解决思路:
23
和24
;TIME-WAIT
并且同时存在大量同ip并发连接,用iptables拉黑。异常流量的过滤策略的python程序:逻辑是把超过3个并发的非法ip访问加入黑名单。同时记录下登陆成功和拉黑的时间和访问ip。
#!/usr/bin/env python3
import re
from collections import defaultdict
from datetime import datetime
import subprocess
# 日志文件路径
log_file_path = '/home/user/right.log'
# 输出文件路径
ban_ip_file = '/home/user/ban_ip.txt'
establishment_ip_file = '/home/user/establishment_ip.txt'
# IP状态计数
ip_counts = defaultdict(int)
# 成功连接的IP集合
established_ips = set()
def parse_log_file():
with open(log_file_path, 'r') as file:
next(file) # Skip header
for line in file:
parts = line.strip().split()
if len(parts) < 6:
continue
status = parts[1] # Correct column for status
# Correct extraction of IP address without port
remote_ip = re.sub(r'\[::ffff:(.*?)\]', r'\1', parts[5])
remote_ip = re.sub(r':\d+$', '', remote_ip) # Remove port number
if status == 'ESTAB':
if remote_ip not in established_ips:
established_ips.add(remote_ip)
record_established_connection(remote_ip)
elif status == 'TIME-WAIT':
ip_counts[remote_ip] += 1
def record_established_connection(ip):
with open(establishment_ip_file, 'a') as file:
file.write(f"{datetime.now()}: Established connection from IP {ip}\n")
print(f"Recorded established connection: {ip}")
def apply_iptables_rules():
for ip, count in ip_counts.items():
print('count',count)
if count > 3: # Threshold is 3
subprocess.run(['sudo', 'iptables', '-A', 'INPUT', '-s', ip, '-j', 'DROP'], stdout=subprocess.DEVNULL)
with open(ban_ip_file, 'a') as file:
file.write(f"{datetime.now()}: Blocked IP {ip} due to exceeding TIME-WAIT threshold\n")
print(f"Blocked IP: {ip}")
if __name__ == '__main__':
parse_log_file()
apply_iptables_rules()
Crontab运行的脚本
ss -anp | grep ":23" >/home/user/right.log
sudo /home/user/monitor_and_block.py
ss -anp | grep ":24" >/home/user/right.log
sudo /home/user/monitor_and_block.py
针对异常流量的过滤策略
之后,发现更好的办法是关闭ssh的密码登录,同时设置 SSH 通过密钥登录;