勢感知系統(tǒng):采集-規(guī)則-報告最小閉環(huán))
簡介這是一套面向計算機、通信、人工智能及自動化等專業(yè)學(xué)生的主機安全態(tài)勢感知系統(tǒng)實戰(zhàn)項目適用于畢業(yè)設(shè)計、期末大作業(yè)及安全方向進(jìn)階學(xué)習(xí)。系統(tǒng)基于Python開發(fā)融合深度學(xué)習(xí)與日志分析技術(shù)可實現(xiàn)對SSH、HTTP、暴力破解等常見攻擊行為的實時識別與可視化呈現(xiàn)具備完整工程閉環(huán)能力。資源包共662個文件含15個核心Python腳本含brute_analyse、http_analyse等模塊、619個JavaScript前端交互文件支撐ECharts與ECharts-GL動態(tài)圖表渲染、以及配套HTML頁面、CSS樣式、GeoIP數(shù)據(jù)庫mmdb和多國地理數(shù)據(jù)JS文件整體壓縮后35.19MB結(jié)構(gòu)清晰、模塊解耦度高。目前已有104人下載學(xué)習(xí)提供經(jīng)答辯驗證99分、全鏈路調(diào)試通過的可運行代碼詳細(xì)文檔涵蓋部署指南、功能說明與關(guān)鍵算法注釋特別適合初學(xué)者理解安全態(tài)勢建模邏輯也便于進(jìn)階者二次開發(fā)與功能擴展。1. 這不是“殺毒軟件界面美化”而是一套可落地的主機安全態(tài)勢感知最小閉環(huán)很多同學(xué)拿到“基于Python開發(fā)的主機安全態(tài)勢感知系統(tǒng)”這個畢設(shè)題目時第一反應(yīng)是去GitHub搜一個帶Web界面的掃描器改改前端——結(jié)果跑起來只顯示“正在掃描中…”連進(jìn)程列表都拿不到更別說判斷是否存在異常行為。實際上真正的主機安全態(tài)勢感知核心不在炫酷圖表而在能穩(wěn)定采集、可解釋建模、有依據(jù)告警這三個剛性環(huán)節(jié)。它面向的是Linux/Windows服務(wù)器或開發(fā)機本地環(huán)境解決的是“我這臺機器此刻是否被植入后門有沒有異常外連關(guān)鍵服務(wù)是否被篡改”這類具體問題。本方案不依賴第三方SaaS平臺全部用標(biāo)準(zhǔn)Python庫psutil、osquery-lite封裝、scapy、yara-python實現(xiàn)數(shù)據(jù)采集用輕量級規(guī)則引擎json條件表達(dá)式做策略匹配用SQLite做本地狀態(tài)快照存儲避免引入Flask/Django等重量框架增加部署復(fù)雜度。適合計算機、信息安全、網(wǎng)絡(luò)工程專業(yè)學(xué)生在無云資源、無運維權(quán)限的條件下兩周內(nèi)完成從零部署到生成首份安全態(tài)勢報告的全過程。2. 數(shù)據(jù)采集層用原生Python接口直取操作系統(tǒng)底層信號避開Shell命令解析陷阱主機安全態(tài)勢感知的第一道門檻是能否穩(wěn)定、低開銷、跨平臺地獲取真實運行時數(shù)據(jù)。很多畢設(shè)代碼直接調(diào)用os.popen(netstat -ano)或subprocess.run([ps, -ef])看似簡單實則埋下三類隱患一是Windows/Linux命令參數(shù)不一致導(dǎo)致腳本崩潰二是Shell輸出格式隨系統(tǒng)語言/版本變化如中文Windows返回“PID”列名英文系統(tǒng)為“PID”但位置偏移三是無法獲取進(jìn)程內(nèi)存映射、文件句柄、網(wǎng)絡(luò)連接狀態(tài)等深層字段。我們采用分層采集策略所有數(shù)據(jù)源均通過Python原生綁定庫獲取確保字段語義統(tǒng)一、返回結(jié)構(gòu)可序列化。2.1 進(jìn)程與服務(wù)狀態(tài)psutil win32serviceWindows/ systemdLinux雙路徑psutil是跨平臺進(jìn)程信息采集的事實標(biāo)準(zhǔn)但默認(rèn)不暴露服務(wù)啟動類型auto/manual/disabled和依賴關(guān)系。Windows需補充pywin32獲取服務(wù)控制管理器SCM數(shù)據(jù)Linux則需解析systemctl list-units --typeservice --staterunning的JSON輸出需啟用--outputjson。關(guān)鍵代碼如下# process_collector.py import psutil import json import platform from typing import List, Dict, Any def get_running_processes() - List[Dict[str, Any]]: 統(tǒng)一返回標(biāo)準(zhǔn)化進(jìn)程字典列表字段名與Linux/Windows保持一致 processes [] for proc in psutil.process_iter([pid, name, status, cpu_percent, memory_info, connections, create_time]): try: pinfo proc.info # 統(tǒng)一字段windows pid為intlinux同理name強制strstatus映射為running/stopped/zombie proc_dict { pid: int(pinfo[pid]), name: str(pinfo[name]), status: running if pinfo[status] in [running, sleeping] else stopped, cpu_percent: float(pinfo[cpu_percent]), mem_rss_mb: int(pinfo[memory_info].rss / 1024 / 1024), create_time: int(pinfo[create_time]), connections_count: len(pinfo[connections]) } processes.append(proc_dict) except (psutil.NoSuchProcess, psutil.AccessDenied, KeyError): continue return processes def get_services_status() - List[Dict[str, Any]]: Windows用win32serviceLinux用systemctl解析返回統(tǒng)一service結(jié)構(gòu) if platform.system() Windows: import win32serviceutil services [] # 注意此處需管理員權(quán)限否則跳過 try: for service_name in win32serviceutil.EnumServicesStatus(): services.append({ name: service_name[0], display_name: service_name[1], status: running if service_name[2] 4 else stopped, start_type: [boot, system, auto, manual, disabled][service_name[3]] }) except Exception: pass # 權(quán)限不足時返回空列表不影響主流程 return services else: # Linux: systemctl list-units --typeservice --staterunning --outputjson import subprocess try: result subprocess.run( [systemctl, list-units, --typeservice, --staterunning, --outputjson], capture_outputTrue, textTrue, timeout5 ) if result.returncode 0: units json.loads(result.stdout) return [{name: u[unit], display_name: u[description], status: running, start_type: u[load]} for u in units] except Exception: pass return []提示psutil.process_iter()必須包裹try-except否則遇到已退出進(jìn)程會拋NoSuchProcess異常connections字段在Windows上需額外開啟psutil.net_connections()權(quán)限Linux默認(rèn)可用。get_services_status()在非管理員權(quán)限下Windows分支會靜默失敗這是設(shè)計使然——安全采集本身就需要權(quán)限校驗畢設(shè)演示時建議在管理員CMD中運行。2.2 網(wǎng)絡(luò)連接與監(jiān)聽端口繞過netstat用psutil.connections()直接讀取內(nèi)核socket表netstat輸出需正則解析且不同系統(tǒng)列數(shù)不一。psutil.connections()直接讀取/proc/net/tcpLinux或GetExtendedTcpTableWindows返回結(jié)構(gòu)化元組。關(guān)鍵字段包括laddr(本地地址)、raddr(遠(yuǎn)程地址)、type(TCP/UDP)、status(LISTEN/ESTABLISHED)、pid(關(guān)聯(lián)進(jìn)程ID)。以下代碼提取所有監(jiān)聽端口并關(guān)聯(lián)進(jìn)程名# network_collector.py import psutil from typing import List, Dict, Any def get_listening_ports() - List[Dict[str, Any]]: 獲取所有監(jiān)聽端口關(guān)聯(lián)進(jìn)程名過濾掉內(nèi)核線程pid0 listeners [] for conn in psutil.net_connections(kindinet): if conn.status LISTEN and conn.pid ! 0: # 排除內(nèi)核線程 try: proc psutil.Process(conn.pid) listeners.append({ port: conn.laddr.port, address: conn.laddr.ip or 0.0.0.0, protocol: tcp if conn.type socket.SOCK_STREAM else udp, pid: conn.pid, process_name: proc.name(), user: proc.username().split(\\)[-1] if \\ in proc.username() else proc.username() }) except (psutil.NoSuchProcess, psutil.AccessDenied): # 進(jìn)程已退出或無權(quán)限讀取記錄pid但不填名稱 listeners.append({ port: conn.laddr.port, address: conn.laddr.ip or 0.0.0.0, protocol: tcp if conn.type socket.SOCK_STREAM else udp, pid: conn.pid, process_name: unknown, user: unknown }) return listeners注意psutil.net_connections()在macOS上不支持pid字段需用lsof -i -P -n替代但本畢設(shè)聚焦Windows/Linux主流教學(xué)環(huán)境macOS兼容性作為可選擴展點。address字段為0.0.0.0表示監(jiān)聽所有網(wǎng)卡127.0.0.1表示僅本地回環(huán)——這是識別潛在風(fēng)險端口如Redis未綁定127.0.0.1的關(guān)鍵依據(jù)。2.3 文件完整性校驗用hashlib對關(guān)鍵系統(tǒng)路徑做快照比對態(tài)勢感知需發(fā)現(xiàn)文件篡改但全盤哈希性能不可接受。我們聚焦/etc/passwd、/etc/shadowLinux、C:\Windows\System32\drivers\etc\hostsWindows、/usr/bin/下常用工具ls, ps, netstat等高危路徑。使用hashlib.sha256()計算文件內(nèi)容哈希存入SQLite快照表每次采集時比對# file_integrity.py import hashlib import os import sqlite3 from pathlib import Path CRITICAL_PATHS [ /etc/passwd, /etc/shadow, /usr/bin/ls, /usr/bin/ps, /usr/bin/netstat, C:\\Windows\\System32\\drivers\\etc\\hosts, C:\\Windows\\System32\\notepad.exe ] def calculate_file_hash(filepath: str) - str: 計算文件SHA256忽略不存在或無權(quán)限文件 try: if not Path(filepath).exists(): return with open(filepath, rb) as f: return hashlib.sha256(f.read()).hexdigest() except (OSError, IOError): return def save_baseline(db_path: str baseline.db): 首次運行時生成基線快照 conn sqlite3.connect(db_path) conn.execute( CREATE TABLE IF NOT EXISTS file_baseline ( path TEXT PRIMARY KEY, hash TEXT NOT NULL, timestamp INTEGER NOT NULL ) ) for path in CRITICAL_PATHS: file_hash calculate_file_hash(path) if file_hash: # 僅存有效哈希 conn.execute( INSERT OR REPLACE INTO file_baseline (path, hash, timestamp) VALUES (?, ?, ?), (path, file_hash, int(time.time())) ) conn.commit() conn.close() def check_integrity(db_path: str baseline.db) - List[Dict[str, str]]: 比對當(dāng)前文件哈希與基線返回變更列表 conn sqlite3.connect(db_path) cursor conn.cursor() cursor.execute(SELECT path, hash FROM file_baseline) baseline {row[0]: row[1] for row in cursor.fetchall()} changes [] for path, baseline_hash in baseline.items(): current_hash calculate_file_hash(path) if current_hash and current_hash ! baseline_hash: changes.append({path: path, status: modified, old_hash: baseline_hash, new_hash: current_hash}) elif not current_hash: changes.append({path: path, status: unreachable, old_hash: baseline_hash}) conn.close() return changes提示save_baseline()需手動執(zhí)行一次生成初始快照后續(xù)check_integrity()才有效。calculate_file_hash()對大文件如/var/log/syslog應(yīng)加大小限制如f.read(10*1024*1024)避免內(nèi)存溢出——畢設(shè)場景下關(guān)鍵路徑文件均小于1MB故省略此步實際部署需補全。3. 規(guī)則引擎層用JSON定義檢測邏輯避免硬編碼if-else支持畢業(yè)答辯現(xiàn)場動態(tài)增刪規(guī)則態(tài)勢感知的核心是“什么算異?!?。硬編碼if cpu 90: alert()無法應(yīng)對答辯老師“那如果我要檢測SSH暴力破解呢”的提問。我們采用聲明式規(guī)則引擎所有檢測邏輯寫在rules.json中Python加載后動態(tài)執(zhí)行。規(guī)則結(jié)構(gòu)包含id、name、description、source數(shù)據(jù)源名、conditionJMESPath表達(dá)式、severitylow/medium/high、actionlog/alert。JMESPath語法簡潔支持?jǐn)?shù)組過濾、數(shù)值比較、字符串匹配學(xué)習(xí)成本低于自研DSL。3.1 規(guī)則定義規(guī)范與示例覆蓋進(jìn)程、網(wǎng)絡(luò)、文件三類典型威脅rules.json示例截取關(guān)鍵片段[ { id: high_cpu_process, name: CPU占用率持續(xù)過高, description: 單個進(jìn)程CPU占用超過80%持續(xù)30秒, source: processes, condition: [?cpu_percent 80], severity: medium, action: alert }, { id: suspicious_port, name: 監(jiān)聽高危端口, description: 監(jiān)聽端口為22SSH、3306MySQL、6379Redis且綁定0.0.0.0, source: listening_ports, condition: [?port 22 || port 3306 || port 6379] | [?address 0.0.0.0], severity: high, action: alert }, { id: hosts_modified, name: hosts文件被篡改, description: 檢測/etc/hosts或C:\\Windows\\System32\\drivers\\etc\\hosts內(nèi)容變更, source: file_integrity, condition: [?status modified (contains(path, hosts))], severity: high, action: alert } ]3.2 規(guī)則執(zhí)行引擎用jmespath庫解析condition避免eval安全風(fēng)險# rule_engine.py import json import jmespath from typing import List, Dict, Any class RuleEngine: def __init__(self, rules_path: str rules.json): with open(rules_path, r, encodingutf-8) as f: self.rules json.load(f) def evaluate_rules(self, data: Dict[str, Any]) - List[Dict[str, Any]]: 對data字典中各source鍵執(zhí)行對應(yīng)規(guī)則返回匹配結(jié)果列表 alerts [] for rule in self.rules: source_key rule[source] if source_key not in data: continue # 使用jmespath.search安全執(zhí)行表達(dá)式不執(zhí)行任意代碼 try: result jmespath.search(rule[condition], data[source_key]) if result: # JMESPath返回非空即匹配 alerts.append({ rule_id: rule[id], rule_name: rule[name], matched_data: result if isinstance(result, list) else [result], severity: rule[severity], timestamp: int(time.time()) }) except jmespath.exceptions.JMESPathError as e: # condition語法錯誤記錄日志但不中斷 print(fRule {rule[id]} JMESPath error: {e}) continue return alerts # 使用示例 if __name__ __main__: # 假設(shè)已采集數(shù)據(jù) collected_data { processes: get_running_processes(), listening_ports: get_listening_ports(), file_integrity: check_integrity() } engine RuleEngine() alerts engine.evaluate_rules(collected_data) for alert in alerts: print(f[{alert[severity].upper()}] {alert[rule_name]}: {len(alert[matched_data])} items matched)注意jmespath.search()比eval()安全萬倍它只解析查詢語法不執(zhí)行Python代碼。condition中[?cpu_percent 80]是合法JMESPath[?name python cpu_percent 90]也支持。若需更復(fù)雜邏輯如“過去5分鐘平均CPU70%”可在數(shù)據(jù)采集層預(yù)計算滑動窗口指標(biāo)再交由JMESPath過濾。3.3 規(guī)則熱加載與調(diào)試答辯時現(xiàn)場修改JSON立即生效畢設(shè)答辯常被要求“現(xiàn)場演示新增規(guī)則”。傳統(tǒng)硬編碼需改Python再重啟而JSON規(guī)則可做到熱加載# main.py 中的采集循環(huán) import time import threading def run_monitoring(): engine RuleEngine() # 初始化一次 while True: # 每30秒采集一次 collected_data { processes: get_running_processes(), listening_ports: get_listening_ports(), file_integrity: check_integrity() } # 每次都重新讀取rules.json支持熱更新 engine.rules json.load(open(rules.json)) alerts engine.evaluate_rules(collected_data) # 輸出到控制臺答辯演示 for alert in alerts: print(f\033[91mALERT [{alert[severity]}] {alert[rule_name]}\033[0m) for item in alert[matched_data][:3]: # 只打印前3條避免刷屏 print(f → {item}) time.sleep(30) # 啟動監(jiān)控線程 threading.Thread(targetrun_monitoring, daemonTrue).start()提示daemonTrue確保主線程退出時子線程自動結(jié)束避免答辯結(jié)束程序卡死。print()用ANSI顏色碼\033[91m標(biāo)紅高危告警視覺沖擊力強符合答辯場景需求。4. 態(tài)勢聚合與報告生成用SQLite存狀態(tài)快照用Jinja2渲染HTML報告告別Excel手工整理采集和告警只是起點態(tài)勢感知要求回答“這臺機器整體安全水位如何哪些風(fēng)險在惡化歷史趨勢怎樣”。我們不引入Elasticsearch等重型組件而是用SQLite存儲時間序列快照 Jinja2模板生成靜態(tài)HTML報告既滿足畢設(shè)交付物要求可打包提交的獨立HTML文件又具備分析能力。4.1 SQLite數(shù)據(jù)庫設(shè)計三個核心表支撐態(tài)勢演進(jìn)分析創(chuàng)建security_state.db含三張表表名字段說明snapshotid(PK), timestamp, hostname, os_version, total_processes, listening_ports_count, high_cpu_count, file_modified_count每次采集的宏觀快照alertsid(PK), snapshot_id(FK), rule_id, severity, matched_json, created_at每次觸發(fā)的原始告警詳情matched_json存JSON字符串trendid(PK), metric_name, value, timestamp用于繪制趨勢圖的指標(biāo)如cpu_max_5min,ports_opened建表SQLdb_init.pyimport sqlite3 def init_database(db_pathsecurity_state.db): conn sqlite3.connect(db_path) conn.execute( CREATE TABLE IF NOT EXISTS snapshot ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER NOT NULL, hostname TEXT NOT NULL, os_version TEXT NOT NULL, total_processes INTEGER DEFAULT 0, listening_ports_count INTEGER DEFAULT 0, high_cpu_count INTEGER DEFAULT 0, file_modified_count INTEGER DEFAULT 0 ) ) conn.execute( CREATE TABLE IF NOT EXISTS alerts ( id INTEGER PRIMARY KEY AUTOINCREMENT, snapshot_id INTEGER NOT NULL, rule_id TEXT NOT NULL, severity TEXT NOT NULL, matched_json TEXT NOT NULL, created_at INTEGER NOT NULL, FOREIGN KEY(snapshot_id) REFERENCES snapshot(id) ) ) conn.execute( CREATE TABLE IF NOT EXISTS trend ( id INTEGER PRIMARY KEY AUTOINCREMENT, metric_name TEXT NOT NULL, value REAL NOT NULL, timestamp INTEGER NOT NULL ) ) conn.commit() conn.close()4.2 快照入庫與趨勢計算將離散告警轉(zhuǎn)化為連續(xù)態(tài)勢指標(biāo)每次采集后不僅存原始數(shù)據(jù)更要計算衍生指標(biāo)# report_generator.py import sqlite3 import json import platform from datetime import datetime def save_snapshot_and_alerts(db_path: str, collected_data: dict, alerts: list): conn sqlite3.connect(db_path) cursor conn.cursor() # 插入快照 hostname platform.node() os_ver f{platform.system()} {platform.release()} total_procs len(collected_data.get(processes, [])) listening_ports len(collected_data.get(listening_ports, [])) high_cpu_count len([p for p in collected_data.get(processes, []) if p.get(cpu_percent, 0) 80]) file_modified_count len([f for f in collected_data.get(file_integrity, []) if f.get(status) modified]) cursor.execute( INSERT INTO snapshot (timestamp, hostname, os_version, total_processes, listening_ports_count, high_cpu_count, file_modified_count) VALUES (?, ?, ?, ?, ?, ?, ?), (int(time.time()), hostname, os_ver, total_procs, listening_ports, high_cpu_count, file_modified_count) ) snapshot_id cursor.lastrowid # 插入告警 for alert in alerts: cursor.execute( INSERT INTO alerts (snapshot_id, rule_id, severity, matched_json, created_at) VALUES (?, ?, ?, ?, ?), (snapshot_id, alert[rule_id], alert[severity], json.dumps(alert[matched_data]), alert[timestamp]) ) # 計算并插入趨勢指標(biāo)示例高CPU進(jìn)程數(shù) cursor.execute( INSERT INTO trend (metric_name, value, timestamp) VALUES (?, ?, ?), (high_cpu_processes, float(high_cpu_count), int(time.time())) ) conn.commit() conn.close()4.3 HTML報告生成用Jinja2模板嵌入圖表支持答辯PPT直接截圖report_template.html精簡版!DOCTYPE html html headtitle主機安全態(tài)勢報告/title stylebody{font-family:Arial,sans-serif;margin:20px}table{border-collapse:collapse;width:100%}th,td{border:1px solid #ddd;padding:8px;text-align:left}/style /head body h1主機安全態(tài)勢報告/h1 p生成時間{{ now }}/p p主機名{{ hostname }} | 操作系統(tǒng){{ os_version }}/p h2宏觀態(tài)勢概覽/h2 table trth指標(biāo)/thth當(dāng)前值/thth7日均值/th/tr trtd運行進(jìn)程數(shù)/tdtd{{ snapshot.total_processes }}/tdtd{{ avg_processes }}/td/tr trtd監(jiān)聽端口數(shù)/tdtd{{ snapshot.listening_ports_count }}/tdtd{{ avg_ports }}/td/tr trtd高CPU進(jìn)程數(shù)/tdtd{{ snapshot.high_cpu_count }}/tdtd{{ avg_cpu }}/td/tr /table h2最新告警最近10條/h2 {% for alert in recent_alerts %} div stylebackground:#ffebee;padding:10px;margin:5px 0 strong[{{ alert.severity|upper }}]/strong {{ alert.rule_name }}br small{{ alert.matched_data|length }}項匹配{{ alert.matched_data|first|tojson|truncate(100) }}/small /div {% endfor %} h2歷史趨勢高CPU進(jìn)程數(shù)/h2 !-- 此處可嵌入Chart.js圖表畢設(shè)簡化用文字描述 -- p過去24小時高CPU進(jìn)程數(shù)峰值{{ max_cpu_last24h }}均值{{ avg_cpu_last24h }}/p /body /html生成報告代碼# generate_report.py from jinja2 import Template import sqlite3 import json from datetime import datetime, timedelta def generate_html_report(db_pathsecurity_state.db, output_pathreport.html): conn sqlite3.connect(db_path) cursor conn.cursor() # 獲取最新快照 cursor.execute(SELECT * FROM snapshot ORDER BY timestamp DESC LIMIT 1) snap cursor.fetchone() if not snap: return # 計算7日均值 week_ago int((datetime.now() - timedelta(days7)).timestamp()) cursor.execute(SELECT AVG(total_processes), AVG(listening_ports_count), AVG(high_cpu_count) FROM snapshot WHERE timestamp ?, (week_ago,)) avg_vals cursor.fetchone() # 獲取最近10條告警 cursor.execute( SELECT a.rule_id, r.name as rule_name, a.severity, a.matched_json, a.created_at FROM alerts a JOIN (SELECT id, name FROM rules) r ON a.rule_id r.id ORDER BY a.created_at DESC LIMIT 10 ) recent_alerts [] for row in cursor.fetchall(): recent_alerts.append({ rule_id: row[0], rule_name: row[1], severity: row[2], matched_data: json.loads(row[3]), created_at: row[4] }) # 計算24小時趨勢 day_ago int((datetime.now() - timedelta(hours24)).timestamp()) cursor.execute(SELECT MAX(value), AVG(value) FROM trend WHERE metric_name high_cpu_processes AND timestamp ?, (day_ago,)) trend_vals cursor.fetchone() conn.close() # 渲染模板 with open(report_template.html) as f: template Template(f.read()) html template.render( nowdatetime.now().strftime(%Y-%m-%d %H:%M:%S), hostnamesnap[2], os_versionsnap[3], snapshot{ total_processes: snap[4], listening_ports_count: snap[5], high_cpu_count: snap[6], file_modified_count: snap[7] }, avg_processesround(avg_vals[0], 1) if avg_vals[0] else 0, avg_portsround(avg_vals[1], 1) if avg_vals[1] else 0, avg_cpuround(avg_vals[2], 1) if avg_vals[2] else 0, recent_alertsrecent_alerts, max_cpu_last24hint(trend_vals[0]) if trend_vals[0] else 0, avg_cpu_last24hround(trend_vals[1], 1) if trend_vals[1] else 0 ) with open(output_path, w, encodingutf-8) as f: f.write(html) print(fReport generated: {output_path}) if __name__ __main__: generate_html_report()提示答辯時只需運行python generate_report.py即可生成report.html。打開瀏覽器查看所有數(shù)據(jù)來自本地SQLite無需網(wǎng)絡(luò)確保演示環(huán)境純凈。若需圖表可引入chart.js在模板中添加canvas但純文字版已滿足畢設(shè)基礎(chǔ)要求。5. 畢設(shè)交付與答辯技巧三個必做動作讓老師一眼看到技術(shù)深度畢業(yè)設(shè)計評審最怕“看起來很熱鬧細(xì)看全是調(diào)API”。要讓老師快速認(rèn)可工作量和技術(shù)含量必須在交付包和答辯陳述中突出三個硬核動作5.1 交付包結(jié)構(gòu)必須體現(xiàn)工程化思維拒絕“一堆py文件扔根目錄”標(biāo)準(zhǔn)交付目錄結(jié)構(gòu)host-security-situation/├── README.md # 含環(huán)境要求、啟動命令、規(guī)則修改指南、截圖示例 ├── requirements.txt # 明確列出psutil5.9.5 jmespath1.0.1等精確版本 ├── config/ │ ├── rules.json # 預(yù)置10條規(guī)則含注釋說明每條檢測邏輯 │ └── baseline.db # 已初始化的文件基線數(shù)據(jù)庫 ├── src/ │ ├── __init__.py │ ├── collector/ # 數(shù)據(jù)采集模塊 │ │ ├── __init__.py │ │ ├── process_collector.py │ │ ├── network_collector.py │ │ └── file_integrity.py │ ├── engine/ │ │ ├── __init__.py │ │ └── rule_engine.py # 規(guī)則引擎核心 │ ├── database/ │ │ ├── __init__.py │ │ └── db_init.py # 數(shù)據(jù)庫初始化 │ └── report/ │ ├── __init__.py │ ├── report_template.html │ └── generate_report.py ├── scripts/ │ ├── setup_baseline.py # 首次運行生成基線 │ └── start_monitor.py # 主監(jiān)控入口含熱加載邏輯 └── docs/ └── design_doc.md # UML類圖用PlantUML語法、數(shù)據(jù)流圖、規(guī)則設(shè)計說明注意requirements.txt必須用pip freeze requirements.txt生成而非手寫。答辯時老師可能檢查psutil版本是否與process_collector.py中psutil.process_iter([connections])兼容——5.9.0才支持該參數(shù)舊版本會報錯。5.2 答辯演示必須包含“規(guī)則動態(tài)增刪”和“基線重置”兩個高光時刻老師最想驗證你是否真懂原理而非復(fù)制粘貼。準(zhǔn)備兩段1分鐘演示動態(tài)增規(guī)則打開config/rules.json新增一條檢測powershell.exe異常網(wǎng)絡(luò)連接的規(guī)則Windows專屬保存后觀察控制臺30秒內(nèi)打印新告警。強調(diào)“規(guī)則引擎不重啟靠每次循環(huán)重讀JSON實現(xiàn)熱加載這是生產(chǎn)環(huán)境常見做法。”基線重置故意修改C:\Windows\System32\drivers\etc\hosts加一行127.0.0.1 evil.com運行python scripts/setup_baseline.py重建基線再運行監(jiān)控——告警消失。說明“文件完整性檢測依賴可信基線基線必須在干凈系統(tǒng)上生成這模擬了企業(yè)安全運維中‘黃金鏡像’的概念?!?.3 技術(shù)難點表格化呈現(xiàn)直擊評審關(guān)注點在PPT最后一頁用表格總結(jié)技術(shù)難點與解法避免口語化描述評審關(guān)注點你的解法為什么比別人強跨平臺兼容性psutil統(tǒng)一進(jìn)程采集 Windows/Linux雙路徑服務(wù)檢測避免subprocess調(diào)用Shell命令導(dǎo)致的解析失敗字段語義完全一致規(guī)則可維護(hù)性JSON定義 JMESPath引擎支持答辯現(xiàn)場修改不用改Python代碼降低維護(hù)成本體現(xiàn)軟件工程思想數(shù)據(jù)持久化SQLite存儲快照告警趨勢生成靜態(tài)HTML報告無需部署數(shù)據(jù)庫服務(wù)單文件交付符合畢設(shè)輕量級要求安全采集權(quán)限Windows服務(wù)檢測自動降級權(quán)限不足時跳過、Linux進(jìn)程連接數(shù)統(tǒng)計用psutil而非netstat明確處理權(quán)限邊界不因權(quán)限問題導(dǎo)致整個系統(tǒng)崩潰提示答辯時指著表格說“老師這四個點是我們重點攻克的比如第三點很多同學(xué)用Excel手工整理數(shù)據(jù)而我們實現(xiàn)了自動化的態(tài)勢報告生成點擊這里就能導(dǎo)出HTML——請看屏幕?!?然后切換到已生成的report.html放大展示“最新告警”區(qū)塊。本文還有配套的精品資源點擊獲取