FRP内网穿透如何避免SSH暴力破解(一)

目录

  • 前言
    • 情况分析
    • 完整代码和脚本
    • 总结

前言

FRP作为高性能内网穿透工具,广泛运用在高校和企业的内网服务器穿透,让内部服务器可以通过外网访问内部资源。但是FRP给运维人员带来便利的同时,也暗藏被Hacker爆破攻击的风险。传统防止SSH被扫描爆破的方法有很多,比如关闭密码认证只允许ssh密钥认证、Fail2ban封掉扫描机器ip等等。但是由于FRP服务器无法区分异常流量,目前已有的方法只能在内网服务器部署,大量来自攻击者的流量仍会占据大量FRP隧道资源。同时来自FRP服务器的流量来源ip都是127.0.0.1,难以用Fail2ban过滤。因此针对上述难题,我设计了一种针对异常流量的过滤策略,避免FRP端口暴露导致的ssh爆破安全问题和网络拥塞问题。

情况分析

实验室的导师来自2个大学,有两个不同地区的服务器通过FRP做了内网穿透,外网端口分别是2324。由于Fail2ban无法区分来自127.0.0.1的非法访问流量,我们将在FRP服务器结合Crontab和iptables过滤非法扫描爆破的ip。

非法流量特征:

  1. 同一个ip会同时启动是个乃至上百个访问,轮流试图破解SSH密码;
  2. 运行ss -anp | grep ":port" (port切换为你的frps开放的ip),会发现合法的ip显示的状态是ESTAB
  3. 而非法ip显示的是TIME-WAIT并且同时大量同ip并发连接。

解决思路:

  1. 定期扫描访问开放端口的tcp连接情况,本文是2324
  2. 如果发现连接是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

总结

  1. 后来部署上我的针对异常流量的过滤策略之后,发现更好的办法是关闭ssh的密码登录,同时设置 SSH 通过密钥登录
  2. 这些爆破肉鸡发现我的服务器没法用账号密码试错之后,都纷纷放弃了扫描;
  3. 但是出现了新情况,仍然有随机的ip试图连接我的主机电脑,虽然破解密钥需要几十年,但是试图反复建立TCP链路仍然造成了流量的浪费,下一篇文章我将讲述如何解决这种问题。

你可能感兴趣的:(ssh,运维,内网穿透,python,FRP)