30 分钟搞定:用 Python 写一个简易防火墙日志分析工具
30 分钟搞定:用 Python 写一个简易防火墙日志分析工具

“每天看防火墙日志像翻天书,满屏的DROP/ACCEPT记录,想找‘谁在频繁扫 22 端口’要翻半小时;想统计‘被拦截最多的 IP’,手动计数又容易错”—— 这是运维、开发转安全时,处理防火墙日志的常见困境。
其实用 Python 写一个简易分析工具只需 30 分钟,核心功能聚焦 “提取关键信息 + 统计高频风险”,不用复杂框架,依赖库仅需re(正则,Python 自带)、collections(统计)和matplotlib(可视化,可选)。本文从 “日志解析逻辑→分步编码→实战验证” 全程拆解,代码可直接复制运行,还支持自定义日志格式,帮你快速从 “手动翻日志” 升级为 “自动化分析”。
一、工具核心定位:30 分钟能实现的 3 个实用功能
为确保 “快速落地”,工具不追求全功能,聚焦防火墙日志分析的高频需求:
-
日志解析:从原始日志中提取 “时间、源 IP、目的端口、动作(ACCEPT/DROP)”4 个核心字段(覆盖 80% 分析场景);
-
风险统计:
-
统计 “被拦截(DROP)次数最多的前 10 个源 IP”(定位攻击源);
-
筛选 “访问高危端口(22/3389/8080)的请求”(聚焦敏感端口访问);
- 结果输出:生成文本报告 + 可选可视化图表(柱状图),结果直观易读。
适配场景:默认支持 Linux iptables 日志(最常用),文末附 “适配 UFW / 华为防火墙日志” 的修改方法,转行用户可根据实际环境调整。
二、环境准备:5 分钟搭好开发环境
无需复杂配置,Python3.8 + 即可,仅需安装 1 个可选依赖(可视化用):
1. 环境清单
| 工具 / 库 | 作用 | 安装说明 |
|---|---|---|
| Python 3.8+ | 代码运行基础环境 | 官网下载,勾选 “Add Python to PATH” |
| re 库 | 正则提取日志关键字段 | Python 自带,无需安装 |
| collections 库 | 统计 IP 出现次数、动作分布 | Python 自带,无需安装 |
| matplotlib 库 | 生成可视化图表(可选) | 安装命令:pip install matplotlib |
2. 准备日志文件
以 Linux iptables 日志为例,默认路径为/var/log/iptables.log(若没有,可手动生成测试日志):
- 测试日志样例(iptables 日志格式):
Oct 29 10:05:23 localhost kernel: [12345.678901] IPTables-Dropped: IN=eth0 OUT= MAC=00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd SRC=192.168.1.100 DST=192.168.1.200 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=54321 PROTO=TCP SPT=56789 DPT=22 WINDOW=14600 RES=0x00 SYN URGP=0
Oct 29 10:06:30 localhost kernel: [12356.123456] IPTables-Accepted: IN=eth0 OUT= MAC=00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd SRC=192.168.1.101 DST=192.168.1.200 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=12345 PROTO=TCP SPT=45678 DPT=80 WINDOW=14600 RES=0x00 SYN URGP=0
- 获取真实日志:若有 Linux 服务器,直接复制/var/log/iptables.log到本地;若无,将上述样例保存为firewall.log(测试用)。
三、分步编码:20 分钟实现核心功能
工具分 3 个模块编写,每个模块功能独立,带详细注释,复制即可运行,可根据需求灵活调整。
模块 1:日志解析(核心!提取关键字段)
用正则表达式匹配日志中的 “时间、源 IP、目的端口、动作”,适配 iptables 日志格式,新手可根据自身日志格式调整正则表达式。
import re
from datetime import datetime
from collections import Counter
def parse_firewall_log(log_path):
"""
解析防火墙日志,提取关键字段
参数:log_path - 防火墙日志文件路径(如"firewall.log")
返回:parsed_data - 解析后的数据列表(每个元素是字典,含time/ip/dport/action)
"""
parsed_data = []
# 正则表达式:匹配iptables日志中的关键字段(可根据日志格式调整)
# 解释:
# (?P<time>\w+ \d+ \d+:\d+:\d+) :匹配时间(如Oct 29 10:05:23)
# (?P<action>ACCEPT|DROP) :匹配动作(ACCEPT或DROP,注意日志中可能是IPTables-Accepted,需对应)
# (?P<src_ip>\d+\.\d+\.\d+\.\d+) :匹配源IP
# (?P<dst_port>\d+) :匹配目的端口(DPT字段)
log_pattern = re.compile(
r"(?P<time>\w+ \d+ \d+:\d+:\d+).*IPTables-(?P<action>\w+):.*SRC=(?P<src_ip>\d+\.\d+\.\d+\.\d+).*DPT=(?P<dst_port>\d+)"
)
# 读取日志文件
try:
with open(log_path, "r", encoding="utf-8") as f:
for line_num, line in enumerate(f, 1):
line = line.strip()
if not line:
continue # 跳过空行
# 匹配日志字段
match = log_pattern.search(line)
if match:
# 提取字段并处理
log_time = match.group("time")
# 转换时间格式(便于后续排序,如"Oct 29 10:05:23"→"2025-10-29 10:05:23",默认年份为当前年)
current_year = datetime.now().year
formatted_time = datetime.strptime(f"{current_year} {log_time}", "%Y %b %d %H:%M:%S").strftime("%Y-%m-%d %H:%M:%S")
# 组装解析后的数据
parsed_data.append({
"time": formatted_time,
"src_ip": match.group("src_ip"),
"dst_port": int(match.group("dst_port")), # 端口转为整数,便于后续筛选
"action": match.group("action").upper() # 统一转为大写(如Accepted→ACCEPT)
})
else:
# 日志格式不匹配,打印行号提醒(便于调试)
print(f"警告:第{line_num}行日志格式不匹配,跳过:{line}")
print(f"\n✅ 日志解析完成,共提取{len(parsed_data)}条有效记录")
return parsed_data
except FileNotFoundError:
print(f"❌ 日志文件不存在:{log_path}")
return []
except Exception as e:
print(f"❌ 解析日志出错:{str(e)}")
return []
模块 2:风险统计(聚焦高频攻击与高危端口)
基于解析后的数据,实现 “攻击 IP 统计”“高危端口筛选”,用Counter快速统计频次,代码简洁高效。
def analyze_firewall_data(parsed_data):
"""
分析解析后的防火墙数据,生成统计结果
参数:parsed_data - 模块1返回的解析数据列表
返回:analysis_result - 分析结果字典(含ip_stats/port_stats/action_stats)
"""
if not parsed_data:
return {"error": "无有效数据可分析"}
# 1. 统计源IP出现次数(按动作区分,重点看DROP)
drop_ips = [item["src_ip"] for item in parsed_data if item["action"] == "DROP"]
accept_ips = [item["src_ip"] for item in parsed_data if item["action"] == "ACCEPT"]
ip_stats = {
"drop_top10": Counter(drop_ips).most_common(10), # DROP次数前10的IP
"accept_top10": Counter(accept_ips).most_common(10), # ACCEPT次数前10的IP
"total_drop": len(drop_ips), # 总拦截次数
"total_accept": len(accept_ips) # 总允许次数
}
# 2. 筛选高危端口访问(常见高危端口:22=SSH,3389=RDP,8080=Web管理,可自定义)
high_risk_ports = {22, 3389, 8080, 445} # 可根据需求添加/删除
high_risk_records = [
item for item in parsed_data
if item["dst_port"] in high_risk_ports
]
# 统计高危端口访问的IP分布
high_risk_ip_stats = Counter([item["src_ip"] for item in high_risk_records])
port_stats = {
"high_risk_records": high_risk_records, # 高危端口访问记录
"high_risk_ip_top10": high_risk_ip_stats.most_common(10), # 访问高危端口前10的IP
"total_high_risk": len(high_risk_records) # 高危端口访问总次数
}
# 3. 统计动作分布(ACCEPT/DROP比例)
action_stats = Counter([item["action"] for item in parsed_data])
return {
"ip_stats": ip_stats,
"port_stats": port_stats,
"action_stats": action_stats,
"error": None
}
模块 3:结果输出(生成报告 + 可视化)
支持 “文本报告” 和 “可视化图表” 两种输出方式,文本报告便于保存,图表更直观,用户可按需选择。
import matplotlib.pyplot as plt
def generate_report(analysis_result, output_path="firewall_analysis_report.txt"):
"""
生成文本格式的分析报告
参数:analysis_result - 模块2返回的分析结果,output_path - 报告保存路径
"""
if analysis_result.get("error"):
print(f"❌ 生成报告失败:{analysis_result['error']}")
return
ip_stats = analysis_result["ip_stats"]
port_stats = analysis_result["port_stats"]
action_stats = analysis_result["action_stats"]
# 构建报告内容
report_content = f"""# 防火墙日志分析报告
生成时间:{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
==========================================================================
## 一、整体统计
- 总允许访问(ACCEPT):{ip_stats['total_accept']} 次
- 总拦截访问(DROP):{ip_stats['total_drop']} 次
- 高危端口访问(22/3389/8080/445):{port_stats['total_high_risk']} 次
- 动作分布:{dict(action_stats)}
## 二、拦截IP统计(TOP 10)
{'IP地址':<15} {'拦截次数':<10}
{'-'*25}
"""
# 添加DROP TOP10 IP
for ip, count in ip_stats["drop_top10"]:
report_content += f"{ip:<15} {count:<10}\n"
if not ip_stats["drop_top10"]:
report_content += "无拦截IP记录\n"
# 添加高危端口访问统计
report_content += f"""
## 三、高危端口访问统计(TOP 10 IP)
高危端口:22(SSH)、3389(RDP)、8080(Web管理)、445(SMB)
{'IP地址':<15} {'访问次数':<10}
{'-'*25}
"""
for ip, count in port_stats["high_risk_ip_top10"]:
report_content += f"{ip:<15} {count:<10}\n"
if not port_stats["high_risk_ip_top10"]:
report_content += "无高危端口访问记录\n"
# 保存报告到文件
try:
with open(output_path, "w", encoding="utf-8") as f:
f.write(report_content)
print(f"\n✅ 文本报告已保存至:{output_path}")
except Exception as e:
print(f"❌ 保存报告失败:{str(e)}")
def plot_visualization(analysis_result, output_img="firewall_analysis.png"):
"""
生成可视化图表(柱状图),可选功能
参数:analysis_result - 分析结果,output_img - 图表保存路径
"""
if analysis_result.get("error"):
print(f"❌ 生成图表失败:{analysis_result['error']}")
return
ip_stats = analysis_result["ip_stats"]
action_stats = analysis_result["action_stats"]
# 设置中文字体(避免乱码)
plt.rcParams['font.sans-serif'] = ['WenQuanYi Zen Hei', 'SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建2个子图:动作分布 + DROP TOP10 IP
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
# 子图1:动作分布(饼图更直观)
actions = list(action_stats.keys())
counts = list(action_stats.values())
colors = ['#2E8B57', '#DC143C'] # ACCEPT绿色,DROP红色
ax1.pie(counts, labels=actions, autopct='%1.1f%%', colors=colors, startangle=90)
ax1.set_title('防火墙动作分布(ACCEPT/DROP)')
# 子图2:DROP TOP10 IP(柱状图)
drop_ips = [ip for ip, _ in ip_stats["drop_top10"]]
drop_counts = [count for _, count in ip_stats["drop_top10"]]
ax2.barh(range(len(drop_ips)), drop_counts, color='#DC143C')
ax2.set_yticks(range(len(drop_ips)))
ax2.set_yticklabels(drop_ips)
ax2.set_xlabel('拦截次数')
ax2.set_title('拦截次数TOP10 IP')
ax2.grid(axis='x', alpha=0.3)
# 调整布局并保存
plt.tight_layout()
plt.savefig(output_img, dpi=100, bbox_inches='tight')
print(f"✅ 可视化图表已保存至:{output_img}")
模块 4:工具入口(一键运行)
整合上述模块,用户只需修改LOG_PATH为自己的日志路径,运行即可完成分析。
def main():
# --------------------------
# 配置参数(用户只需改这里!)
LOG_PATH = "firewall.log" # 日志文件路径(本地测试用)
# LOG_PATH = "/var/log/iptables.log" # Linux服务器实际路径
REPORT_PATH = "firewall_analysis_report.txt" # 报告保存路径
IMG_PATH = "firewall_analysis.png" # 图表保存路径(可选)
# --------------------------
# 1. 解析日志
parsed_data = parse_firewall_log(LOG_PATH)
if not parsed_data:
return
# 2. 分析数据
analysis_result = analyze_firewall_data(parsed_data)
if analysis_result.get("error"):
print(analysis_result["error"])
return
# 3. 生成报告
generate_report(analysis_result, REPORT_PATH)
# 4. 生成可视化图表(可选,注释掉则不生成)
plot_visualization(analysis_result, IMG_PATH)
print("\n🎉 防火墙日志分析工具运行完成!")
if __name__ == "__main__":
main()
四、实战验证:5 分钟完成分析(附结果解读)
按以下步骤操作,5 分钟内即可看到分析结果,新手可跟着做:
步骤 1:准备日志文件
将测试日志(前文的 iptables 样例)保存为firewall.log,放在与 Python 脚本同一文件夹。
步骤 2:修改配置参数
打开脚本,将LOG_PATH改为"firewall.log"(本地测试),其他参数默认即可。
步骤 3:运行脚本
打开终端,进入脚本所在目录,执行命令:
python firewall_analyzer.py
步骤 4:解读结果
1. 终端输出(进度提示)
✅ 日志解析完成,共提取2条有效记录
✅ 文本报告已保存至:firewall_analysis_report.txt
✅ 可视化图表已保存至:firewall_analysis.png
🎉 防火墙日志分析工具运行完成!
2. 文本报告(关键内容)
打开firewall_analysis_report.txt,核心信息如下:
# 防火墙日志分析报告
生成时间:2025-10-29 15:30:00
==========================================================================
## 一、整体统计
- 总允许访问(ACCEPT):1 次
- 总拦截访问(DROP):1 次
- 高危端口访问(22/3389/8080/445):1 次(源IP 192.168.1.100 访问 22端口)
- 动作分布:{'DROP': 1, 'ACCEPT': 1}
## 二、拦截IP统计(TOP 10)
IP地址 拦截次数
-------------------------
192.168.1.100 1
## 三、高危端口访问统计(TOP 10 IP)
高危端口:22(SSH)、3389(RDP)、8080(Web管理)、445(SMB)
IP地址 访问次数
-------------------------
192.168.1.100 1
3. 可视化图表
打开firewall_analysis.png,可看到:
-
左侧饼图:ACCEPT 和 DROP 各占 50%(因测试数据只有 2 条);
-
右侧柱状图:192.168.1.100 被拦截 1 次,清晰定位攻击 IP。
五、避坑指南:新手 3 个高频问题
1. 坑 1:日志格式不匹配,解析出 0 条记录
原因:正则表达式与实际日志格式不符(比如日志中动作是 “IPTables-Dropped” 而非 “DROP”);
解决方案:
-
先打印 1 条原始日志,比如:print(line),观察字段格式;
-
调整log_pattern正则,例如若动作是 “IPTables-Dropped”,将正则中的(?PACCEPT|DROP)改为(?PDropped|Accepted),并在后续代码中统一转为大写(如action = match.group(“action”).upper().replace(“DROPPED”, “DROP”))。
2. 坑 2:matplotlib 中文乱码,图表显示方框
原因:缺少中文字体;
解决方案:
-
方案 1:改用英文标题(如ax1.set_title(‘Firewall Action Distribution’));
-
方案 2:安装中文字体(如 WenQuanYi),或在代码中指定系统已有的中文字体(如plt.rcParams[‘font.sans-serif’] = [‘SimHei’],需 Windows 系统有黑体)。
3. 坑 3:Linux 服务器无权限读取日志文件
原因:/var/log/iptables.log默认只有 root 可读;
解决方案:用 sudo 运行脚本:sudo python3 firewall_analyzer.py,或复制日志到普通用户目录:sudo cp /var/log/iptables.log ~/ && sudo chmod 644 ~/iptables.log。
六、扩展方向:让工具更实用(按需升级)
- 支持更多防火墙日志格式:
-
UFW 日志(Ubuntu 默认防火墙):调整正则匹配[UFW BLOCK]或[UFW ALLOW];
-
华为防火墙日志:匹配action="drop"或action=“permit”,字段名可能是source-ip而非SRC。
-
增加邮件告警:用smtplib库,当 “某 IP 拦截次数超过 10 次” 时自动发邮件通知(适合运维监控)。
-
多日志文件合并分析:修改parse_firewall_log函数,支持遍历/var/log/iptables.log.*(压缩日志),用gzip库解压后解析。
最后:30 分钟的工具,解决 80% 的日志分析需求
这个工具虽简易,但覆盖了防火墙日志分析的核心场景:定位攻击 IP、筛选高危端口、生成可追溯的报告。对于转行安全的用户,你不需要一开始就写复杂工具 —— 先实现 “能解决实际问题的小功能”,再逐步迭代升级。
现在就行动:找一份真实的防火墙日志,修改脚本中的LOG_PATH,运行后看看谁在频繁访问你的服务器 22 端口 —— 当你用自己写的工具找出第一个攻击 IP 时,你就已经迈出了 “自动化安全分析” 的第一步。
网络安全学习资料分享
为了帮助大家更好的学习网络安全,我把我从一线互联网大厂薅来的网络安全教程及资料分享给大家,里面的内容都是适合零基础小白的笔记和资料,不懂编程也能听懂、看懂,朋友们如果有需要这套网络安全教程+进阶学习资源包,可以扫码下方二维码限时免费领取(如遇扫码问题,可以在评论区留言领取哦)~


更多推荐


所有评论(0)