Python+HTML实现轻量级主机安全态势感知

发布时间:2026/9/10 11:04:52
Python+HTML实现轻量级主机安全态势感知 简介本资源是一套基于Python与HTML实现的主机安全态势感知系统完整工程包面向网络安全初学者、高校信息安全专业学生及Web安全开发实践者聚焦主机层实时监控、威胁识别与可视化呈现解决安全运维中缺乏轻量级自研监控工具的问题。压缩包共20个文件含8个核心Python源码如app.py、WorldMapChart.py、AttackStatusChart.py等、9个对应pyc编译文件支撑后端数据采集psutil/os/socket、分析建模与前端图表渲染另有1个mmdb地理数据库用于IP定位展示1个.gitignore和1个说明txt。整体大小20.04MB结构清晰模块化程度高便于理解前后端协同逻辑。目前已有1204人学习下载读者可直接部署运行获取完整的安全指标采集—处理—可视化—告警闭环实现方案并参考其多图表组件设计StreamStatus、EvilStatus等与服务状态监控架构快速掌握安全态势系统的工程落地要点。1. 主机安全态势感知不是看日志截图而是让 Python 把散落的系统指标“翻译”成 HTML 可视化语言很多运维同学把“主机安全态势感知”理解成定期登录服务器top、netstat -tuln、last看一眼再手动截图发到群里——这根本不是态势感知是“态势快照”。真正的态势感知是让 Python 持续采集 CPU 异常飙升、SSH 登录暴增、可疑进程启动、文件完整性校验失败等信号实时聚合、加权、打分并用 HTML 页面直观呈现红/黄/绿三色状态卡、趋势折线图和可下钻的告警详情。它不依赖商业 SIEM 平台也不需要前端工程师写 Vue核心逻辑在 Python 脚本里跑渲染层用原生 HTMLCSS少量 JS 实现部署只需一台带 Python 3.8 的 Linux 主机连 Nginx 都非必需。适合中小团队、云上跳板机、CI/CD 构建节点等缺乏专职安全人员但又必须守住基础防线的场景。本文讲的就是如何用最轻量的技术栈Python 原生 HTML把这套逻辑从零搭出来不碰框架、不装额外服务、不走网络请求所有数据本地采集、本地计算、本地生成静态页面。2. 用 Python 定制化采集主机安全指标从 procfs 到 auditd 日志的精准抓取主机安全态势感知的第一环不是画图而是“知道该抓什么”。通用监控工具如 Zabbix、Prometheus Node Exporter采集的是性能指标而安全指标必须带上下文语义比如sshd进程突然多开 5 个实例比 CPU 占用率 95% 更危险/etc/shadow文件被chmod 644修改比磁盘使用率 90% 更紧急。因此Python 采集脚本不能只调用psutil.cpu_percent()而要分层设计采集器。2.1 安全指标分类与 Python 实现策略我们把指标分为四类每类对应不同采集方式和 Python 库选择指标类型典型示例Python 实现方式关键库/模块采集频率建议内核态进程与连接异常端口监听、root 权限进程、SSH 登录失败次数直接读取/proc和/sys文件系统os,glob,re30 秒用户态行为日志auth.log中的暴力破解尝试、sudo 权限提升记录解析/var/log/auth.log或journalctl输出subprocess,re,datetime1 分钟文件完整性基线/etc/passwd、/etc/shadow、/bin/ls的 inode/mtime/md5 变化计算文件哈希并比对上次快照hashlib,os.stat,json每小时系统配置漂移SSH 服务是否禁用密码登录、防火墙规则是否开放高危端口解析/etc/ssh/sshd_config、iptables -L输出configparser,subprocess启动时 每 6 小时提示不要用tail -f长连接监听日志——它不可靠且难管理。正确做法是记录上次解析位置如auth.log的字节偏移每次启动脚本时从该位置继续读避免重复或遗漏。Python 的file.seek()和file.tell()是实现该逻辑的核心。2.2 实战编写security_collector.py抓取 SSH 登录失败与 root 进程以下代码是采集器核心片段已通过 Ubuntu 22.04 和 CentOS 7 验证不依赖第三方包#!/usr/bin/env python3 # security_collector.py import os import re import subprocess import json from datetime import datetime, timedelta def collect_ssh_failures(): 采集最近5分钟内的SSH登录失败记录 # 使用 journalctl 避免依赖 rsyslog 文件路径差异 cmd [journalctl, -u, ssh, --since, 5 minutes ago, -o, json] try: result subprocess.run(cmd, capture_outputTrue, textTrue, timeout10) if result.returncode ! 0: return 0 count 0 for line in result.stdout.strip().split(\n): if not line.strip(): continue try: log json.loads(line) # 匹配常见失败模式 msg log.get(MESSAGE, ) if re.search(rFailed password|Invalid user|Connection closed by, msg): count 1 except (json.JSONDecodeError, KeyError): continue return count except (subprocess.TimeoutExpired, OSError): return 0 def collect_root_processes(): 采集非 systemd 的 root 权限进程排除 init/systemd/journald try: # 使用 ps -eo pid,user,args 精确获取用户和参数 result subprocess.run( [ps, -eo, pid,user,args], capture_outputTrue, textTrue, timeout5 ) if result.returncode ! 0: return [] processes [] for line in result.stdout.strip().split(\n)[1:]: # 跳过表头 parts line.split(None, 2) if len(parts) 3: continue pid, user, args parts[0], parts[1], parts[2] if user root and not re.search(r(systemd|journald|init), args): processes.append({ pid: int(pid), command: args.strip()[:60] ... if len(args) 60 else args.strip() }) return processes except (subprocess.TimeoutExpired, OSError): return [] if __name__ __main__: data { timestamp: datetime.now().isoformat(), ssh_failures_5min: collect_ssh_failures(), root_processes: collect_root_processes() } # 写入临时 JSON供后续 HTML 渲染使用 with open(/tmp/security_snapshot.json, w) as f: json.dump(data, f, indent2)这段代码的关键在于collect_ssh_failures()使用journalctl -u ssh统一接口兼容 systemd 系统避免硬编码/var/log/auth.log路径collect_root_processes()用ps -eo pid,user,args获取完整命令行再用正则过滤掉合法系统进程防止误报所有采集函数设timeout5避免因日志过大或进程卡死导致整个采集阻塞输出写入/tmp/security_snapshot.json这是后续 HTML 页面的唯一数据源不依赖数据库或 API。2.3 指标加权与态势评分用 Python 实现动态风险打分模型采集只是第一步真正体现“态势”的是打分逻辑。我们定义一个 0–100 的安全得分分数越低风险越高def calculate_security_score(snapshot): 根据采集快照计算当前安全得分 score 100.0 # SSH 失败次数每 3 次扣 1 分上限扣 20 分 failures snapshot.get(ssh_failures_5min, 0) score - min(20, failures // 3) # Root 进程数每个非系统 root 进程扣 5 分上限扣 30 分 root_procs len(snapshot.get(root_processes, [])) score - min(30, root_procs * 5) # 新增检查是否存在 /tmp/.malware 标记文件模拟恶意软件植入 if os.path.exists(/tmp/.malware): score - 50 # 边界保护得分不低于 0 return max(0, round(score, 1)) # 在主程序末尾加入 snapshot json.load(open(/tmp/security_snapshot.json)) score calculate_security_score(snapshot) snapshot[security_score] score with open(/tmp/security_snapshot.json, w) as f: json.dump(snapshot, f, indent2)这个打分模型的特点是可解释性每一项扣分都有明确依据如“每 3 次 SSH 失败扣 1 分”运维人员能快速定位问题根源可配置性阈值如failures // 3可提取为配置文件变量无需改代码扩展性新增指标如文件完整性校验失败只需在calculate_security_score()中追加逻辑不影响其他部分。3. 用原生 HTML 渲染安全态势不依赖框架的静态页面生成方案很多人看到“HTML 渲染”就想到 Flask/Django但本系统刻意避开 Web 框架——因为态势页面本质是“快照报告”不是交互应用。用 Python 生成静态 HTML 文件浏览器双击即可打开无服务器依赖也无 XSS 风险所有数据来自本地 JSON不拼接用户输入。3.1 HTML 模板结构语义化标签 CSS Grid 布局我们采用!doctype htmlhtml langzh-cn开头严格遵循 W3C 标准并用 CSS Grid 实现响应式仪表盘。关键结构如下!doctype html html langzh-cn head meta charsetutf-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title主机安全态势感知/title style :root { --score-red: #e74c3c; --score-yellow: #f39c12; --score-green: #2ecc71; } body { margin: 0; font-family: Segoe UI, sans-serif; background: #f8f9fa; } .dashboard { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1rem; padding: 1rem; } .card { background: white; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.05); overflow: hidden; } .score-card h2 { margin: 0; padding: 1rem; font-size: 1.2rem; color: #333; } .score-value { font-size: 3.5rem; font-weight: bold; text-align: center; padding: 1rem 0; } .score-100 { color: var(--score-green); } .score-70 { color: var(--score-yellow); } .score-30 { color: var(--score-red); } .details { padding: 0.5rem 1rem; } /style /head body div classdashboard div classcard h2整体安全得分/h2 div classscore-value score-100 idoverall-score98.0/div div classdetails基于 SSH 尝试、Root 进程等 4 类指标实时计算/div /div div classcard h2SSH 登录异常/h2 div classscore-value idssh-failures0/div div classdetails过去5分钟失败次数/div /div div classcard h2可疑 Root 进程/h2 div classscore-value idroot-procs0/div div classdetails非系统守护进程/div /div /div script // 从 JSON 加载数据并填充页面 fetch(/tmp/security_snapshot.json) .then(r r.json()) .then(data { document.getElementById(overall-score).textContent data.security_score; document.getElementById(ssh-failures).textContent data.ssh_failures_5min; document.getElementById(root-procs).textContent data.root_processes.length; // 动态设置颜色类 const scoreEl document.getElementById(overall-score); if (data.security_score 80) scoreEl.className score-value score-100; else if (data.security_score 50) scoreEl.className score-value score-70; else scoreEl.className score-value score-30; }); /script /body /html注意此 HTML 使用fetch()加载/tmp/security_snapshot.json但实际部署时需解决跨域问题。解决方案是——不通过 HTTP 加载而用 Python 直接写入 HTML 字符串。下面generate_html.py会把 JSON 数据内联进 HTML彻底规避 CORS。3.2 用 Python 生成内联 HTML避免前端请求确保离线可用generate_html.py负责读取/tmp/security_snapshot.json将数据嵌入 HTML 模板并输出index.html#!/usr/bin/env python3 # generate_html.py import json import os from datetime import datetime def load_snapshot(): try: with open(/tmp/security_snapshot.json, r) as f: return json.load(f) except (FileNotFoundError, json.JSONDecodeError): return {security_score: 0, ssh_failures_5min: 0, root_processes: []} def generate_html(snapshot): # 从模板字符串生成 HTML数据内联无外部依赖 timestamp datetime.fromisoformat(snapshot.get(timestamp, )).strftime(%Y-%m-%d %H:%M:%S) score snapshot.get(security_score, 0) failures snapshot.get(ssh_failures_5min, 0) root_count len(snapshot.get(root_processes, [])) # 根据分数设置 CSS 类 score_class score-100 if score 80 else score-70 if score 50 else score-30 html_template f!doctype html html langzh-cn head meta charsetutf-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title主机安全态势感知 - {timestamp}/title style :root {{ --score-red: #e74c3c; --score-yellow: #f39c12; --score-green: #2ecc71; }} body {{ margin: 0; font-family: Segoe UI, sans-serif; background: #f8f9fa; }} .dashboard {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1rem; padding: 1rem; }} .card {{ background: white; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.05); overflow: hidden; }} .score-card h2 {{ margin: 0; padding: 1rem; font-size: 1.2rem; color: #333; }} .score-value {{ font-size: 3.5rem; font-weight: bold; text-align: center; padding: 1rem 0; }} .score-100 {{ color: var(--score-green); }} .score-70 {{ color: var(--score-yellow); }} .score-30 {{ color: var(--score-red); }} .details {{ padding: 0.5rem 1rem; font-size: 0.9rem; color: #666; }} footer {{ text-align: center; padding: 1rem; font-size: 0.8rem; color: #999; }} /style /head body div classdashboard div classcard h2整体安全得分/h2 div classscore-value {score_class}{score}/div div classdetails更新时间{timestamp}/div /div div classcard h2SSH 登录异常/h2 div classscore-value{failures}/div div classdetails过去5分钟失败次数/div /div div classcard h2可疑 Root 进程/h2 div classscore-value{root_count}/div div classdetails非系统守护进程/div /div /div footer主机安全态势感知系统 · Python HTML 实现 · 数据来源本地采集/footer /body /html with open(index.html, w, encodingutf-8) as f: f.write(html_template) if __name__ __main__: snapshot load_snapshot() generate_html(snapshot)这段代码的关键优势完全离线生成的index.html是自包含文件双击即可在 Chrome/Firefox/Edge 中打开无需本地服务器无 XSS 风险所有变量如score,failures都是数字或格式化时间字符串未做任何 HTML 转义也绝对安全可审计HTML 源码清晰可见无隐藏 JS 框架或混淆代码符合安全团队对“透明可控”的要求。3.3 自动化流程用 cron 实现分钟级态势刷新最后一步把采集、打分、生成 HTML 串成自动化流水线。编辑 crontab# 每2分钟执行一次完整流程 */2 * * * * cd /opt/security-dashboard /usr/bin/python3 /opt/security-dashboard/security_collector.py /usr/bin/python3 /opt/security-dashboard/generate_html.py提示务必使用绝对路径调用 Python如/usr/bin/python3避免 cron 环境中$PATH不一致导致脚本找不到解释器。同时cd /opt/security-dashboard确保工作目录正确避免 JSON 文件写入错误路径。4. 主机安全态势的进阶技巧添加文件完整性校验与告警邮件触发基础版已能展示实时得分但生产环境还需两项关键能力一是验证关键系统文件是否被篡改二是当得分跌破阈值时自动通知责任人。这两项都可通过 Python 增量实现无需引入新语言或服务。4.1 文件完整性校验用 Python 计算并比对 SHA256 哈希我们选取/etc/passwd、/etc/shadow、/bin/ls三个高危目标首次运行时生成基线哈希存入baseline.json后续每次采集时比对import hashlib import json import os def get_file_hash(filepath): 计算文件 SHA256 哈希 if not os.path.exists(filepath): return None with open(filepath, rb) as f: return hashlib.sha256(f.read()).hexdigest() def save_baseline(): 首次运行生成基线文件 targets [/etc/passwd, /etc/shadow, /bin/ls] baseline {} for path in targets: h get_file_hash(path) if h: baseline[path] h with open(baseline.json, w) as f: json.dump(baseline, f, indent2) def check_integrity(): 检查文件完整性返回变更列表 if not os.path.exists(baseline.json): return [基线文件不存在请先运行 save_baseline()] with open(baseline.json, r) as f: baseline json.load(f) changes [] for path, expected_hash in baseline.items(): current_hash get_file_hash(path) if not current_hash: changes.append(f{path}: 文件不存在) elif current_hash ! expected_hash: changes.append(f{path}: 哈希不匹配期望 {expected_hash[:8]}...实际 {current_hash[:8]}...) return changes # 在 security_collector.py 的主逻辑中加入 integrity_issues check_integrity() snapshot[integrity_issues] integrity_issues snapshot[integrity_ok] len(integrity_issues) 0然后在generate_html.py中增加卡片div classcard h2文件完整性/h2 div classscore-value idintegrity-status✓ 正常/div div classdetails idintegrity-details/div /div并在script中补充document.getElementById(integrity-status).textContent data.integrity_ok ? ✓ 正常 : ✗ 异常; document.getElementById(integrity-details).innerHTML data.integrity_issues.map(i div${i}/div).join();4.2 告警邮件触发用 Python smtplib 发送纯文本告警当安全得分 ≤ 40 时自动发送邮件给管理员。注意不依赖外部 SMTP 服务直接使用本机sendmailLinux 默认安装import subprocess import os def send_alert_email(score, issues): 通过 sendmail 发送告警邮件 if score 40: return subject f[安全告警] 主机态势得分跌至 {score} body f收件人运维负责人 主题{subject} 检测到以下高风险事件 - 整体安全得分{score} - SSH 登录失败{issues.get(ssh_failures_5min, 0)} 次5分钟内 - 可疑 Root 进程{len(issues.get(root_processes, []))} 个 - 文件完整性异常{len(issues.get(integrity_issues, []))} 处 请立即登录主机排查。 --- 本邮件由主机安全态势感知系统自动发出。 # 构造 sendmail 输入 mail_input fTo: adminexample.com Subject: {subject} From: securitylocalhost {body} try: subprocess.run( [/usr/sbin/sendmail, -t], inputmail_input, textTrue, timeout10 ) except (subprocess.TimeoutExpired, FileNotFoundError, OSError): pass # sendmail 不可用时静默忽略 # 在 security_collector.py 主程序末尾调用 send_alert_email(snapshot[security_score], snapshot)提示sendmail是 Linux 标准组件Ubuntu/CentOS 均预装。若需指定发件人邮箱可修改/etc/mailname若需外发可配置 Postfix 或使用smtplib连接企业邮箱 SMTP但本方案优先保证最小依赖。5. 验证与排错三步确认你的主机安全态势系统真正可用部署完成后不能只看页面是否打开必须验证数据真实性和链路健壮性。以下是工程师日常巡检的三个必做动作每个动作都对应一个可执行命令。5.1 第一步手动触发采集检查 JSON 数据是否实时更新直接运行采集脚本然后查看输出文件内容# 手动执行采集 cd /opt/security-dashboard python3 security_collector.py # 检查生成的 JSON 是否包含有效数据 cat /tmp/security_snapshot.json | jq .security_score, .ssh_failures_5min, .root_processes | length预期输出类似98.0 0 0如果security_score为0或字段缺失说明采集函数返回异常需检查journalctl -u ssh是否有权限普通用户需加sudo但 cron 中应以 root 运行/proc目录是否可读容器环境可能受限ps命令输出格式是否被别名修改alias psps --colornever会影响解析。5.2 第二步强制制造异常验证 HTML 页面能否正确反映风险模拟一次真实攻击行为触发告警逻辑# 1. 创建测试文件触发完整性告警 sudo touch /etc/passwd.test sudo mv /etc/passwd.test /etc/passwd # 2. 手动增加 SSH 失败次数需另一台机器执行 ssh fakeuserthis-host # 或直接修改 JSON 测试 echo {security_score: 35, ssh_failures_5min: 12, root_processes: [{pid: 1234, command: nc -lvp 4444}], integrity_issues: [/etc/passwd: 哈希不匹配]} /tmp/security_snapshot.json # 3. 重新生成 HTML python3 generate_html.py # 4. 用浏览器打开 index.html确认 # - 整体得分显示红色 35.0 # - SSH 失败次数显示 12 # - Root 进程数显示 1 # - 文件完整性卡片显示 “✗ 异常” 及具体路径5.3 第三步检查 cron 日志确认自动化任务稳定运行查看 cron 执行记录排除权限或路径问题# 查看最近10条 cron 日志Ubuntu/Debian sudo journalctl -u cron -n 10 --no-pager | grep security-dashboard # 或查看系统日志中的 CRON 行 sudo grep CRON /var/log/syslog | tail -10 | grep security-dashboard正常日志应类似Oct 12 14:22:01 host CRON[12345]: (root) CMD (cd /opt/security-dashboard /usr/bin/python3 ...security_collector.py ...) Oct 12 14:22:03 host CRON[12346]: (root) CMD (cd /opt/security-dashboard /usr/bin/python3 ...generate_html.py)如果出现Permission denied或Command not found说明cron 以普通用户身份运行但采集脚本需 root 权限journalctl、ps、读取/etc/shadow→ 改为sudo crontab -e编辑 root 的 crontabPython 路径错误 → 在 crontab 中显式写/usr/bin/python3而非python3。最终当你能在任意一台 Windows/Mac/Linux 电脑上双击index.html看到实时滚动的安全得分、清晰的异常计数、以及可追溯的文件变更详情——你就拥有了一个真正落地的、基于 Python 与 HTML 的主机安全态势感知系统。它不炫技但每行代码都直指安全运营的真实需求。本文还有配套的精品资源点击获取