Python脚本防止Linux远程SSH暴力破解

Python脚本防止Linux远程SSH暴力破解

问题:

服务器被长时间持续ssh访问暴力破解,系统存在大量的sshd异常访问日志和错误提示,例如

Failed password for invalid user 用户名 from IP地址 port 端口号 ssh2
Connection closed by IP地址 port 端口号 [preauth]
error: kex_exchange_identification: Connection closed by remote host

解决方案:

读取Linux日志/var/log/secure中的日志记录(不同版本的系统的日志文件不同,但一般都在/var/logl路径下的某个日志文件中,例如messages),识别包含Connection closed.*preauth并且不包含user的sshd日志(即在用户认证之前被异常关闭的访问请求),和包含Failed的sshd日志(即由于密码或端口错误而失败的请求),以及包含authentication failuresshd日志(身份验证失败),提取其中IP地址和记录出现次数。当IP地址出现的次数大于指定的阈值时,判断该Ip地址是否已井存在于防火墙规则中,若不存在,则将其加入防火墙规则拒绝其访问。

代码:

#!/usr/bin/python
# coding=utf-8

# 导入启动其他进程的模块
import subprocess
# 导入正则表达式模块
import re
# 从collections模块中导入一个计数器Counter类
from collections import Counter
# 导入时间模块
import time

# 系统日志文件路径
sys_log_path = '/var/log/secure'
# 脚本日志路径
log_path = '/sshPrevent/' + time.strftime('%Y%m%d') + '.log'
# IP地址出现次数阈值
define = 5

# 读取系统sshd日志
def read_sshd_log():
    # 始化一个计数器来存储IP地址及其出现次数
    ip_counter = Counter()
    # 读取日志文件
    with open (sys_log_path,'r') as file:
        # 逐行读取
        for line in file:
            # 用re模块中的search函数来搜索字符串line中是否包含符合特定模式的子串
            ip_match = re.search(r'\b([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\b', line)
            # 判断ip_match对象是否存在
            if ip_match:
                # 提取正则表达式中的第1个捕获组匹配到的文本
                ip_address = ip_match.group(1)
                # 检查行是否满足条件
                if 'Connection closed.*preauth' in line and 'user' not in line:
                    # 把ip_counter字典中ip_address键对应的值增加1,如果ip_adress不存在则新增并将值设置为1
                    ip_counter[ip_address] += 1
                elif 'Failed' in line:
                    ip_counter[ip_address] += 1
                elif 'authentication failure' in line:
                	ip_counter[ip_address] += 1
    # 返回最终的计数器字典
    return ip_counter
    
# 判断IP地址是否已经在firewall列表中
def check_firewall_ip(ip):
    # 构建firewall查询命令,使用grep来搜索包含指定IP地址
    command = "firewall-cmd --list-all |grep " + ip
    # 执行命令并获取输出(python3.6和3.7版本的subprocess参数不太一样)
    result = subprocess.run(command, shell=True, stdout=subprocess.PIPE, universal_newlines=True)
    # 检查命令是否成功执行并且有输出
    if result.returncode == 0 and result.stdout:
        # 如果有输出,说明找到了包含该IP地址的规则
        return 'true'
    else:
        # 如果没有输出或者命令执行失败,说明没有找到该IP地址的规则
        return 'false'

# 添加firewall规则,拒绝指定的IP地址
def add_firewall_rule(ip):
    # 构建防火墙规则(\是为了转译单引号,在此处不加也可以)
    rule = "rule family=\'ipv4\' source address=" + ip + " reject"
    # 构建添加firewall规则的参数
    command = ['firewall-cmd', '--permanent', '--add-rich-rule', rule]
    # 执行命令并获取输出(在python3.7中,universal_newlines=True变成了text=True)
    result = subprocess.run(command,stdout=subprocess.PIPE, universal_newlines=True)
    # 执行成功返回true,否则返回false 
    if result.returncode == 0:
        return 'true'
    else:
        # 执行失败则返回false
        return 'false'

# 重新加载firewall规则
def reload_firewall_rule():    
    # 构建firewall重新加载命令
    command = ['firewall-cmd', '--reload']
    # 执行命令并获取输出
    result = subprocess.run(command,stdout=subprocess.PIPE, universal_newlines=True)
    # 执行完成,成功则返回true
    if result.returncode == 0:
        return 'true'
    else:
        return 'false'

# 写入执行日志
def write_python_log(ip):
	# 打开日志,执行写入,方式为追加
    with open(log_path, 'a') as file:
    	# 写入的内容为时间+IP地址+提示内容,并换行
        file.write( time.strftime('%Y-%m-%d %H:%M:%S') + ' ' + ip + ' Add To Firewall Success.\n')
    return

# 执行步骤
def start():
    try:
    	# 读取计数器中的Ip地址和出现次数
    	for ip, count in read_sshd_log().items():
        	# 若IP地址出现的次数大于等于阈值,则继续
        	if count > define:
            	# 判断Ip地址是否已存在于firewall,不存在则继续
            	if 'false' in check_firewall_ip(ip):
                	# 添加到firewall,成功则继续
                	if 'true' in add_firewall_rule(ip):
                    	# 重新加载firewall,成功则继续
                    	if 'true' in reload_firewall_rule():
                        	# 将添加规则的记录写入日志
                        	write_python_log(ip)
    finally:
    	return None

if __name__ == '__main__':
    start()

yunxi p.deng 2024/06/22

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值