基于Nginx日志与Python的服务器IP动态黑名单自动封禁实战
2026/8/14 5:02:51 网站建设 项目流程

1. 项目概述:从“爱扫站”到主动防御

最近在整理服务器日志时,发现了一个有趣又让人头疼的现象:总有一些IP地址,像不知疲倦的“清洁工”一样,24小时不间断地扫描我的网站。它们尝试各种默认后台路径、探测已知漏洞、甚至暴力破解登录入口。虽然大部分现代Web应用框架和服务器都有基础的安全防护,但放任这些“爱扫站”的IP持续骚扰,不仅浪费服务器资源、产生大量无效日志,更关键的是,它们暴露了潜在的攻击意图。今天要聊的,就是如何从被动记录转为主动出击,为这些不请自来的“访客”建立一份专属的“黑名单”。

这个“IP黑名单”项目,本质上是一个基于行为的动态防火墙规则集。它不是一个简单的静态列表,而是一套从日志分析、威胁判定到自动封禁的完整流程。对于任何拥有线上服务(无论是个人博客、企业官网还是API服务)的运维人员或开发者来说,手动处理攻击日志是低效且不可持续的。通过自动化脚本,我们可以将那些在短时间内进行高频次恶意扫描、尝试非法访问的IP地址自动识别出来,并实时将其加入系统的防火墙(如iptablesfirewalld)或Web服务器(如Nginx、Apache)的拒绝访问列表中,从而实现服务器层面的主动防御。

适合阅读这篇内容的朋友包括:个人站长、中小型企业运维、对服务器安全有初步了解的开发者,以及任何希望提升自己服务安全水位,又不想依赖昂贵商业WAF(Web应用防火墙)的实践者。整个过程将围绕Linux服务器环境展开,用到的工具都是开源且常见的,核心思想是“用自动化对抗自动化攻击”。

2. 核心思路与方案选型:为什么是“日志分析+动态封禁”?

面对海量的服务器访问日志,手动筛选恶意IP无异于大海捞针。因此,我们的核心思路是:通过程序自动分析特定时间段内的访问日志,根据预设的规则(如单位时间内访问特定敏感路径的次数、返回404状态码的频率等)识别出可疑IP,然后调用系统命令将其封禁。

这个方案有几个关键优势。首先,成本极低,完全利用现有服务器和开源工具,无需额外硬件或软件投入。其次,响应迅速,可以实现近实时的封禁,攻击者刚扫描几分钟就可能被踢出局。再者,高度可定制,你可以根据自己服务的具体特点,定义什么样的行为算是“恶意扫描”。例如,对于后台登录页面/wp-admin/admin的频繁访问,显然比访问首页更值得警惕。

在技术选型上,我们主要需要解决两个问题:日志分析引擎封禁执行器

对于日志分析,awkgrepsed这些Linux文本处理“三剑客”是轻量级任务的绝佳选择。它们速度快,几乎在所有Linux发行版上都预装,非常适合处理按行存储的Nginx或Apache日志。如果规则更复杂,或者需要连接数据库进行历史记录查询,那么用Python配合re(正则表达式)模块会是更灵活强大的选择。本项目我们将以Python为例,因为它可读性更好,便于后续添加更复杂的逻辑。

对于封禁执行器,主流选择有两个:

  1. 系统防火墙:如iptables(传统)或firewalld(CentOS/RHEL 8+, Fedora)。直接在网络层丢弃该IP的所有数据包,效果最彻底,对Web服务器软件透明。
  2. Web服务器层封禁:如在Nginx配置文件的server块内使用deny指令,或在Apache中使用Require not ip。这仅在应用层生效,效率略低于防火墙,但配置更简单,且不影响服务器上其他服务。

注意:直接操作iptables需要root权限,且规则配置不当可能导致自己无法远程连接服务器。务必在操作前确保有通过控制台(如云服务商的VNC)登录服务器的备用方案。

综合考虑,我们将采用“Python分析Nginx日志 + 调用iptables封禁”的组合。这套方案通用性强,封禁力度大,是生产环境常见的实践。整个系统的运行将由crontab定时任务驱动,例如每5分钟执行一次分析脚本,实现准实时防护。

3. 实战环境准备与日志格式解析

在开始编写脚本之前,我们需要确保环境就绪,并深刻理解要分析的“原材料”——服务器访问日志的格式。

3.1 环境与权限检查

首先,确认你的服务器环境。通过ssh登录后,可以快速检查:

# 查看系统版本和内核 cat /etc/os-release uname -a # 检查Python3是否安装 python3 --version # 或 python --version # 检查iptables是否可用 which iptables sudo iptables -L -n | head -20 # 查看现有规则,需要sudo权限

确保你使用的账号有执行sudo iptables命令的权限。通常需要将用户加入sudoers组,或者为特定的iptables命令配置免密码sudo。出于安全,我们更建议后者。可以使用visudo命令编辑/etc/sudoers文件,添加一行(请将your_username替换为实际用户名):

your_username ALL=(ALL) NOPASSWD: /sbin/iptables

这样,脚本中调用sudo iptables时就不需要交互式输入密码了。

3.2 理解Nginx日志格式

Nginx的访问日志通常位于/var/log/nginx/access.log,也可能在/etc/nginx/nginx.conf或站点配置中指定。日志的默认格式是“combined”格式,一条记录看起来像这样:

123.45.67.89 - - [10/May/2024:15:32:01 +0800] "GET /wp-login.php HTTP/1.1" 404 162 "-" "Mozilla/5.0 (compatible; SomeBot/1.0)"

我们需要拆解每个字段的含义,以便用程序提取关键信息:

  • 123.45.67.89: 客户端的IP地址。这是我们最关心的字段。
  • [10/May/2024:15:32:01 +0800]: 访问的时间戳。
  • "GET /wp-login.php HTTP/1.1": 请求方法、请求的URI(资源路径)和HTTP协议版本。/wp-login.php就是一个典型的扫描目标。
  • 404: HTTP状态码。404表示未找到,大量404请求往往意味着扫描器在盲猜路径。
  • 162: 返回给客户端的数据包大小(字节)。
  • "-":Referer请求头信息。
  • "Mozilla/5.0 (compatible; SomeBot/1.0)":User-Agent字符串。很多扫描器会在此暴露自己,比如包含scanbotpython-requests等关键词,但更狡猾的攻击者会伪装成普通浏览器。

我们的分析逻辑将主要围绕IP地址请求URI状态码这三个核心字段展开。例如,我们可以定义一个规则:“在过去5分钟内,来自同一个IP地址,对/admin/wp-admin/phpmyadmin等敏感路径的访问请求超过10次,且其中404状态码占比超过70%,则判定该IP为扫描器,加入黑名单。”

4. 核心脚本编写:从日志分析到自动封禁

接下来,我们将一步步构建这个自动化的“IP黑名单”系统。脚本分为三个主要部分:日志读取与解析、恶意IP判定、执行封禁操作。

4.1 日志读取与时间窗口筛选

首先,我们需要读取最近一段时间内的日志。直接分析整个日志文件是不现实的,因为文件可能很大。我们利用日志的时间戳,只分析最近N分钟的数据。

#!/usr/bin/env python3 # -*- coding: utf-8 -*- # 文件名: ip_blacklist.py import re import sys from datetime import datetime, timedelta import subprocess import logging # 配置日志,方便调试和记录封禁操作 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler('/var/log/ip_blacklist.log'), logging.StreamHandler(sys.stdout) ] ) logger = logging.getLogger(__name__) # 配置文件区域(根据实际情况修改) NGINX_LOG_PATH = '/var/log/nginx/access.log' # 分析最近多少分钟内的日志 TIME_WINDOW_MINUTES = 5 # 封禁时长(单位:秒),86400秒=24小时 BAN_DURATION = 86400 # 敏感路径列表,可根据自己站点情况增删 SENSITIVE_PATHS = [ '/wp-admin', '/wp-login.php', '/admin', '/administrator', '/phpmyadmin', '/mysql', '/db', '/config', '/.env', '/api/login', '/user/login', '/backup', '/shell' ] # 判定为恶意的阈值:在时间窗口内,访问敏感路径的总次数 THRESHOLD_ACCESS_COUNT = 15 # 另一个判定维度:在时间窗口内,404状态码的请求次数 THRESHOLD_404_COUNT = 10 def parse_nginx_log_line(line): """ 解析单条Nginx combined格式日志。 返回一个字典,包含ip, time, method, uri, status等字段。 如果解析失败,返回None。 """ # 使用正则表达式匹配combined格式 # 这个正则比简单的split更健壮,能处理User-Agent中包含空格等复杂情况 pattern = r'(?P<ip>\S+) \S+ \S+ \[(?P<time>[^\]]+)\] "(?P<method>\S+) (?P<uri>\S+) \S+" (?P<status>\d+) (?P<size>\S+) "[^"]*" "(?P<ua>[^"]*)"' match = re.match(pattern, line) if match: return match.groupdict() else: # 如果正则匹配失败,可以尝试简单的空格分割(可靠性较低) parts = line.split() if len(parts) >= 10: return { 'ip': parts[0], 'time': parts[3].strip('['), 'uri': parts[6], 'status': parts[8] } return None

这段代码定义了日志解析函数。我们使用正则表达式来精确匹配日志格式,并提供了一个备用的简单分割方法。SENSITIVE_PATHS列表需要你根据自己网站的实际结构进行定制,把那些不希望被公开访问或经常被扫描的管理后台、配置文件和API端点加进去。

4.2 恶意IP判定逻辑实现

有了解析函数,我们需要遍历日志文件,筛选出时间窗口内的记录,并按IP进行聚合分析。

def analyze_logs(): """ 分析日志,返回判定为恶意的IP列表。 """ malicious_ips = [] ip_access_info = {} # 结构:{ip: {'sensitive_count': 0, '404_count': 0, 'total': 0}} # 计算时间窗口的起始时间点 time_window_start = datetime.now() - timedelta(minutes=TIME_WINDOW_MINUTES) try: with open(NGINX_LOG_PATH, 'r', encoding='utf-8', errors='ignore') as f: for line in f: data = parse_nginx_log_line(line) if not data: continue # 解析日志时间,并判断是否在时间窗口内 # Nginx日志时间格式: 10/May/2024:15:32:01 +0800 try: log_time_str = data['time'].split()[0] # 取日期时间部分,忽略时区 # 注意:strptime的格式符必须与日志完全匹配 log_time = datetime.strptime(log_time_str, '%d/%b/%Y:%H:%M:%S') except ValueError as e: logger.warning(f"解析时间失败: {data['time']}, 错误: {e}") continue if log_time < time_window_start: # 如果日志时间早于时间窗口起点,由于日志是按时间追加的,可以提前结束(如果日志是顺序的) # 但为了严谨,我们继续读取,因为日志文件可能被轮转或不是严格按时间排序 continue ip = data['ip'] uri = data['uri'] status = data['status'] # 初始化该IP的记录 if ip not in ip_access_info: ip_access_info[ip] = {'sensitive_count': 0, '404_count': 0, 'total': 0} ip_access_info[ip]['total'] += 1 # 检查是否访问了敏感路径 for sensitive_path in SENSITIVE_PATHS: if sensitive_path in uri: ip_access_info[ip]['sensitive_count'] += 1 break # 只要匹配一个敏感路径就计数一次 # 检查是否是404状态 if status.startswith('404'): ip_access_info[ip]['404_count'] += 1 except FileNotFoundError: logger.error(f"日志文件不存在: {NGINX_LOG_PATH}") return [] except Exception as e: logger.error(f"读取日志文件时发生未知错误: {e}") return [] # 根据阈值判定恶意IP for ip, info in ip_access_info.items(): # 规则1:访问敏感路径次数过多 if info['sensitive_count'] >= THRESHOLD_ACCESS_COUNT: malicious_ips.append(ip) logger.info(f"IP {ip} 被判定为恶意(敏感路径访问 {info['sensitive_count']} 次)") continue # 符合一条规则就加入,避免重复 # 规则2:产生大量404错误(可能是在扫描不存在的路径) if info['404_count'] >= THRESHOLD_404_COUNT: malicious_ips.append(ip) logger.info(f"IP {ip} 被判定为恶意(404错误 {info['404_count']} 次)") logger.info(f"分析完成,共发现 {len(malicious_ips)} 个可疑IP。") return malicious_ips

判定逻辑采用了两种并行规则,满足任一即触发。这比单一规则更有效,因为有的扫描器会小心翼翼地避开已知敏感路径,但依然会产生大量404;而有的则直接对管理后台进行高频撞击。阈值THRESHOLD_ACCESS_COUNTTHRESHOLD_404_COUNT需要根据你站点的实际流量进行调整。对于一个日PV几千的小站,5分钟内出现15次敏感访问已经非常可疑;而对于一个高流量站点,这个阈值可能需要调高。

4.3 封禁执行与黑名单管理

识别出恶意IP后,我们需要通过iptables将其封禁。同时,为了避免重复封禁和便于管理,我们最好将黑名单持久化存储。

def ban_ip_with_iptables(ip_list): """ 使用iptables封禁指定的IP列表。 采用在INPUT链头部插入DROP规则的方式。 """ if not ip_list: return # 读取已封禁的IP列表,避免重复操作 banned_ips = set() try: # 检查iptables规则,获取已存在的封禁IP # 这里假设我们使用一个特定的链或标记来管理,为了简单,我们检查INPUT链中已有的DROP规则 # 注意:这个方法在规则很多时可能效率不高,生产环境建议使用独立的iptables链管理 result = subprocess.run( ['sudo', 'iptables', '-L', 'INPUT', '-n', '--line-numbers'], capture_output=True, text=True, check=False ) for line in result.stdout.split('\n'): if 'DROP' in line and '0.0.0.0/0' not in line: # 简单提取IP,实际规则可能更复杂,这里仅为示例 parts = line.split() for part in parts: # 一个简单的IPv4地址匹配 if re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$', part): banned_ips.add(part) break except Exception as e: logger.error(f"读取现有iptables规则失败: {e}") for ip in ip_list: if ip in banned_ips: logger.info(f"IP {ip} 已在黑名单中,跳过。") continue # 执行封禁命令 # 在INPUT链的头部插入一条规则,丢弃来自该IP的所有数据包 cmd = ['sudo', 'iptables', '-I', 'INPUT', '1', '-s', ip, '-j', 'DROP'] try: subprocess.run(cmd, check=True) logger.warning(f"已封禁IP: {ip}") # 可选:添加日志标记,方便后续审计 # subprocess.run(['sudo', 'iptables', '-I', 'INPUT', '2', '-s', ip, '-j', 'LOG', '--log-prefix', f"BLACKLIST_DROP: "]) except subprocess.CalledProcessError as e: logger.error(f"封禁IP {ip} 失败: {e}") except Exception as e: logger.error(f"执行封禁命令时发生未知错误: {e}") def main(): logger.info("=== IP黑名单脚本开始执行 ===") malicious_ips = analyze_logs() if malicious_ips: ban_ip_with_iptables(malicious_ips) else: logger.info("未发现需要封禁的IP。") logger.info("=== IP黑名单脚本执行结束 ===\n") if __name__ == '__main__': main()

封禁函数ban_ip_with_iptables做了几件重要的事:

  1. 先尝试读取现有的iptables规则,构建一个已封禁IP的集合,避免重复添加规则,导致iptables规则链冗长。
  2. 使用iptables -I INPUT 1 -s <IP> -j DROP命令。-I INPUT 1表示在INPUT链的第1条位置插入规则,确保它优先于其他可能允许的规则。-j DROP直接丢弃数据包,不回应任何信息,让扫描器感觉像是遇到了一个“黑洞”。
  3. 添加了详细的日志记录,所有封禁操作都会记录到/var/log/ip_blacklist.log文件和标准输出中,便于事后审计和排查问题。

重要提示:直接在INPUT链操作存在一定风险。更规范的做法是创建一个自定义的链,比如BLACKLIST,将所有封禁规则放在那里,然后在INPUT链的头部跳转到这个自定义链。这样管理起来更清晰,也便于批量清空或修改黑名单规则。考虑到本文的入门导向,我们使用了直接操作INPUT链的简单方法,但在生产环境中,建议采用自定义链的方式。

5. 部署、调度与进阶优化

脚本写好了,但它不会自己运行。我们需要将其部署到服务器,并设置定时任务。

5.1 脚本部署与权限设置

  1. 保存脚本:将上面的完整代码保存为/usr/local/bin/ip_blacklist.py
  2. 赋予执行权限
    sudo chmod +x /usr/local/bin/ip_blacklist.py
  3. 测试脚本:可以先手动运行一次,检查是否有语法错误,以及日志输出是否正常。
    sudo python3 /usr/local/bin/ip_blacklist.py
    查看/var/log/ip_blacklist.log和终端输出,确认脚本能正确读取日志并执行分析。

5.2 使用Crontab设置定时任务

我们希望脚本每5分钟自动执行一次,实现近实时防护。

  1. 编辑当前用户的crontab:
    crontab -e
  2. 在文件末尾添加一行:
    */5 * * * * /usr/bin/python3 /usr/local/bin/ip_blacklist.py > /dev/null 2>&1
    这行配置表示每5分钟执行一次脚本,并将所有标准输出和错误输出重定向到/dev/null(丢弃),因为我们已经在脚本内部将重要信息记录到独立的日志文件了。

注意:确保python3的路径正确,可以使用which python3命令查看。使用/dev/null重定向是为了避免cron的邮件通知,但调试阶段可以去掉> /dev/null 2>&1,以便在/var/mail/$USER中查看任何错误输出。

5.3 进阶优化与功能扩展

基础版本已经能工作,但一个健壮的生产级系统还需要考虑更多:

1. 封禁自动过期与释放我们目前是永久封禁(直到手动移除)。更合理的做法是设置封禁时长。这可以通过两种方式实现:

  • 方式A:使用iptables-m comment模块和定时清理脚本。封禁时添加一个带有时间戳的注释:
    sudo iptables -I INPUT 1 -s 123.45.67.89 -m comment --comment "ban_$(date +%s)" -j DROP
    然后,另一个定时脚本(比如每天凌晨运行)检查所有带comment的规则,如果时间戳超过24小时(或你设定的BAN_DURATION),就删除该规则。
  • 方式B:在应用层管理。将封禁的IP和封禁时间存入一个小型数据库(如SQLite)或文件。每次分析脚本运行时,先检查“黑名单数据库”,释放那些已过期的IP(即调用iptables -D删除对应规则),然后再分析新的日志。这种方式更灵活,可以轻松实现不同IP不同封禁时长的策略。

2. 误封处理与白名单机制自动封禁难免有误伤,比如自己频繁测试后台,或者某个搜索引擎的合法爬虫(如Googlebot)触发了规则。因此,必须建立白名单机制。

  • 静态白名单:在脚本开头定义一个WHITELIST_IPS列表,包含你自己的办公IP、家庭IP、云服务商监控IP等。在判定为恶意IP后,执行封禁前,先检查该IP是否在白名单内。
  • 动态豁免:对于某些虽然触发规则但可能是合法的IP(例如,你忘记密码导致登录失败多次),可以设计一个“申诉”或“验证”环节。例如,不直接DROP,而是先将其重定向到一个验证页面(使用iptablesREDIRECT或Web应用层实现),通过验证则加入临时白名单一段时间。

3. 性能优化与日志轮转

  • 分析增量日志:每次都从头读取整个日志文件是低效的。可以记录上次分析到的日志文件位置(行号或时间戳),下次从该位置开始读取。或者,更简单的方法是,利用logrotate机制,分析完成后在日志中做一个标记,或者直接分析access.log,而历史归档的access.log.1.gz等文件则不再分析。
  • 使用更高效的数据结构:如果站点流量巨大,ip_access_info字典可能会变得很大。可以考虑使用collections.defaultdict或对IP进行聚合分析时,只保留最近时间窗口内活跃的IP,定期清理旧数据。

4. 报警与通知集成单纯的封禁还不够,知道“谁”在攻击也很重要。可以将封禁信息通过其他渠道通知你:

  • 发送邮件:使用smtplib库,当封禁了新的IP时,发送一封邮件到你的管理邮箱,包含IP、封禁时间、触发原因(敏感访问/404过多)。
  • 集成即时通讯工具:通过调用Webhook,将报警信息发送到Slack、钉钉、企业微信或飞书群中,实现实时感知。

6. 常见问题排查与操作心得

在实际部署和运行过程中,你可能会遇到以下问题。这里记录了我踩过的一些坑和对应的解决方案。

6.1 权限问题导致封禁失败

问题描述:脚本执行时报错sudo: no tty present and no askpass program specified或直接Permission denied排查与解决

  1. 检查sudoers配置:确保已按照3.1节所述,为运行脚本的用户配置了无需密码执行/sbin/iptables的权限。使用sudo visudo检查配置是否正确,注意语法。
  2. 检查命令路径:脚本中使用的命令路径必须是绝对路径。iptables通常位于/sbin//usr/sbin/。可以使用which iptables确认。
  3. 以root用户运行cron:最直接(但安全性稍低)的方法是,将定时任务添加到root用户的crontab中(sudo crontab -e),这样就不需要配置sudo免密了。

6.2 误封自己或重要服务IP

问题描述:脚本运行后,发现自己无法SSH连接服务器,或者网站监控告警。紧急处理

  1. 通过控制台登录:立即通过云服务商提供的VNC或串口控制台登录服务器。
  2. 查看并删除iptables规则
    # 列出INPUT链规则及行号 sudo iptables -L INPUT -n --line-numbers # 找到封禁自己IP的那条规则,记下行号(假设是第3行) sudo iptables -D INPUT 3 # 删除第3行规则
  3. 分析原因
    • 检查白名单:立刻将自己的IP加入脚本的WHITELIST_IPS
    • 调整阈值:可能是THRESHOLD_ACCESS_COUNTTHRESHOLD_404_COUNT设置过低,导致正常的管理操作也被判定为攻击。根据日志流量适当调高阈值。
    • 细化敏感路径:检查SENSITIVE_PATHS列表,是否包含了你自己也会频繁访问的合法API路径?将其从列表中移除或添加更精确的匹配规则(如使用正则表达式,只匹配/admin/目录下的特定危险文件)。

6.3 脚本执行但无任何封禁记录

问题描述/var/log/ip_blacklist.log中只有开始和结束的日志,没有发现恶意IP的记录。排查步骤

  1. 检查日志路径:确认NGINX_LOG_PATH变量指向了正确的、正在被写入的访问日志文件。有时Nginx配置了多个日志文件,或者使用了日志轮转。
  2. 检查时间窗口:手动查看日志文件末尾,确认最近几分钟确实有访问记录。可以临时将TIME_WINDOW_MINUTES调大(如30分钟),再次运行脚本测试。
  3. 检查判定阈值:阈值可能设置过高。可以临时将THRESHOLD_ACCESS_COUNTTHRESHOLD_404_COUNT调低到1或2,然后运行脚本,看是否能触发封禁。同时,在脚本中打印出ip_access_info字典的内容,查看每个IP的统计计数是否如预期。
  4. 检查日志格式:我们的解析函数针对的是Nginx的combined格式。如果你的Nginx使用了自定义的log_format,那么正则表达式可能无法正确匹配。需要根据实际的日志格式调整parse_nginx_log_line函数中的正则表达式。

6.4 iptables规则过多导致管理混乱

问题描述:运行一段时间后,sudo iptables -L -n输出非常长,难以管理。优化建议: 采用之前提到的自定义链方案。以下是设置步骤:

# 1. 创建一个名为 BLACKLIST 的自定义链 sudo iptables -N BLACKLIST # 2. 将自定义链的规则默认动作设为DROP(可选,也可以在最后加一条规则) # sudo iptables -A BLACKLIST -j DROP # 3. 在INPUT链的头部引用这个自定义链 sudo iptables -I INPUT 1 -j BLACKLIST

然后,修改脚本中的封禁命令,将规则添加到BLACKLIST链:

cmd = ['sudo', 'iptables', '-A', 'BLACKLIST', '-s', ip, '-j', 'DROP']

这样,所有黑名单规则都集中在BLACKLIST链里,查看和管理(如清空所有黑名单sudo iptables -F BLACKLIST)都非常方便。

6.5 个人实操心得

  1. 阈值设置是一门艺术,不是科学:初始阈值不要设得太激进。可以先设置一个较高的值(比如敏感访问30次,404错误50次),让脚本跑几天,观察日志和封禁记录。然后根据/var/log/ip_blacklist.log中记录的“嫌疑IP”的访问模式,逐步调低阈值到一个合理的水平。对于个人小站,5分钟内10-20次敏感访问已经非常可疑。
  2. 日志是你的眼睛:定期(比如每周)查看/var/log/ip_blacklist.log,不仅看封禁了谁,更要看那些“差点”被封禁的IP(访问次数接近阈值)。这能帮你发现新的攻击模式,从而更新你的SENSITIVE_PATHS列表或判定规则。
  3. 组合拳效果更佳:这个IP黑名单脚本是服务器安全的一环,但不应是唯一一环。务必确保你的Web应用程序本身是安全的(及时更新、使用强密码、关闭不必要的服务),并考虑启用Nginx的limit_req模块来限制请求频率,以及使用fail2ban这类更成熟的工具来防护SSH等服务的暴力破解。多层次的防御才能构成有效的安全体系。
  4. 保持敬畏,谨慎操作:防火墙规则是服务器的大门卫士,错误的规则可能导致服务完全不可用。任何对生产环境的修改,尤其是防火墙规则,都建议先在测试环境验证。修改脚本或规则后,第一次运行可以加上--dry-run(模拟运行)参数,只打印将要执行的操作而不实际执行,确认无误后再去掉该参数。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询