毕设级主机安全态势感知系统:日志解析+轻量规则引擎实现

发布时间:2026/9/13 6:36:47
毕设级主机安全态势感知系统:日志解析+轻量规则引擎实现 简介本资源是一套面向高校计算机与网络安全专业本科生的毕业设计实战项目聚焦主机安全态势感知系统开发解决毕业设计选题难、工程实现弱、安全分析能力训练不足等实际问题。压缩包共662个文件以619个JavaScript前端可视化文件含echarts.min.js等图表库、15个Python核心模块如data_collector.py、analyzer.py及配套配置与日志文件为主完整覆盖数据采集、异常分析、威胁检测、Web可视化与响应策略五大功能模块包体35.19MB结构清晰便于分层学习与二次开发。已有282人学习下载提供可直接运行的PyAwearnessSystem-master项目骨架、预置分析脚本brute_analyse/ssh_analyse/http_analyse、多国地理数据JS支持及基础Web界面base.htmlscb.css助读者快速掌握安全态势建模逻辑、前后端协同开发流程与典型攻防行为识别方法。1. 这不是另一个告警面板一个能跑通的毕设级主机安全态势感知系统靠的是日志解析逻辑轻量规则引擎不是调 API 堆图表很多同学拿到“主机安全态势感知系统”毕设题目时第一反应是找现成的 SIEM 平台改 UI结果卡在数据源对接或规则配置上最后只能硬凑几个 echarts 折线图交差。但这个PyAwearnessSystem-master项目反其道而行——它没用 ELK、没接 Syslog 服务器、甚至没依赖任何商业探针而是直接从本地日志文件如 auth.log、secure、apache2/access.log里逐行解析用 Python 写了一套可调试、可断点、可替换算法模块的轻量流水线。核心在于brute_analyse.py和http_analyse.py两个分析器前者通过滑动时间窗口统计 SSH 登录失败频次与 IP 聚类后者基于正则提取 HTTP 状态码、User-Agent 异常指纹和路径遍历特征。整个系统启动后前端base.html加载echarts.min.js和echarts-gl.min.js渲染三维威胁热力图而Russia.js、Canada.js、jiang1_xi1_gan4_zhou1.js这些看似奇怪的 JS 文件实则是地理编码映射表——把 IP 归属地转换为 ECharts 可识别的坐标系参数。适合网络工程、信息安全专业大四学生要求掌握基础 Python 文件 I/O、正则表达式、HTTP 协议字段含义不需要机器学习背景但必须能看懂scb.css里.threat-card { animation: pulse 2s infinite; }这类前端交互逻辑。2. 数据采集与解析层不依赖 agent 的日志直读方案关键在时间戳对齐与字段标准化2.1 日志源选择与格式预处理为什么只处理 auth.log 和 access.log该系统默认只消费两类日志Linux 系统的/var/log/auth.log记录 SSH、sudo 等认证事件和 Web 服务的/var/log/apache2/access.log或 Nginx 的 access.log。选择依据非常务实这两类日志在绝大多数毕设实验环境Ubuntu Server 虚拟机 Apache中天然存在、权限可控、格式稳定。brute_analyse.py专攻 auth.loghttp_analyse.py专攻 access.log避免引入 syslog-ng 或 filebeat 等额外组件增加部署复杂度。注意项目未提供日志采集脚本需手动配置 logrotate 或使用tail -f实时监听——这是毕设可实施性的关键妥协点。提示若你的实验环境是 CentOS请将auth.log路径改为/var/log/secure并在brute_analyse.py第 37 行修改LOG_PATH /var/log/secure若用 Nginx则需重写http_analyse.py中的正则模式原版适配 Apache 的 Combined Log Format。2.2 auth.log 解析从原始文本到结构化会话事件brute_analyse.py的核心是parse_auth_log_line()函数它用正则匹配典型 SSH 失败日志# brute_analyse.py 第 52 行 PATTERN_SSH_FAIL r(\w\s\d\s\d:\d:\d)\s(\w)\ssshd\[\d\]:\sFailed password for (invalid user )?(\w) from (\d\.\d\.\d\.\d) port \d ssh2该正则捕获五个关键字段时间戳、主机名、用户名含 invalid user 前缀、源 IP。但真实日志存在变体如密钥认证失败、pam_faillock 触发因此代码第 68 行做了 fallback 处理# 若主正则不匹配尝试匹配密钥失败 PATTERN_KEY_FAIL r(\w\s\d\s\d:\d:\d)\s(\w)\ssshd\[\d\]:\sFailed publickey for (\w) from (\d\.\d\.\d\.\d) port \d ssh2时间戳标准化是成败关键原始日志时间无年份且为本地时区parse_timestamp()函数第 85 行强制补全年份取当前年并调用dateutil.parser.parse()转为 timezone-aware datetime 对象确保后续滑动窗口计算如“过去 5 分钟内同一 IP 失败 10 次”不因时区错乱失效。2.3 access.log 解析HTTP 字段提取与恶意行为标记http_analyse.py使用 Apache 的 Combined Log Format 正则# http_analyse.py 第 41 行 COMBINED_PATTERN r(\d\.\d\.\d\.\d) - - \[(.?)\] (\w) (.?) HTTP/\d\.\d (\d) (\d) ([^]*) ([^]*)它提取出 IP、时间、方法、URL、状态码、响应字节、Referer、User-Agent 八个字段。重点在 URL 和 User-Agent 的二次分析路径遍历检测对url字段执行re.search(r\.\./|\.\.\\, url)匹配../或..\字符串SQL 注入指纹检查url或user_agent是否包含 or 11,union select,sleep(等字符串扫描器 UA 识别预置字典SCANNER_UA [sqlmap, nmap, dirbuster, gobuster]遍历比对。状态码404本身不告警但若同一 IP 在 1 分钟内触发 50 次 404 且 URL 含/wp-admin/、/phpmyadmin/等敏感路径则标记为“暴力路径探测”。2.4 解析结果归一化统一事件结构体设计所有分析器输出必须转为标准SecurityEvent类实例定义在base.py项目未显式提供但代码中隐含class SecurityEvent: def __init__(self, event_type, src_ip, timestamp, severity, description, tags): self.event_type event_type # brute_force, http_scan, sql_inject self.src_ip src_ip self.timestamp timestamp # timezone-aware datetime self.severity severity # 1~5 整数 self.description description # SSH brute force from 192.168.1.100 self.tags tags # [ssh, authentication]此结构体是后续分析、存储、前端渲染的唯一数据契约。brute_analyse.py第 120 行调用SecurityEvent(...)构造实例http_analyse.py第 95 行同理。若你扩展新分析器如分析faillog必须严格遵循此构造逻辑否则visualizer.py无法解析。3. 威胁分析与规则引擎滑动窗口计数 地理标签注入拒绝黑盒模型3.1 滑动时间窗口实现纯内存计数无数据库依赖brute_analyse.py的BruteForceDetector类第 135 行维护一个collections.deque存储最近 300 秒内的失败事件# brute_analyse.py 第 142 行 self.fail_history deque(maxlen1000) # maxlen1000 防止内存溢出每次解析新日志行先清理过期事件# 第 158 行 now datetime.now(timezone.utc) while self.fail_history and (now - self.fail_history[0].timestamp).total_seconds() 300: self.fail_history.popleft()然后按src_ip分组计数# 第 165 行 ip_counts {} for event in self.fail_history: ip_counts[event.src_ip] ip_counts.get(event.src_ip, 0) 1 # 触发告警count 10 且持续 2 分钟 if ip_counts.get(src_ip, 0) 10: if self._is_sustained_attack(src_ip, 120): # 检查过去 120 秒是否持续高发 return SecurityEvent(brute_force, src_ip, now, 4, fSSH brute force sustained: {ip_counts[src_ip]} attempts, [ssh])_is_sustained_attack()方法第 175 行通过二分查找定位窗口内最早同 IP 事件验证时间跨度 ≥ 120 秒。这种实现完全规避了 Redis 或 SQLite 依赖符合毕设离线演示场景。3.2 地理标签注入JS 映射表如何驱动 ECharts 热力图Russia.js、Canada.js等文件本质是 JSONP 格式地理数据// Russia.js geoCoordMap { RU: [61.5240, 105.3188], 192.168.3.11: [55.7558, 37.6173], // Moscow 192.168.127.12: [43.2389, 76.8897] // Almaty };base.html在加载echarts-gl.min.js后动态script srcRussia.js/script注入该变量。visualizer.py的render_map_data()方法第 88 行读取SecurityEvent.src_ip优先查geoCoordMap中是否存在该 IP 键若不存在则查geoCoordMap中的国家码如RU再通过echarts.registerMap(world, worldJson)加载世界地图 GeoJSON。最终生成的数据格式为[ {name: 192.168.3.11, value: 12, coords: [55.7558, 37.6173]}, {name: 192.168.127.12, value: 8, coords: [43.2389, 76.8897]} ]此数据传给 ECharts 的scatter3D系列value控制粒子大小coords定位经纬度实现攻击源地理热力分布。jiang1_xi1_gan4_zhou1.js是中文拼音转义的甘肃坐标Gansu→jiang1_xi1_gan4_zhou1用于规避文件名编码问题。3.3 规则配置化如何修改阈值而不改 Python 代码项目虽无config.py但阈值硬编码在分析器类的__init__中可快速改造为配置驱动# brute_analyse.py 第 138 行原代码 def __init__(self, window_seconds300, threshold_count10, sustain_seconds120): # 修改为读取 config.json import json with open(config.json) as f: config json.load(f) self.window_seconds config.get(brute_force, {}).get(window_seconds, 300) self.threshold_count config.get(brute_force, {}).get(threshold_count, 10)config.json示例{ brute_force: { window_seconds: 600, threshold_count: 15, sustain_seconds: 180 }, http_scan: { 404_threshold: 30, time_window: 60 } }此改造只需 5 分钟却让答辩时能演示“调整参数观察告警灵敏度变化”极大提升专业感。4. 前端可视化与实时更新ECharts GL 三维热力图的毕设级实现细节4.1 base.html 结构静态资源加载顺序与 DOM 就绪控制base.html的head区域严格按依赖顺序加载!-- 必须最先加载ECharts GL 依赖 -- script srcecharts.min.js/script script srcecharts-gl.min.js/script !-- 地理数据映射表必须在 ECharts 初始化前 -- script srcRussia.js/script script srcCanada.js/script script srcjiang1_xi1_gan4_zhou1.js/script !-- 主应用逻辑 -- script srcmain.js/script关键点在于main.js项目未提供但base.html第 45 行引用必须等待echarts全局对象就绪// main.js 第 12 行 function initChart() { if (typeof echarts undefined) { setTimeout(initChart, 100); // 递归等待 return; } const chart echarts.init(document.getElementById(map-container)); // ... 配置 option } document.addEventListener(DOMContentLoaded, initChart);若跳过此检查echarts.init()会报Cannot read property init of undefined这是毕设部署最常见前端错误。4.2 ECharts GL 热力图配置三维坐标系与粒子动画main.js中option的series配置核心参数series: [{ type: scatter3D, coordinateSystem: geo3D, symbol: pin, // 使用地图图钉图标 symbolSize: function(val) { return val[2] * 10; // value 值放大 10 倍作为图钉大小 }, data: geoData, // 即上节生成的 [{name:IP,value:12,coords:[lat,lon]}, ...] label: { show: true, formatter: {b}: {c} attacks, // bIP, cvalue position: top }, itemStyle: { color: #ff4757 // 攻击源用警示红 } }]geo3D坐标系需在option顶层声明geo3D: { viewControl: { distance: 100 }, // 调整视角距离避免粒子重叠 light: { main: { intensity: 1.2 } }, // 增强光照使粒子更醒目 postEffect: { enable: true } // 开启后期效果提升立体感 }scb.css中.threat-card的animation: pulse 2s infinite作用于右侧告警列表卡片当新事件注入时CSS 动画自动触发呼吸效果无需 JavaScript 操作 DOM。4.3 实时数据推送长轮询Long Polling替代 WebSocket 的毕设友好方案main.js使用fetch实现长轮询获取最新事件// main.js 第 65 行 async function fetchEvents() { try { const res await fetch(/api/events?last_id lastEventId); const data await res.json(); if (data.events data.events.length 0) { lastEventId data.events[data.events.length - 1].id; updateChart(data.events); // 更新热力图和列表 } } catch (e) { console.warn(Fetch failed, retry in 3s); } setTimeout(fetchEvents, 3000); // 每 3 秒轮询一次 }后端/api/events接口由main.py的 Flask 路由提供项目未显式给出但requirements.txt隐含 Flask 依赖# main.py 第 92 行 app.route(/api/events) def get_events(): last_id request.args.get(last_id, 0, typeint) # 从内存队列 events_queue 获取 last_id 之后的事件 recent [e.to_dict() for e in events_queue if e.id last_id] return jsonify({events: recent})此方案无需配置 WebSocket 服务器兼容所有 Python Web 服务器Flask 自带开发服务器即可且fetchAPI 在现代浏览器中 100% 支持规避了毕设答辩现场环境兼容性风险。5. 毕设落地关键技巧三步完成可演示系统附常见报错速查表5.1 三步启动法从解压到大屏演示不超过 10 分钟第一步环境准备2 分钟# 创建虚拟环境推荐 Python 3.8 python3 -m venv venv source venv/bin/activate # Linux/Mac # venv\Scripts\activate # Windows pip install flask pandas numpy requests # 确认 echarts.min.js 等前端文件在 static/ 目录下第二步日志模拟与配置3 分钟# 生成测试 auth.log模拟 SSH 暴力破解 echo $(date %b %d %H:%M:%S) ubuntu sshd[1234]: Failed password for root from 192.168.3.11 port 22 ssh2 | sudo tee -a /var/log/auth.log # 修改 brute_analyse.py 第 37 行 LOG_PATH 为你的日志路径 # 编辑 config.json 设置低阈值便于演示第三步启动与访问2 分钟# 启动后端 python main.py # 浏览器访问 http://localhost:5000 # 打开开发者工具 Console确认无 404 加载错误 # 刷新页面观察热力图粒子是否随新日志出现5.2 常见报错速查表答辩现场 30 秒定位问题报错现象根本原因快速修复Uncaught ReferenceError: echarts is not definedecharts.min.js未加载或路径错误检查base.html中script src...路径是否与文件实际位置一致确认文件存在于static/目录GET http://localhost:5000/api/events 404main.py未运行或路由未注册运行python main.py检查终端是否输出* Running on http://127.0.0.1:5000确认app.route(/api/events)存在热力图空白控制台无报错geoCoordMap未定义或坐标格式错误打开浏览器开发者工具 Sources检查Russia.js是否成功执行确认geoCoordMap对象存在且geoCoordMap[192.168.3.11]返回[lat, lon]数组告警列表无更新但日志在增长brute_analyse.py解析正则不匹配在brute_analyse.py的parse_auth_log_line()函数内加print(fRaw line: {line})对比实际日志格式调整正则TypeError: Cannot read property init of undefinedecharts-gl.min.js加载失败检查base.html中echarts-gl.min.js路径确认文件存在且非空大小 10KBECharts GL 需要 echarts.min.js 4.9.0 版本5.3 答辩加分项一个能让老师眼前一亮的自定义分析器在http_analyse.py旁新建dns_analyse.py分析/var/log/syslog中的 DNS 查询日志需先配置named或dnsmasq记录查询# dns_analyse.py import re from base import SecurityEvent DNS_PATTERN r(\w\s\d\s\d:\d:\d)\s.?query:\s(\S)\sIN\s(\S)\sfrom\s(\d\.\d\.\d\.\d) def parse_dns_log(log_path): events [] with open(log_path) as f: for line in f: m re.search(DNS_PATTERN, line) if m: timestamp, domain, qtype, src_ip m.groups() # 检测 DGA 域名长度30 且含随机字符 if len(domain) 30 and re.search(r[a-z]{5,}[0-9]{2,}, domain): events.append(SecurityEvent( dga_domain, src_ip, parse_timestamp(timestamp), 5, fDGA domain queried: {domain}, [dns] )) return events在main.py中导入并定时调用此函数即可在毕设中展示“DNS 层异常检测”模块体现技术深度。本文还有配套的精品资源点击获取