ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于主机安全态势感知系统的源码解析与可视化大屏实现

基于主机安全态势感知系统的源码解析与可视化大屏实现 简介基于主机安全态势感知系统的毕业设计完整方案面向网络与信息安全、计算机科学等相关专业适合作为毕设、课设或项目演示。资源包共663个文件、约35.19MB包含619个JavaScript文件构建的前端可视化界面与ECharts动态图表15个Python脚本实现后端威胁检测逻辑同时提供暴力破解分析、HTTP异常分析、SSH攻击分析等专项模块配合IP地理数据库、JSON配置、CSS样式、说明文档及单页面入口形成从数据解析、威胁识别到大屏展示的完整安全分析链路。项目源码已通过导师认可答辩评审分达95分属于高分毕设案例代码经测试运行稳定可直接部署演示也便于在此基础上扩展新的检测规则或可视化功能。目前已有111人学习浏览适合需要完整项目参考、快速搭建安全态势感知系统或希望深入理解攻击检测与可视化实现的学习者。1. 主机安全态势感知系统这份毕设源码里到底藏了多少东西拿到一个名为「基于主机安全态势感知系统」的毕设项目压缩包第一眼往往会懵一堆JS文件、两个没有扩展名的分析模块、一个base.html看不出门道。这套系统的本质不是普通的管理后台而是一条「日志分析 可视化大屏」的流水线后端读入登录日志与HTTP访问日志用brute_analyse和http_analyse跑出暴力破解与异常请求前端再靠ECharts、地图JS把攻击来源渲染成一张能演示的大屏。对网络安全、人工智能、物联网方向的学生来说这是少见的能讲清楚、能演示、能二次扩展的毕业设计源码。很多人把它当黑匣子其实拆开以后会发现难的不是算法而是把日志格式、时间窗口、地图注册这些边角料对齐。2. 系统架构与核心模块拆解从日志到告警的分析链路2.1 先捋清四层数据链路主机安全态势感知这类系统骨架通常是四层数据接入层、分析层、存储层、展示层。数据接入层负责把原始日志读进来两类日志最典型一类是SSH/远程登录类认证日志记录每次登录尝试另一类是HTTP访问日志即Web服务留下的access log。brute_analyse和http_analyse两个模块正好分别对应这两类日志的解析入口。从文件命名能看出作者刻意把两个分析模块拆开、互不依赖这个设计在毕设里很讨巧答辩时可以清楚地说“哪段代码负责什么”。分析层是核心brute_analyse管暴力破解检测http_analyse管HTTP异常请求检测两者都是规则引擎思路不涉及机器学习运行快、可解释性强。存储层一般用MySQL或SQLite保存告警结果方便前端查询和回放。展示层就是base.html配合ECharts系列JS文件渲染出来的大屏。2.2 暴力破解检测brute_analyse的窗口与阈值brute_analyse的核心逻辑一句话说清固定时间窗口内统计同一个来源IP的认证失败次数超过阈值就判定为暴力破解。窗口设多大、阈值设多少直接决定误报率。常见做法是把分析逻辑写成一个带参数函数参数可以进配置文件。下面是一个典型的简化实现# brute_analyse.py 核心判定逻辑简化版 import re from collections import defaultdict from datetime import datetime, timedelta def analyse_brute_force(log_lines, window300, threshold5): 在时间窗口内统计同一源IP的失败次数超过阈值告警。 :param window: 统计窗口单位秒默认300秒 :param threshold: 失败次数阈值默认5次 :return: 告警列表每个元素为(ip, 次数, 起始时间) attempts defaultdict(list) fail_pattern re.compile(r(Failed password|LOGIN FAILED|authentication failure), re.I) for line in log_lines: if not fail_pattern.search(line): continue # 非失败认证记录直接跳过 ts_match re.search(r(\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}), line) ip_match re.search(rfrom ([\d.])|ip([\d.]), line) if not (ts_match and ip_match): continue # 时间或IP缺失的记录无法进入统计 ts datetime.strptime(ts_match.group(1).replace(T, ), %Y-%m-%d %H:%M:%S) ip ip_match.group(1) or ip_match.group(2) attempts[ip].append(ts) alarms [] for ip, ts_list in attempts.items(): ts_list.sort() base ts_list[0] count sum(1 for t in ts_list if t base timedelta(secondswindow)) if count threshold: alarms.append((ip, count, base)) return alarms这段代码有三个关键点。第一正则没有写死“Failed password”一种格式而是同时兼容常见Linux发行版的认证失败写法re.I忽略大小写避免大小写差异漏匹配。第二时间解析里用replace(T, )处理的是“有的日志时间分隔符是空格、有的是T”的差异这一行不处理后面所有时间比较都会报错。第三滑动窗口实现得比较朴素先排序再取区间如果日志量到几十万行以上我会改成双指针或deque增量移除避免O(n²)求和。阈值怎么调给一组实测经验纯SSH暴力破解300秒内同IP失败5次在校园网环境误报率很低如果服务器本身常被扫描器探测把窗口缩到120秒、阈值提到10次更稳。答辩老师大概率会问“阈值是硬编码还是可配置”所以参数化是必选项别写死在函数体里。2.3 HTTP攻击分析http_analyse的规则匹配思路http_analyse处理的是Web访问日志目标是从一堆正常请求里挑出可疑行为。常见规则有三类。第一类是状态码异常正常访问不会出现大量404或500按IP聚合4xx/5xx状态码数量超过阈值就告警这能抓目录扫描。第二类是UA指纹sqlmap、nikto、nmap等工具的特征非常固定字符串匹配就能命中。第三类是请求密度同IP短时间发出大量请求即使状态码正常也可能是爬虫或CC攻击用请求数/秒统计。一个简化的实现思路长这样# http_analyse.py 简化示例状态码聚合 UA黑名单 import re from collections import Counter def analyse_http(access_log_lines, ua_blacklistNone, max_40450): ua_blacklist ua_blacklist or [sqlmap, nikto, nmap, masscan] pattern re.compile( r(?Pip[\d.]) .*?(?Pmethod\w) (?Purl\S) HTTP/\d\.\d (?Pstatus\d{3}) ) status_counter Counter() ip_404 Counter() ua_hits [] for line in access_log_lines: m pattern.search(line) if not m: continue # 格式不符的日志行直接跳过 ip, status m.group(ip), m.group(status) status_counter[status] 1 if status 404: ip_404[ip] 1 if any(ua in line.lower() for ua in ua_blacklist): ua_hits.append((ip, m.group(url), status)) results { status_dist: dict(status_counter), 404_hot_ips: {ip: cnt for ip, cnt in ip_404.items() if cnt max_404}, ua_hits: ua_hits[:200], } return results这里的ip_404统计每个IP的404次数max_404设为50表示“同IP累计404超过50次进热点名单”。ua_hits切片只保留前200条防止超大日志占满内存。全部分析前先把字符串lower()归一化因为攻击工具常在UA里混大小写绕过简单匹配这招挡不住高级绕过但能拦住大部分脚本小子。http_analyse定位是辅助分析不用追求覆盖所有攻击类型。答辩时能讲清“状态码聚合、UA黑名单、频率统计三类规则分别防什么攻击”就已经是加分项。2.4 分析结果落到哪存储层的选型建议分析模块跑完结果要落库给前端用。常见两种做法MySQL或SQLite。毕设场景推荐SQLite零配置、单文件建表查表不过百行代码数据层一个脚本搞定。MySQL虽然更“正规”但多出装服务、初始化库表、处理连接的步骤评审现场跑不起来就得不偿失。如果项目文档里带了MySQL建表SQL就按文档初始化。拆过不少这类毕设后发现表结构常见坑有两个时间字段没用DATETIME而是用VARCHAR导致范围查询全错IP字段只留VARCHAR(15)IPv6地址存不进去。用VARCHAR(45)最稳妥。另外我习惯把分析命中的原始日志片段也存一份前端点开告警能看到“证据”答辩演示时非常加分。3. 可视化大屏是怎么拼出来的ECharts、地图JS与base.html的配合3.1 base.html与scb.css先看懂大屏的布局base.html是典型模板入口。从命名习惯看后端多半走的是模板渲染那套体系Flask或Django都常见。它负责搭大屏骨架顶部标题栏、中间主要图表区、侧边排行统计卡片。scb.css就是这套布局的样式文件控背景色、卡片阴影、滚动条等视觉细节。改造布局时有个原则不要直接动scb.css里定义好的类名。比如图表容器类叫chart-container新增图表时复制同类的div即可改了原始类名会导致整块大屏间距全乱。我一般会在base.html里先数清楚现有容器的id再决定新增内容放哪避免样式覆盖。这个习惯不费时间但能省掉改完样式后焦头烂额找不原因的半小时。3.2 ECharts ECharts-GL从统计图到3D地球echarts.min.js是基础统计图库折线图、柱状图、饼图、散点图都靠它。echarts-gl.min.js是3D扩展专门渲染3D地球、飞线图、立体柱图。态势感知大屏最常见的组合是3D地球展示攻击来源分布折线图展示攻击趋势环形图展示攻击类型占比表格展示告警明细。ECharts的玩法就是“一次setOption重新渲染”初始化三步创建实例、写option、setOption。一个最常用的飞线图配置长这样// 威胁IP地理分布-飞线图配置 // 前提先用 echarts.registerMap 注册地图数据见 3.3 节 const chart echarts.init(document.getElementById(geoChart)); const option { backgroundColor: #0b1a2a, // 深色背景大屏标配 geo: { map: world, // 对应 registerMap 的第一个参数 roam: true, // 允许拖拽和缩放 itemStyle: { areaColor: #1c3a52, // 区域填充色 borderColor: #3ee0ff // 边界线颜色 } }, series: [{ type: lines, // 飞线类型 coordinateSystem: geo, data: window.attackLines, // [{ from: [lng, lat], to: [lng, lat] }] effect: { show: true, period: 4, // 飞线流动周期单位秒 trailLength: 0.4, // 轨迹长度0-1 symbol: arrow, // 飞线的箭头 symbolSize: 4 } }] }; chart.setOption(option);几个参数值得单独讲。coordinateSystem: geo是飞线贴在地图上的前提少了它series默认走直角坐标系数据全画不出来。effect.period控制流动速度4秒一个完整动画调太小显得急促调太大视觉上像卡住。trailLength是尾迹长度0.4是视觉舒适值。data里的坐标必须是[经度, 纬度]顺序后端数据经常反过来存这类问题最玄学——图表不报错就是没有线。我习惯拿到数据后先console.log一行确认经纬度顺序。3.3 地图JS的加载机制registerMap是唯一入口项目里的Russia.js、Canada.js本质是GeoJSON格式的地图边界数据不是图表插件。ECharts要画地图必须先调用echarts.registerMap注册然后在option里用map字段引用。思路一句话先注册后引用两步缺一不可。在HTML里加载地图的常见做法!-- 注册之前必须先引入需要的地图JS -- script src/static/echarts.min.js/script script src/static/Russia.js/script script src/static/Canada.js/script script // 两个地图JS内部已经调用过 registerMap // 这里只需要确认注册成功就能在 option 里写 map: Russia fetch(/api/attack_sources) .then(res res.json()) .then(data { // data 格式: [{ name: Russia, value: 256 }, ...] const option { geo: { map: Russia, roam: true }, series: [{ type: effectScatter, // 带涟漪动画的散点 coordinateSystem: geo, data: data, rippleEffect: { scale: 3 } }] }; echarts.init(document.getElementById(countryMap)).setOption(option); }); /script说明两点。第一地图JS文件内部通常已经自动调用registerMap不需要重复注册但前提是引入顺序必须在echarts.min.js之后否则会报ECharts is not defined。第二option里map字段的值必须和registerMap第一个参数完全一致大小写、空格都不能差。Russia.js注册的是Russiaoption里写russia就白屏。项目里还带了一个jiang1_xi1_gan4_zhou1.js对应江西赣州应该是演示环境或靶机所在地的局部下钻视图。毕设后期要换成本地城市地图去下载对应GeoJSON替换这个文件即可前端逻辑不用动。3.4 图表数据怎么喂后端接口与前端option的对应大屏每个图表背后几乎都有一个后端接口。/api/attack_sources返回攻击来源聚合/api/attack_trend返回按小时或天的趋势/api/top_ips返回攻击源TOP10。前端用fetch或axios请求接口拿到数据后组装成ECharts要求的data结构。最容易踩的坑是数据结构不匹配。散点地图要[{name, value}]饼图要[{name, value}]但字段含义不同雷达图又是另一套格式。最省事的办法是让后端直接返回ECharts能用的结构而不是后端给原始数据、前端二次加工。我做这类系统会把后端接口设计成“查询即所得”后端聚合SQL算完直接拼成[{name: Russia, value: 256}]返回前端拿到就能setOption。少一层清洗代码就少一类bug。4. 把系统跑起来环境准备、目录读懂与启动验证4.1 环境准备先装对Python和数据库zip打包的毕设项目解压是第一步但解压前先做完整性校验。有些资源下载一截会损坏解压到一半报CRC错误文件不完整跑起来报模块找不到。我用两个命令处理# 先测试压缩包完整性再解压 unzip -t 毕业设计-基于主机安全态势感知系统全部资料详细文档高分项目源码.zip unzip 毕业设计-基于主机安全态势感知系统全部资料详细文档高分项目源码.zip -d host_situational_awareness/ cd host_situational_awareness/ # 创建虚拟环境避免污染系统Python python3 -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate # 升级pip后安装依赖 pip install --upgrade pip pip install -r requirements.txtunzip -t只做测试不解压返回No errors detected才是真完整。网上说的zip伪加密也会造成解压出空壳完整性校验能筛掉大部分。venv这一步很多人跳过直接装进系统Python后患无穷系统里已有包版本冲突时改也不是退也不是。requirements.txt里部分依赖版本写死pip安装报编译错误优先怀疑Python版本太新。很多毕设项目还停留在Python 3.8/3.9生态用3.12装旧版lxml、pyyaml会直接编译失败。我建议直接装Python 3.9兼容性最好。数据库方面如果项目文档里提到MySQL注意它很可能要求5.7或8.0。Windows下用zip免安装版的人特别多最常见翻车点是服务起不来原因通常是没初始化data目录。先跑一遍mysqld --initialize-insecure再启动就能过。4.2 目录结构先读懂再动手解压后不要急着跑花十分钟把目录过一遍。典型结构大致如下路径/文件作用brute_analyse暴力破解分析模块http_analyseHTTP异常请求分析模块base.html前端大屏模板入口scb.css大屏样式文件echarts.min.js / echarts-gl.min.js图表与3D渲染库Russia.js / Canada.js / jiang1_xi1_gan4_zhou1.js地图GeoJSON数据.gitignoreGit忽略配置值得注意一点brute_analyse和http_analyse没有.py后缀。有两种可能一是作者刻意去掉后缀避免IDE当普通模块打开二是打包时扩展名丢失。如果是后者去项目文档里确认它们是被import还是被命令行执行。不少zip资源跨平台传输时把.py扩展名弄丢启动报ModuleNotFoundError时先想这一层别一上来怀疑代码本身。4.3 数据接入日志文件放哪、格式怎么对齐分析模块能不能跑出结果全看日志格式对不对。项目文档一般会写明样例格式你要做的第一件事是拿一段真实日志和样例对比。重点看三处时间字段在第几位、IP在第几位、失败关键字长什么样。建议先做一个最小验证找10行真实日志喂给brute_analyse打印解析结果。一条没解析出来基本是正则没匹配上。优先查时间格式里有没有中划线、冒号之外的字符。很多系统日志时间带毫秒或时区后缀原代码的正则未必覆盖需要按真实格式修改。改的时候只动正则部分不动统计逻辑缩小排查范围。4.4 启动与验证从后端到前端的一条龙后端如果是Flask启动命令通常是flask run如果是Django是python manage.py runserver。具体以项目里README或启动脚本为准。启动后按顺序做三个验证。第一后端接口裸测。浏览器直接访问http://127.0.0.1:8000/api/attack_trend看返回JSON是否包含预期字段。第二前端页面加载。访问首页按F12打开控制台重点看JS文件404和接口CORS报错。第三静态资源检查。地图JS、ECharts引用路径如果写的是绝对路径比如/assets/echarts.min.js部署到其他端口会404改成相对路径或按项目里统一配置的静态目录前缀走。整个启动过程最隐蔽的坑是端口和bind地址。后端启动带0.0.0.0才能被局域网内其他机器访问只写127.0.0.1换一台电脑演示就要改代码。我一般固定写法是flask run --host 0.0.0.0 --port 8080前端请求也统一走http://服务器IP:8080答辩时教室其他电脑直接访问服务器IP就行。5. 部署避坑指南五个让毕设当场翻车的具体问题以下五个问题是复现同类源码时几乎都会撞上的提前避开能省下大半天排查时间。5.1 ECharts-GL引入顺序错误3D地球白屏现象页面其他图表正常唯独3D地球区域空白控制台报Cannot read properties of undefined。原因echarts-gl.min.js必须在echarts.min.js之后引入。浏览器按顺序执行脚本基础库先加载3D扩展才能挂到echarts对象上顺序反了gl插件直接失效。另一个常见连带原因是同时引入了两个版本的ECharts全局命名空间被覆盖新老API混在一起图表行为变得不可预测。解决检查base.html里script标签顺序确保基础库在前、扩展库在后。如果有多个模板页都引了这两个文件全部排查。吃过一次亏是在一个子页面多引入一个老版本echarts.min.js页面运行不报错但3D功能没了。从那以后我每引入一个ECharts相关JS都要在控制台确认版本号一致。5.2 地图显示空白控制台报Unable to get map现象geo或map类型图表区域空白控制台报Unable to get map: xxx。原因option里map字段写名字和registerMap注册名字不一致。ECharts渲染时拿map字段去注册表找找不到就画空白。常见不一致有大写不同、多了空格、地图JS文件根本没被加载。解决控制台执行echarts.getMap(你要的名字)返回undefined就是没注册成功。把地图JS文件里的registerMap第一个参数打出来对比一字不差填回option。最稳做法是全局搜registerMap把注册名和引用名对齐。这个坑几乎都是手滑但手滑一次能浪费二十分钟。5.3 暴力破解检测一条告警都没有现象喂了一堆明显暴力破解日志brute_analyse返回空列表。原因日志格式和正则不匹配。最常见是时间格式带时区比如2025-01-01 08:00:00 0800或者IP不是from开头而是src开头导致ts_match或ip_match匹配失败。更隐蔽的是日志混了ANSI颜色控制符肉眼看着正常正则实际匹配的是带转义序列的脏文本。解决把真实日志逐条放进带调试功能的正则工具验证不要靠猜。改法是放开IP匹配模式优先匹配from xxx没有就匹配srcxxx再兜底匹配IPv4格式。改完后再跑一遍最小验证解出的IP数量立刻正常。这个坑排查起来慢是因为正则失败不报错、只出空结果很容易让人怀疑统计逻辑写错。5.4 前端图表有数据却画不出来X轴全是null现象接口返回的JSON数据量是对的但ECharts X轴不显示或显示null。原因数据字段名和ECharts要求对不上。柱状图要求xAxis.data是数组后端要是返回[{time: 10:00}]这种对象数组又没有在option里写encode映射图表拿不到值。解决后端接口返回时直接把数组映射成[10:00, 10:05]这种纯字符串数组交给xAxis.data。value系列同理映射成纯数字数组。数据清洗放后端做前端只接收已整理好的结构这是减少图表类bug最有效的习惯。记住ECharts不负责理解业务字段它只认数组和数值。5.5 换了目录或换电脑后页面样式全乱、图标全丢现象项目在自己机器上正常拷到另一台电脑后图片不显示、样式不对。原因base.html里CSS和JS引用写的是绝对磁盘路径比如D:/project/static/scb.css或者带了一层项目目录前缀换机器后路径失效。资源引用是这类项目最脆弱的点拷项目时经常连带坏掉。解决把所有静态资源引用改成相对路径./static/xxx或/static/xxx统一风格。图片资源在本地的一并检查。改完按F12看Network面板404资源逐个修正。这类问题不涉及代码逻辑但最容易在答辩前夜出现提前改好路径等于给自己上了后悔药。6. 进阶玩法把单机毕设扩展成能微信告警的小工具毕设做完了想让它真正“活”起来有个小技巧加一个实时告警推送让态势感知从“开着网页才看得到”变成“有攻击就通知到手机”。这一步不复杂后端加一个发送函数在brute_analyse和http_analyse输出告警时调用即可。# alert.py 简化版企业微信机器人告警 import requests def send_webhook_alert(message: str) - bool: webhook_url https://qyapi.weixin.qq.com/cgi-bin/webhook/send?keyYOUR_KEY payload { msgtype: text, text: {content: f[态势感知告警] {message}} } try: resp requests.post(webhook_url, jsonpayload, timeout5) return resp.status_code 200 except requests.RequestException: return False # 网络异常时静默失败不影响主流程webhook_url里的key在企业微信群里添加机器人后生成。代码用try包裹保证告警发送失败不拖垮分析主流程。接入位置很关键放在暴力破解判定为真、准备返回告警列表的那一行作为第二个动作不影响原有逻辑。这是踩了几次坑换来的经验。第一次接入时我把告警逻辑写进了判定函数内部结果告警接口超时把整个分析流程卡死日志全堆在内存里。后来改成这种独立函数、异常静默的写法再也没出过类似问题。从那以后我每次在分析模块里加新判定规则都会强制走一遍同一个流程拿真实日志回放、看告警是否触发、再看webhook有没有收到。这个习惯帮我免掉了好几次在汇报时才发现规则失效的尴尬。希望帮到你。本文还有配套的精品资源点击获取
返回列表