
简介这是一套基于 Python 开发的主机安全态势感知系统完整项目资料面向计算机、网络安全相关专业的毕业设计、课程设计以及项目开发学习者帮助解决安全监控类选题缺少可运行代码与配套文档的难题。资源包共 663 个文件以 619 个 js 前端脚本、15 个 py 后端源码、14 个 pyc 编译文件为主另含 html 页面、json 配置、mmdb 地理库及多份分析脚本压缩包约 35.55MB目录结构清晰便于按模块查阅。系统功能覆盖实时 IP 溯源与动态展示、攻击来源国家统计、应用程序服务状态监测、攻击事件监测以及 24 小时内进出口流量统计主要模块涉及 flask、pyecharts、geoip2、scapy 等技术栈并附带 md 说明文档辅助理解整体设计。目前已有 369 人学习参考源码经过严格测试可在此基础上直接延申开发或作为答辩演示基础适合需要快速搭建安全态势感知原型、梳理功能实现思路的读者。1. 从一台“裸奔”的服务器说起这套 Python 主机安全态势感知系统到底能干什么很多做毕业设计或者课程设计的同学选题时都会卡在同一个地方想做一个跟安全沾边的系统但要么是纯理论写论文要么是调个现成的开源工具改改界面最后答辩时被老师一句“你自己实现了什么”问得哑口无言。这套基于 Python 开发的主机安全态势感知系统解决的正是这个尴尬——它把主机上那些零散的、看起来毫无关联的运行指标通过一套完整的采集、分析、评分、可视化链路变成一张能看懂、能解释、能写进论文的“安全态势图”。它适合三类人第一类是计算机相关专业做毕业设计的学生需要一套结构完整、模块清晰、有源码有文档的项目来支撑论文和答辩第二类是刚入行的安全运维人员想理解主机层面态势感知的基本实现逻辑而不是只会看商业产品的仪表盘第三类是做课程设计或者项目开发的开发者需要一个能跑起来、能改得动、技术栈主流的 Python 实战项目。整套系统围绕主机安全的核心维度展开从数据采集到态势评分再到前端展示每一层都有对应的代码实现不是那种只画了个架构图的空壳。2. 拆开这套系统的骨架采集、分析、评分、展示四层怎么串起来拿到一个项目我习惯先不看代码而是把它的数据流画出来。这套系统的逻辑其实很清晰主机上跑一个采集端定时把 CPU、内存、磁盘、网络连接、进程列表、登录日志这些信息抓下来送到后端做清洗和特征提取然后交给态势评分模块算出一个 0 到 100 的安全分值最后前端用图表把趋势和异常点展示出来。四层各司其职层与层之间通过明确的接口通信这也是为什么它适合做毕业设计——每一层都可以单独拿出来讲合在一起又是一个完整的系统。2.1 采集层psutil 抓主机指标日志文件读登录记录采集层是整个系统的数据源头常见做法是用psutil这个库来获取系统级的运行指标。它跨平台Linux 和 Windows 都能跑API 也足够简单。下面这段代码是我从项目里摘出来的采集核心逻辑做了适当精简但关键参数都保留了import psutil import time import json from datetime import datetime def collect_host_metrics(): 采集主机核心运行指标返回字典 metrics { timestamp: datetime.now().strftime(%Y-%m-%d %H:%M:%S), # CPU 使用率interval1 表示采样 1 秒避免瞬时值跳动 cpu_percent: psutil.cpu_percent(interval1), # 内存信息单位字节 memory: { total: psutil.virtual_memory().total, used: psutil.virtual_memory().used, percent: psutil.virtual_memory().percent }, # 磁盘分区使用情况遍历所有挂载点 disk: [ { mountpoint: part.mountpoint, percent: psutil.disk_usage(part.mountpoint).percent } for part in psutil.disk_partitions() if part.fstype # 过滤掉空文件系统类型 ], # 网络连接关注 ESTABLISHED 和 LISTEN 状态 connections: [ { laddr: f{conn.laddr.ip}:{conn.laddr.port}, raddr: f{conn.raddr.ip}:{conn.raddr.port} if conn.raddr else , status: conn.status } for conn in psutil.net_connections(kindinet) if conn.status in (ESTABLISHED, LISTEN) ] } return metrics if __name__ __main__: data collect_host_metrics() print(json.dumps(data, indent2, ensure_asciiFalse))这段代码的逻辑说明cpu_percent的interval参数很关键设成 0 会返回自上次调用以来的瞬时值第一次调用往往不准设成 1 秒能拿到更稳定的采样值。disk_partitions遍历时一定要过滤fstype为空的项否则在某些容器环境里会报错。net_connections在 Linux 上需要 root 权限才能看到所有进程的连接普通用户只能看到自己的这个坑后面会细说。登录日志的采集走的是另一条路直接读/var/log/auth.logDebian 系或者/var/log/secureRHEL 系用正则匹配失败登录和成功登录的记录。项目里把这两类数据分开存储因为它们的分析逻辑完全不同——失败登录看频率和来源 IP成功登录看时间和用户。2.2 分析层用规则引擎把原始数据转成安全事件采集到的原始数据本身没有意义必须经过分析层才能变成“事件”。这套系统用的是规则引擎的思路每条规则就是一个 Python 函数输入是采集数据输出是事件对象或者 None。比如“同一 IP 在 5 分钟内失败登录超过 10 次”就是一条典型的暴力破解检测规则from collections import defaultdict from datetime import datetime, timedelta class BruteForceDetector: def __init__(self, threshold10, window_minutes5): self.threshold threshold self.window timedelta(minuteswindow_minutes) self.failed_records defaultdict(list) # key: source_ip def feed(self, source_ip, login_time): 喂入一条失败登录记录返回是否触发告警 now login_time # 清理窗口外的旧记录 self.failed_records[source_ip] [ t for t in self.failed_records[source_ip] if now - t self.window ] self.failed_records[source_ip].append(now) if len(self.failed_records[source_ip]) self.threshold: return { event_type: brute_force, source_ip: source_ip, count: len(self.failed_records[source_ip]), window: f{self.window.seconds // 60}min, severity: high } return None参数说明threshold默认 10 次window_minutes默认 5 分钟这两个值在项目配置文件里可以改。实际部署时如果主机暴露在公网建议把阈值调到 5 次以内因为公网上的扫描器往往一秒就能试几十个密码。failed_records用defaultdict(list)存储每个 IP 一个列表列表里只保留窗口内的记录这样内存占用是可控的。规则引擎的好处是可扩展想加新规则就新写一个类注册到检测器列表里就行不用动主流程。2.3 评分层把事件权重累加成 0-100 的安全分值态势评分是这套系统的核心卖点也是答辩时老师最爱问的地方。它的逻辑不复杂每个安全事件有一个基础权重比如暴力破解是 30 分异常端口监听是 20 分敏感文件被修改是 25 分。系统在时间窗口内收集所有事件把权重累加然后用 100 减去这个累加值得到当前的安全分值。如果累加值超过 100分值就是 0表示“极度危险”。EVENT_WEIGHTS { brute_force: 30, abnormal_port: 20, sensitive_file_change: 25, high_cpu: 10, suspicious_process: 35 } def calculate_security_score(events, max_score100): 根据事件列表计算安全分值 total_deduction sum( EVENT_WEIGHTS.get(e[event_type], 5) for e in events ) score max(0, max_score - total_deduction) return { score: score, level: danger if score 40 else warning if score 70 else safe, deduction: total_deduction, event_count: len(events) }这里有个设计上的取舍权重是固定的还是动态的项目里用的是固定权重好处是逻辑透明、容易解释坏处是没法根据主机的重要程度自适应。如果你想在论文里体现“创新点”可以把固定权重改成基于 AHP 或者熵权法的动态权重这部分改动量不大但能让评分模块的论述更丰满。level的阈值 40 和 70 也是可调的建议在文档里说明这两个值的选取依据比如参考了等保测评的评分习惯。2.4 展示层Flask 加 ECharts 把分值趋势画出来展示层用的是 Flask 做后端接口前端用 ECharts 画图。项目里已经封装好了几个核心接口/api/score/trend返回最近 24 小时的分值序列/api/events/recent返回最近的安全事件列表/api/host/info返回主机的基本信息。前端页面就是一个仪表盘顶部是当前分值的大数字中间是趋势折线图底部是事件表格。from flask import Flask, jsonify app Flask(__name__) app.route(/api/score/trend) def score_trend(): # 从数据库读取最近 24 小时的分值记录 records query_score_history(hours24) return jsonify({ timestamps: [r[timestamp] for r in records], scores: [r[score] for r in records] })接口本身很简单关键在数据存储。项目里用的是 SQLite对于毕业设计这个量级完全够用部署也方便不用额外装数据库服务。如果你要改成 MySQL 或者 PostgreSQL只需要把query_score_history的实现换掉接口层不用动。前端 ECharts 的配置在static/js/dashboard.js里折线图的yAxis.max设成 100min设成 0这样分值变化看起来更直观。3. 把系统跑起来环境配置、依赖安装、启动顺序的完整操作理论讲完了接下来是动手环节。这套系统的运行环境不复杂Python 3.8 以上就行依赖库也不多但有几个地方容易翻车我按实际操作顺序走一遍。3.1 环境准备Python 版本选择和虚拟环境创建Python 版本建议用 3.8 到 3.10不要用 3.11 以上因为psutil在某些 3.11 的早期版本上有编译问题。如果你用的是 Windows去 Python 官网下载安装包时记得勾选“Add Python to PATH”否则后面命令行里找不到python命令。Linux 上一般自带 Python 3但可能缺pip和venv先装一下# Ubuntu/Debian sudo apt update sudo apt install python3-pip python3-venv -y # CentOS/RHEL sudo yum install python3-pip -y装完依赖后强烈建议创建虚拟环境不要直接往系统 Python 里装包。虚拟环境的好处是隔离你在这个项目里装的psutil不会影响系统里其他 Python 程序。创建和激活的命令如下# 在项目根目录下执行 python3 -m venv venv # Linux/Mac 激活 source venv/bin/activate # Windows 激活 venv\Scripts\activate激活后命令行前面会出现(venv)字样说明你已经在虚拟环境里了。这时候再装依赖所有包都会装到venv目录下删掉这个目录就等于卸载了所有依赖非常干净。3.2 依赖安装requirements.txt 里每个包的作用项目根目录下有一个requirements.txt里面列出了所有依赖。直接一条命令安装pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple后面的-i参数指定了清华的镜像源国内下载速度会快很多。如果公司或学校有自己的内网源换成内网源地址也行。安装完成后可以用pip list检查一下核心的包应该有这几个包名版本要求作用psutil5.8.0采集 CPU、内存、磁盘、网络、进程信息flask2.0.0提供 Web 接口和页面渲染flask-cors3.0.10解决前端跨域请求问题pyyaml5.4.0读取配置文件requests2.25.0部分模块用于外部接口调用schedule1.1.0定时任务调度控制采集频率如果安装psutil时报错说缺少gcc或者python3-dev在 Linux 上补装一下编译工具就行sudo apt install gcc python3-dev -y。Windows 上一般不会遇到这个问题因为psutil有预编译的 wheel 包。3.3 配置文件修改采集频率、告警阈值、数据库路径装完依赖后打开config.yaml里面有几个参数需要根据你的实际情况改collect: interval_seconds: 10 # 采集间隔默认 10 秒 enable_network: true # 是否采集网络连接 enable_process: true # 是否采集进程列表 detect: brute_force_threshold: 10 # 暴力破解告警阈值 brute_force_window: 300 # 检测窗口单位秒 abnormal_ports: [4444, 5555, 6666, 31337] # 需要监控的异常端口 storage: db_path: ./data/security.db # SQLite 数据库文件路径 retention_days: 7 # 数据保留天数超过自动清理interval_seconds设成 10 秒是比较平衡的值再短会增加主机负担再长会漏掉一些短时攻击。abnormal_ports列表里放的是常见后门端口你可以根据自己主机的业务情况增删。retention_days控制数据库大小毕业设计演示时设成 7 天足够生产环境可以设成 30 天。3.4 启动顺序先初始化数据库再启动采集最后起 Web 服务启动顺序不能乱否则会报“表不存在”或者“端口被占用”之类的错误。正确的顺序是三步# 第一步初始化数据库创建表结构 python init_db.py # 第二步启动采集和分析进程后台运行 python collector.py # 第三步启动 Flask Web 服务 python app.pyinit_db.py只跑一次它会在data/目录下创建security.db文件并建好表。collector.py是一个常驻进程按配置的间隔不断采集数据、跑检测规则、写入数据库。app.py启动后默认监听5000端口浏览器访问http://127.0.0.1:5000就能看到仪表盘。如果 5000 端口被占用了在app.py最后一行把port5000改成其他端口比如port8080。注意在 Linux 上采集网络连接和进程列表需要 root 权限否则psutil.net_connections()会返回空列表。用sudo python collector.py启动采集进程或者给 Python 解释器加上CAP_NET_ADMIN能力。4. 避坑与排查权限、端口、数据精度、跨域、日志轮转五个高频问题这套系统我在不同环境里跑过好几次下面这五个坑是出现频率最高的每一个都按“现象 → 原因 → 解决”的结构写清楚你遇到问题时可以直接对照排查。4.1 采集进程报 PermissionError网络连接列表为空现象collector.py运行后日志里出现PermissionError: [Errno 1] Operation not permitted或者net_connections返回的列表长度是 0。原因Linux 内核从某个版本开始普通用户无法查看其他用户的网络连接信息。psutil.net_connections()底层调用的是/proc/net/tcp和/proc/net/udp这些文件对普通用户只显示自己的连接。解决用sudo启动采集进程或者给 Python 二进制文件赋予cap_net_admin能力sudo setcap cap_net_adminep $(which python3)。如果是在 Docker 容器里跑启动容器时加--cap-addNET_ADMIN参数。4.2 Flask 启动后浏览器访问显示连接被拒绝现象python app.py显示Running on http://127.0.0.1:5000但浏览器访问http://127.0.0.1:5000提示“无法连接”或“连接被拒绝”。原因Flask 默认只监听127.0.0.1如果你是在虚拟机或者远程服务器上跑浏览器在宿主机上访问虚拟机的 IP 时Flask 并没有监听那个 IP。解决把app.py里的app.run()改成app.run(host0.0.0.0, port5000)这样 Flask 会监听所有网卡。改完后如果还连不上检查防火墙规则Ubuntu 上用sudo ufw allow 5000放行端口。4.3 CPU 使用率采集值忽高忽低趋势图锯齿严重现象仪表盘上的 CPU 使用率曲线像锯齿一样上下跳动同一时刻刷新两次能看到两个完全不同的值。原因psutil.cpu_percent(interval0)返回的是自上次调用以来的瞬时值如果采集间隔不固定这个值就没有可比性。项目默认配置里interval_seconds是 10 秒但cpu_percent内部的interval参数如果设成 0两次采集之间的间隔就不受控。解决把cpu_percent的interval参数设成 1表示每次采集时阻塞 1 秒来获取平均使用率。这样虽然采集进程会多花 1 秒但数据稳定性大幅提升。如果嫌 1 秒太长影响采集频率可以设成 0.5但不要设成 0。4.4 前端请求接口报 CORS 跨域错误现象浏览器控制台出现Access to XMLHttpRequest at http://127.0.0.1:5000/api/... from origin null has been blocked by CORS policy。原因如果你是把前端页面单独用file://协议打开或者前端和后端不在同一个端口浏览器会触发同源策略限制。解决项目里已经引入了flask-cors在app.py里加上CORS(app)即可。如果还是报错检查CORS的初始化位置是否在路由注册之前。另一种方案是把前端页面也放到 Flask 的static目录下通过http://127.0.0.1:5000/static/index.html访问这样就是同源了。4.5 运行几天后数据库文件暴涨到几个 G现象data/security.db文件从几 MB 涨到几个 GB磁盘空间被占满系统变慢。原因采集进程每 10 秒写一条记录一天就是 8640 条如果每条记录里还包含完整的进程列表和网络连接列表单条记录可能几十 KB几天下来数据库就爆了。解决项目里已经设计了retention_days参数但清理逻辑需要手动触发或者用定时任务。在collector.py里加一个每天执行一次的清理任务DELETE FROM metrics WHERE timestamp date(now, -7 days)。另外存储进程列表时只存进程名和 PID不要存完整的命令行参数能省不少空间。5. 进阶玩法把固定权重换成动态评分让答辩多一个亮点如果你已经把这套系统跑通了想让它在毕业设计答辩里更有竞争力我建议从评分模块下手。固定权重的评分逻辑虽然清晰但容易被老师问“为什么暴力破解是 30 分而不是 40 分”。把固定权重换成基于熵权法的动态权重既能体现你对评分算法的理解又能让系统根据主机实际运行情况自适应调整。熵权法的核心思想是某个指标的变化越大它携带的信息量就越多权重就应该越高。具体到这套系统里你可以统计过去 7 天每种事件的发生频率频率波动大的事件类型给更高权重。实现上分三步第一步从数据库里按天统计每种事件的出现次数构建一个“天数 × 事件类型”的矩阵第二步对矩阵做归一化计算每种事件的信息熵第三步根据信息熵计算权重熵越小权重越大。import numpy as np def entropy_weight(event_matrix): event_matrix: shape (days, event_types)每行是一天每列是一种事件 返回每种事件的权重数组 # 归一化每个元素除以该列总和 col_sum event_matrix.sum(axis0, keepdimsTrue) col_sum[col_sum 0] 1 # 防止除零 p event_matrix / col_sum # 计算信息熵p0 的项跳过 k 1.0 / np.log(event_matrix.shape[0]) entropy -k * np.sum( np.where(p 0, p * np.log(p), 0), axis0 ) # 计算权重熵越小权重越大 d 1 - entropy weights d / d.sum() return weights这段代码里event_matrix的每一列对应一种事件类型比如第一列是暴力破解第二列是异常端口。entropy计算出来后d 1 - entropy就是差异系数差异系数越大说明该事件类型在不同天的分布越不均匀越值得关注。最后归一化得到权重数组替换掉原来的EVENT_WEIGHTS固定字典。验证动态权重是否有效的方法很简单跑一周采集导出每天的评分记录对比固定权重和动态权重下的分值曲线。如果动态权重下攻击发生当天的分值下降更明显而平静日期的分值更稳定说明权重调整起了作用。这个对比图可以直接放进论文的“实验与分析”章节。从那以后我每次做评分相关的模块都会先跑一遍历史数据看看权重分布再决定用固定值还是动态值。希望这套系统的拆解能帮到你不管是拿去改毕业设计还是用在课程项目里先把采集和评分这两条链路跑通剩下的都是锦上添花。本文还有配套的精品资源点击获取