絡(luò)入侵檢測(cè)與防御系統(tǒng):從流量分析到自動(dòng)阻斷)
簡(jiǎn)介防火墻作為靜態(tài)防御手段難以發(fā)現(xiàn)穿透邊界后的惡意行為而入侵檢測(cè)系統(tǒng)IDS通過(guò)持續(xù)監(jiān)控網(wǎng)絡(luò)流量利用規(guī)則匹配與異常檢測(cè)技術(shù)識(shí)別潛在攻擊。本文從工程實(shí)踐出發(fā)系統(tǒng)講解基于Python構(gòu)建網(wǎng)絡(luò)入侵檢測(cè)與防御系統(tǒng)的完整流程涵蓋數(shù)據(jù)包捕獲、協(xié)議解析、特征提取、檢測(cè)引擎設(shè)計(jì)以及防火墻聯(lián)動(dòng)阻斷等核心環(huán)節(jié)。結(jié)合Scapy等工具實(shí)現(xiàn)實(shí)時(shí)抓包與離線(xiàn)分析并引入NSL-KDD數(shù)據(jù)集訓(xùn)練機(jī)器學(xué)習(xí)分類(lèi)器提升未知威脅的識(shí)別能力。該方案適合畢設(shè)項(xiàng)目及中小企業(yè)內(nèi)網(wǎng)安全監(jiān)控既能體現(xiàn)網(wǎng)絡(luò)攻防原理又能落地為可運(yùn)行的防御工具。 畢設(shè)里拿到“基于Python的網(wǎng)絡(luò)入侵檢測(cè)與防御系統(tǒng)”這個(gè)題目的人第一反應(yīng)通常是有點(diǎn)懵。它不像圖書(shū)管理系統(tǒng)那樣有清晰的CRUD套路也不像圖像識(shí)別那樣有成熟的煉丹流程這個(gè)題目橫跨了網(wǎng)絡(luò)協(xié)議分析、數(shù)據(jù)包捕獲、安全檢測(cè)算法、系統(tǒng)聯(lián)動(dòng)等多個(gè)領(lǐng)域光是把范圍理清楚就夠喝一壺的。但這恰恰是這類(lèi)項(xiàng)目的價(jià)值所在——它夠綜合、夠落地做完之后你對(duì)網(wǎng)絡(luò)安全、對(duì)Python工程化、對(duì)整個(gè)系統(tǒng)的理解都會(huì)有質(zhì)的提升。這篇文章我想把它從選題拆解、架構(gòu)設(shè)計(jì)、核心模塊實(shí)現(xiàn)、檢測(cè)引擎設(shè)計(jì)、防御聯(lián)動(dòng)到測(cè)試評(píng)估和文檔撰寫(xiě)完整地拆開(kāi)講一遍。每一步都會(huì)給出可操作的方案、選型理由和我在實(shí)際調(diào)試中踩過(guò)的坑。如果你正在做這個(gè)方向的畢業(yè)設(shè)計(jì)或者想在簡(jiǎn)歷里多一個(gè)能講清楚的安全項(xiàng)目這篇內(nèi)容應(yīng)該能幫你少走不少?gòu)澛贰?. 選題拆解入侵檢測(cè)系統(tǒng)到底在檢測(cè)什么1.1 防火墻管不到的地方才是IDS的機(jī)會(huì)很多同學(xué)做這個(gè)題目的時(shí)候會(huì)陷入一個(gè)困惑既然已經(jīng)有了防火墻為什么還需要入侵檢測(cè)系統(tǒng)這個(gè)問(wèn)題的答案其實(shí)就是整個(gè)項(xiàng)目的立足點(diǎn)。傳統(tǒng)防火墻工作在網(wǎng)絡(luò)的邊界按照預(yù)設(shè)的規(guī)則決定數(shù)據(jù)包是放行還是丟棄它本質(zhì)上是一種“靜態(tài)防御”。一旦攻擊者的流量偽裝成正常流量穿透了邊界防火墻就徹底失去了作用。更麻煩的是防火墻沒(méi)有“理解”能力它不知道一臺(tái)內(nèi)網(wǎng)主機(jī)突然在凌晨向外網(wǎng)發(fā)送大量數(shù)據(jù)意味著什么也不知道某個(gè)IP短時(shí)間內(nèi)對(duì)大量端口發(fā)起連接是什么行為。入侵檢測(cè)系統(tǒng)解決的就是這個(gè)問(wèn)題。它部署在網(wǎng)絡(luò)的關(guān)鍵節(jié)點(diǎn)上被動(dòng)地監(jiān)聽(tīng)流經(jīng)的流量通過(guò)規(guī)則匹配、統(tǒng)計(jì)分析和行為建模來(lái)發(fā)現(xiàn)異常并在檢測(cè)到威脅后觸發(fā)告警或聯(lián)動(dòng)防御。簡(jiǎn)單說(shuō)防火墻是“門(mén)衛(wèi)”看證件決定放不放行入侵檢測(cè)系統(tǒng)是“監(jiān)控室里的保安”觀(guān)察所有進(jìn)門(mén)之后的行為是否正常。1.2 先定義清楚邊界檢測(cè)什么攻擊、用什么數(shù)據(jù)、輸出什么結(jié)果畢設(shè)最忌諱的就是想做的事情太多最后每個(gè)模塊都是半成品。拿到這個(gè)題目第一步不是寫(xiě)代碼而是把系統(tǒng)邊界劃清楚。從部署模式來(lái)看一類(lèi)是主機(jī)型HIDS安裝在被保護(hù)的主機(jī)上監(jiān)控系統(tǒng)日志、文件完整性、進(jìn)程行為另一類(lèi)是網(wǎng)絡(luò)型NIDS通過(guò)抓取網(wǎng)絡(luò)流量來(lái)分析入侵行為。從題目“網(wǎng)絡(luò)入侵檢測(cè)”來(lái)看重點(diǎn)應(yīng)該是后者也就是基于流量分析的網(wǎng)絡(luò)入侵檢測(cè)系統(tǒng)。從檢測(cè)技術(shù)上可以分為兩類(lèi)誤用檢測(cè)也叫特征檢測(cè)把已知攻擊的特征整理成規(guī)則庫(kù)流量去和規(guī)則匹配命中即告警。優(yōu)點(diǎn)是準(zhǔn)確率高、解釋性強(qiáng)缺點(diǎn)是只能檢測(cè)已知攻擊。異常檢測(cè)先通過(guò)學(xué)習(xí)建立“正常流量”的基線(xiàn)模型當(dāng)流量偏離基線(xiàn)到一定程度時(shí)判定為異常。優(yōu)點(diǎn)是有可能發(fā)現(xiàn)未知攻擊缺點(diǎn)是比較容易誤報(bào)。一個(gè)完整的畢設(shè)系統(tǒng)最好兩條腿走路。規(guī)則匹配作為主干保證可解釋性和演示效果統(tǒng)計(jì)異常檢測(cè)作為補(bǔ)充體現(xiàn)系統(tǒng)的智能性和算法能力。如果能力允許再加一個(gè)機(jī)器學(xué)習(xí)分類(lèi)器作為進(jìn)階模塊這部分在答辯時(shí)是很加分的亮點(diǎn)。1.3 一套合格的畢設(shè)系統(tǒng)應(yīng)該具備哪些模塊按照我自己的經(jīng)驗(yàn)這個(gè)項(xiàng)目至少需要拆成下面幾個(gè)模塊流量捕獲模塊負(fù)責(zé)從網(wǎng)卡上實(shí)時(shí)抓取數(shù)據(jù)包或者讀取離線(xiàn)流量文件比如pcap格式這是整個(gè)系統(tǒng)的數(shù)據(jù)入口。協(xié)議解析與特征提取模塊把原始的數(shù)據(jù)包轉(zhuǎn)換成結(jié)構(gòu)化的記錄包括五元組源IP、目的IP、源端口、目的端口、協(xié)議、包長(zhǎng)度、TCP標(biāo)志位、載荷內(nèi)容等這部分是檢測(cè)的基礎(chǔ)。檢測(cè)引擎模塊包括規(guī)則匹配引擎、統(tǒng)計(jì)異常檢測(cè)引擎可選機(jī)器學(xué)習(xí)檢測(cè)引擎對(duì)特征記錄進(jìn)行分析并生成告警。告警與防御模塊對(duì)檢測(cè)結(jié)果進(jìn)行分級(jí)、記錄、推送通知并聯(lián)動(dòng)防火墻/系統(tǒng)命令實(shí)現(xiàn)自動(dòng)阻斷。數(shù)據(jù)存儲(chǔ)與展示模塊把告警事件存儲(chǔ)到數(shù)據(jù)庫(kù)提供一個(gè)簡(jiǎn)單的可視化界面或日志查詢(xún)?nèi)肟凇0堰@五個(gè)模塊想清楚架構(gòu)圖就出來(lái)了后續(xù)所有的工作都是在往這些模塊里填肉。2. 系統(tǒng)架構(gòu)設(shè)計(jì)單機(jī)版本也能體現(xiàn)工程思維2.1 三層架構(gòu)與數(shù)據(jù)流設(shè)計(jì)很多學(xué)生做畢設(shè)習(xí)慣上來(lái)就寫(xiě)代碼寫(xiě)到一半發(fā)現(xiàn)模塊之間耦合得亂七八糟。我的建議是哪怕只是一個(gè)演示用的單機(jī)系統(tǒng)也一定要先在紙上畫(huà)清楚架構(gòu)。我推薦的架構(gòu)是三層結(jié)構(gòu)采集層、分析層、響應(yīng)層。采集層對(duì)應(yīng)流量捕獲模塊它只做一件事——把數(shù)據(jù)包抓下來(lái)轉(zhuǎn)換成統(tǒng)一的中間格式放入待處理隊(duì)列。分析層對(duì)應(yīng)檢測(cè)引擎它從隊(duì)列中取數(shù)據(jù)做協(xié)議解析、特征提取、規(guī)則匹配和異常檢測(cè)產(chǎn)出一條條告警事件。響應(yīng)層對(duì)應(yīng)告警與防御模塊負(fù)責(zé)對(duì)告警進(jìn)行存儲(chǔ)、展示、通知以及執(zhí)行自動(dòng)阻斷操作。三層之間通過(guò)隊(duì)列解耦最關(guān)鍵的好處是抓包的速度和檢測(cè)的速度不需要完全一致。網(wǎng)絡(luò)流量是持續(xù)不斷涌入的如果檢測(cè)引擎還在處理上一條數(shù)據(jù)時(shí)抓包線(xiàn)程被阻塞就可能丟包。用隊(duì)列做緩沖抓包線(xiàn)程只管往隊(duì)列里放檢測(cè)線(xiàn)程根據(jù)自己的處理速度從隊(duì)列里取二者互不拖累。2.2 并發(fā)模型多線(xiàn)程、隊(duì)列與性能平衡在Python里實(shí)現(xiàn)這種生產(chǎn)者-消費(fèi)者模型最標(biāo)準(zhǔn)的方式就是queue.Queue加多線(xiàn)程。抓包線(xiàn)程是生產(chǎn)者負(fù)責(zé)調(diào)用抓包庫(kù)的回調(diào)函數(shù)把每個(gè)包的關(guān)鍵信息提取出來(lái)放進(jìn)隊(duì)列。檢測(cè)線(xiàn)程是消費(fèi)者負(fù)責(zé)從隊(duì)列中取出數(shù)據(jù)跑規(guī)則匹配和異常檢測(cè)。幾個(gè)檢測(cè)線(xiàn)程可以同時(shí)跑提高處理速度。這里有三個(gè)實(shí)際開(kāi)發(fā)中容易踩的坑我一個(gè)個(gè)說(shuō)。第一Python的全局解釋器鎖GIL會(huì)導(dǎo)致多線(xiàn)程在CPU密集型任務(wù)上性能提升有限。檢測(cè)引擎如果要做復(fù)雜的機(jī)器學(xué)習(xí)推理多線(xiàn)程可能幫不上太大忙。解決辦法是把重計(jì)算任務(wù)放到進(jìn)程池里或者接受現(xiàn)實(shí)——畢設(shè)場(chǎng)景下規(guī)則匹配和統(tǒng)計(jì)檢測(cè)的耗時(shí)并不高多線(xiàn)程完全夠用。第二隊(duì)列的長(zhǎng)度必須設(shè)置上限不能無(wú)限增長(zhǎng)。如果檢測(cè)速度跟不上抓包速度隊(duì)列會(huì)越堆越長(zhǎng)內(nèi)存占用越來(lái)越大最后直接把程序拖死。比較務(wù)實(shí)的做法是給隊(duì)列設(shè)置一個(gè)maxsize滿(mǎn)了之后丟棄最舊的包或者暫時(shí)停止抓包保證系統(tǒng)自身不先崩潰。第三抓包庫(kù)的回調(diào)函數(shù)里一定不要做耗時(shí)操作?;卣{(diào)函數(shù)是抓包庫(kù)在底層線(xiàn)程中直接調(diào)用的如果你在回調(diào)里做數(shù)據(jù)庫(kù)寫(xiě)入或復(fù)雜的字符串解析非常容易阻塞抓包導(dǎo)致大量丟包。正確的做法是回調(diào)里只做最小處理——提取關(guān)鍵字段、放入隊(duì)列立刻返回。2.3 數(shù)據(jù)存儲(chǔ)設(shè)計(jì)告警記錄的庫(kù)表結(jié)構(gòu)檢測(cè)出來(lái)的告警事件需要有地方存。SQLite對(duì)畢設(shè)來(lái)說(shuō)是最合適的——不需要單獨(dú)安裝數(shù)據(jù)庫(kù)服務(wù)一個(gè)文件搞定還支持SQL查詢(xún)寫(xiě)論文的時(shí)候可以直接導(dǎo)出數(shù)據(jù)做統(tǒng)計(jì)圖表。我建議的告警記錄表結(jié)構(gòu)如下CREATE TABLE alerts ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, rule_id INTEGER, severity INTEGER, src_ip TEXT, dst_ip TEXT, src_port INTEGER, dst_port INTEGER, protocol TEXT, threat_type TEXT, detail TEXT, action_taken TEXT, is_handled INTEGER DEFAULT 0 );timestamp記錄告警時(shí)間rule_id標(biāo)識(shí)命中的檢測(cè)規(guī)則severity是嚴(yán)重等級(jí)src_ip、dst_ip、src_port、dst_port、protocol是流量五元組threat_type是攻擊類(lèi)型detail存詳細(xì)的匹配信息action_taken記錄系統(tǒng)對(duì)此告警做了什么響應(yīng)is_handled標(biāo)記是否已人工處理。有了這張表后面的告警查詢(xún)、統(tǒng)計(jì)、可視化就不用再改數(shù)據(jù)結(jié)構(gòu)了。3. 流量捕獲與協(xié)議解析一切檢測(cè)的前提3.1 工具鏈選型Scapy的優(yōu)勢(shì)與坑Python生態(tài)里做數(shù)據(jù)包處理繞不開(kāi)兩個(gè)庫(kù)Scapy和dpkt。Scapy是功能最全面的選擇既能抓包、發(fā)包又能解析協(xié)議支持TCP/IP協(xié)議棧的各個(gè)層級(jí)還能直接操作數(shù)據(jù)包的字段。它的語(yǔ)法很直觀(guān)比如拿到一個(gè)包之后可以通過(guò)packet[IP].src直接取源IP地址這對(duì)做協(xié)議的快速解析非常方便。但Scapy有一個(gè)明顯的問(wèn)題解析速度慢。它在處理復(fù)雜協(xié)議時(shí)非常耗CPU如果網(wǎng)絡(luò)流量稍大實(shí)時(shí)抓包分析很容易丟包。我做這個(gè)項(xiàng)目時(shí)采用的方案是“Scapy抓包解析、隊(duì)列緩沖、多線(xiàn)程并行處理”。如果只是畢設(shè)演示這個(gè)性能基本夠用。如果你的測(cè)試環(huán)境流量比較大可以考慮只在Scapy里做最基礎(chǔ)的鏈路層和IP層解析傳輸層以上的深層次檢測(cè)放到檢測(cè)模塊里按需處理。還有一個(gè)可選的方案是dpkt它比Scapy快不少但API偏底層寫(xiě)起來(lái)不夠直觀(guān)需要自己對(duì)以太網(wǎng)頭、IP頭、TCP頭做偏移解析。對(duì)畢設(shè)來(lái)說(shuō)我建議優(yōu)先考慮Scapy代碼寫(xiě)起來(lái)快調(diào)試也方便性能通過(guò)架構(gòu)去彌補(bǔ)。3.2 核心實(shí)現(xiàn)實(shí)時(shí)抓包與離線(xiàn)讀取先看實(shí)時(shí)抓包的代碼實(shí)現(xiàn)from scapy.all import sniff, IP, TCP, UDP, Raw def packet_callback(packet): try: if IP in packet: src_ip packet[IP].src dst_ip packet[IP].dst protocol packet[IP].proto if TCP in packet: src_port packet[TCP].sport dst_port packet[TCP].dport flags packet[TCP].flags elif UDP in packet: src_port packet[UDP].sport dst_port packet[UDP].dport flags None else: src_port dst_port None flags None length len(packet) payload b if Raw in packet: payload bytes(packet[Raw].load) # 包信息放入待處理隊(duì)列 packet_queue.put({ src_ip: src_ip, dst_ip: dst_ip, src_port: src_port, dst_port: dst_port, protocol: protocol, length: length, flags: str(flags), payload: payload }) except Exception as e: # 單包解析出錯(cuò)不能導(dǎo)致整個(gè)抓包過(guò)程終止 print(f解析包失敗: {e}) def start_sniff(interfaceNone, count0): sniff(ifaceinterface, prnpacket_callback, storeFalse, countcount)這里有幾個(gè)關(guān)鍵點(diǎn)storeFalse是關(guān)鍵參數(shù)如果設(shè)置成storeTrueScapy會(huì)把所有抓到的包緩存在內(nèi)存里流量稍大內(nèi)存就爆了。回調(diào)函數(shù)里的try...except非常重要網(wǎng)絡(luò)包五花八門(mén)有些畸形包可能導(dǎo)致解析出錯(cuò)不能讓一個(gè)壞包毀掉整個(gè)抓包線(xiàn)程。協(xié)議判斷順序很重要——TCP是IP的上層協(xié)議必須先判斷IP in packet再判斷TCP in packet否則直接訪(fǎng)問(wèn)packet[TCP]會(huì)拋異常。離線(xiàn)讀取pcap文件的分析模式同樣重要因?yàn)樽鰷y(cè)試和調(diào)試時(shí)你不可能每次都在真實(shí)網(wǎng)絡(luò)環(huán)境里抓包。離線(xiàn)模式用rdpcap讀取文件然后逐包調(diào)用同樣的解析邏輯即可。把“實(shí)時(shí)抓包”和“離線(xiàn)分析”拆成兩個(gè)入口但共享同一套解析函數(shù)這個(gè)設(shè)計(jì)能讓你在后面測(cè)試檢測(cè)規(guī)則時(shí)省下大量時(shí)間。3.3 特征工程把網(wǎng)絡(luò)包變成檢測(cè)引擎能用的記錄檢測(cè)引擎不能直接處理原始數(shù)據(jù)包需要先做特征提取。從網(wǎng)絡(luò)安全的實(shí)際角度來(lái)看最有價(jià)值的特征包括下面這些連接五元組源IP、目的IP、源端口、目的端口、協(xié)議。這是最基礎(chǔ)的標(biāo)識(shí)信息用于歸并同一個(gè)連接的所有包。連接持續(xù)時(shí)間從第一個(gè)包到最后一個(gè)包的間隔很多攻擊行為的連接時(shí)長(zhǎng)和正常流量差異很大。包長(zhǎng)度統(tǒng)計(jì)單個(gè)包的長(zhǎng)度、平均包長(zhǎng)、最大包長(zhǎng)。像UDP洪水攻擊的包通常長(zhǎng)度固定且短小DDoS攻擊則可能有大量大包。TCP標(biāo)志位特征SYN、ACK、FIN、RST等標(biāo)志位的組合。SYN Flood的特征是大量只含SYN標(biāo)志的包而且這些包沒(méi)有后續(xù)的ACK確認(rèn)。單位時(shí)間內(nèi)的包數(shù)量抓包窗口內(nèi)同一源IP發(fā)往同一目的IP的包數(shù)量。這個(gè)特征對(duì)檢測(cè)掃描行為非常關(guān)鍵正常的用戶(hù)不會(huì)在一秒內(nèi)向同一個(gè)IP的幾百個(gè)端口發(fā)起連接。在代碼層面特征提取通常以“連接”為單位聚合而不是以“單個(gè)包”為單位檢測(cè)。我在項(xiàng)目中維護(hù)了一個(gè)connections字典key是五元組value是聚合后的連接狀態(tài)。connections {} def extract_features(packet_info): key ( packet_info[src_ip], packet_info[dst_ip], packet_info[src_port], packet_info[dst_port], packet_info[protocol] ) conn connections.get(key) if conn is None: conn { start_time: time.time(), packet_count: 0, total_bytes: 0, syn_flags: 0, fin_flags: 0, rst_flags: 0, last_time: time.time() } connections[key] conn conn[packet_count] 1 conn[total_bytes] packet_info[length] # ... 統(tǒng)計(jì)標(biāo)志位過(guò)一段時(shí)間比如60秒就把不再活躍的連接從字典中清理掉否則字典越來(lái)越大內(nèi)存遲早撐不住。這個(gè)思路相當(dāng)于一個(gè)滑動(dòng)窗口讓檢測(cè)引擎始終只關(guān)注當(dāng)前活躍的連接在代碼里是一個(gè)需要提前處理好的細(xì)節(jié)。4. 檢測(cè)引擎設(shè)計(jì)規(guī)則、統(tǒng)計(jì)與機(jī)器學(xué)習(xí)三層聯(lián)動(dòng)檢測(cè)引擎是整個(gè)系統(tǒng)的核心。我把檢測(cè)引擎分成三個(gè)層次每一層都有明確的職責(zé)三層各司其職互相補(bǔ)充。4.1 規(guī)則匹配引擎把Snort思路搬到Python里規(guī)則匹配是最直觀(guān)的檢測(cè)方式也是整個(gè)系統(tǒng)的主干。思路借鑒開(kāi)源入侵檢測(cè)系統(tǒng)Snort每一條規(guī)則定義一種攻擊特征流量與規(guī)則做匹配命中就產(chǎn)生告警。我推薦用JSON或者YAML來(lái)定義規(guī)則而不是寫(xiě)死在代碼里這樣做的好處是規(guī)則變更不需要改代碼直接在配置文件里增刪即可。下面是一個(gè)規(guī)則配置的示例{ rules: [ { id: 1001, name: SQL注入嘗試, protocol: tcp, dst_port: 80, content: SELECT, severity: 3, message: 檢測(cè)到疑似SQL注入字符串 }, { id: 1002, name: 端口掃描, protocol: tcp, flags: S, threshold: 20, time_window: 5, severity: 2, message: 短時(shí)間內(nèi)大量SYN請(qǐng)求疑似端口掃描 } ] }規(guī)則匹配的邏輯就是遍歷規(guī)則對(duì)每個(gè)規(guī)則檢查協(xié)議是否匹配、目的端口是否匹配、載荷內(nèi)容是否包含指定特征串。需要注意的是字符串匹配要區(qū)分大小寫(xiě)而SQL注入語(yǔ)句的大小寫(xiě)變化很多所以規(guī)則里要保存大小寫(xiě)不敏感的匹配標(biāo)志。規(guī)則匹配這部分最容易忽略的是規(guī)則本身的誤報(bào)問(wèn)題。比如規(guī)則1002“5秒內(nèi)發(fā)起20次SYN請(qǐng)求”在公網(wǎng)環(huán)境下可能是掃描但在內(nèi)網(wǎng)某些不規(guī)范的業(yè)務(wù)系統(tǒng)里也可能出現(xiàn)。所以規(guī)則的閾值參數(shù)需要可配置并且告警產(chǎn)生后應(yīng)該能回溯到具體的流量記錄方便在論文里做案例分析。4.2 統(tǒng)計(jì)異常檢測(cè)先建立“正?!被€(xiàn)規(guī)則匹配只能抓住已知的攻擊模式對(duì)于慢速掃描、隱蔽隧道這類(lèi)未知攻擊就要靠統(tǒng)計(jì)異常檢測(cè)來(lái)兜底。統(tǒng)計(jì)異常檢測(cè)的核心思想是先學(xué)習(xí)網(wǎng)絡(luò)流量的正常特征分布然后計(jì)算當(dāng)前流量與正?;€(xiàn)的偏離程度偏離超過(guò)閾值就判定為異常。最實(shí)用的統(tǒng)計(jì)方法是用Z-Score來(lái)量化偏離程度。Z-Score表示當(dāng)前值與均值的差相當(dāng)于多少個(gè)標(biāo)準(zhǔn)差公式是z (x - mean) / std。當(dāng)Z-Score大于3或者小于-3時(shí)可以認(rèn)為當(dāng)前觀(guān)測(cè)值顯著偏離正常范圍。在實(shí)現(xiàn)時(shí)我先維護(hù)一個(gè)基礎(chǔ)流量統(tǒng)計(jì)窗口持續(xù)記錄每秒的包數(shù)、每秒的字節(jié)數(shù)、每秒新建連接數(shù)并計(jì)算這些指標(biāo)的均值和標(biāo)準(zhǔn)差。然后在檢測(cè)階段每5秒計(jì)算一次當(dāng)前窗口的Z-Score如果某指標(biāo)連續(xù)幾個(gè)窗口都超過(guò)閾值就產(chǎn)生告警。這個(gè)方案有一個(gè)需要注意的點(diǎn)初期的基線(xiàn)數(shù)據(jù)很重要。系統(tǒng)啟動(dòng)后需要先跑一段時(shí)間比如10分鐘讓基線(xiàn)穩(wěn)定下來(lái)這段時(shí)間內(nèi)的檢測(cè)結(jié)果不可靠。我把這個(gè)“學(xué)習(xí)模式”做成了可選開(kāi)關(guān)調(diào)試的時(shí)候可以跳過(guò)但要演示異常檢測(cè)時(shí)必須開(kāi)啟。4.3 機(jī)器學(xué)習(xí)分類(lèi)器從NSL-KDD開(kāi)始更容易如果想讓系統(tǒng)在答辯時(shí)更有亮點(diǎn)可以在檢測(cè)引擎中加入一個(gè)機(jī)器學(xué)習(xí)分類(lèi)模塊。網(wǎng)絡(luò)安全領(lǐng)域有一個(gè)非常經(jīng)典的數(shù)據(jù)集NSL-KDD里面包含了正常流量和幾十種攻擊流量的特征記錄非常適合用來(lái)訓(xùn)練和評(píng)估入侵檢測(cè)分類(lèi)器。訓(xùn)練部分用scikit-learn就足夠了。流程是讀取數(shù)據(jù)集的CSV文件對(duì)類(lèi)別特征做編碼對(duì)數(shù)值特征做標(biāo)準(zhǔn)化然后用隨機(jī)森林或邏輯回歸訓(xùn)練分類(lèi)模型最后用測(cè)試集評(píng)估準(zhǔn)確率、召回率、F1分?jǐn)?shù)。from sklearn.ensemble import RandomForestClassifier from sklearn.preprocessing import LabelEncoder, StandardScaler import pandas as pd train_df pd.read_csv(KDDTrain.txt) # 對(duì)協(xié)議類(lèi)型、服務(wù)、標(biāo)志位做標(biāo)簽編碼 le_proto LabelEncoder() train_df[protocol_type] le_proto.fit_transform(train_df[protocol_type]) features train_df.drop(columns[class, difficulty]) scaler StandardScaler() X_train scaler.fit_transform(features) y_train train_df[class].apply(lambda x: 0 if x normal else 1) model RandomForestClassifier(n_estimators100, random_state42) model.fit(X_train, y_train)訓(xùn)練好的模型可以用joblib保存成文件檢測(cè)引擎啟動(dòng)時(shí)加載模型然后對(duì)實(shí)時(shí)提取的特征做預(yù)測(cè)。這里要提醒一點(diǎn)模型訓(xùn)練時(shí)的特征列必須和預(yù)測(cè)時(shí)的特征列完全一致否則模型會(huì)報(bào)錯(cuò)或者產(chǎn)生不可信的結(jié)果。所以實(shí)際工程中特征提取模塊要和訓(xùn)練腳本共用一套特征工程代碼避免兩邊維護(hù)兩份邏輯。4.4 檢測(cè)結(jié)果的聚合與去重一個(gè)攻擊行為往往會(huì)產(chǎn)生大量告警。比如一個(gè)端口掃描目標(biāo)IP的多個(gè)端口會(huì)觸發(fā)多條規(guī)則如果每條都記錄到數(shù)據(jù)庫(kù)告警表會(huì)被刷爆反而不利于分析。我做的處理是事件聚合在時(shí)間窗口內(nèi)把同一個(gè)源IP、同一個(gè)目的IP、相同威脅類(lèi)型的所有告警合并成一條事件計(jì)數(shù)累加并記錄最早和最晚的時(shí)間戳。這樣一來(lái)告警數(shù)量大幅減少每次告警的信息量反而更豐富。聚合邏輯在數(shù)據(jù)庫(kù)查詢(xún)時(shí)用GROUP BY就可以實(shí)現(xiàn)也可以在檢測(cè)引擎輸出前做一次歸并。5. 從檢測(cè)到防御告警推送與自動(dòng)阻斷檢測(cè)系統(tǒng)發(fā)現(xiàn)威脅之后不能只停留在“記錄在案”的層面要體現(xiàn)出“防御”能力。防御部分的完整鏈路是分級(jí)告警、通知推送、自動(dòng)阻斷、事后審計(jì)。5.1 告警分級(jí)什么時(shí)候只需要記錄什么時(shí)候必須響應(yīng)不同威脅的嚴(yán)重程度完全不同。把告警分成三個(gè)等級(jí)每個(gè)等級(jí)對(duì)應(yīng)不同的響應(yīng)策略低危告警記錄到日志即可例如單個(gè)端口掃描探測(cè)的嘗試、HTTP請(qǐng)求中含有敏感字符串等。這些行為可能是誤報(bào)不一定要阻斷。中危告警產(chǎn)生通知并標(biāo)記可疑IP。例如一定頻率的暴力破解嘗試說(shuō)明有人在對(duì)系統(tǒng)做持續(xù)探測(cè)需要重點(diǎn)關(guān)注。高危告警立即自動(dòng)阻斷。例如檢測(cè)到大量SYN Flood的數(shù)據(jù)包、明確的SQL注入嘗試、蠕蟲(chóng)傳播行為等這些攻擊如果不及時(shí)阻斷可能很快造成實(shí)際損害。告警分級(jí)對(duì)應(yīng)的響應(yīng)策略做成可配置的這樣可以在演示時(shí)調(diào)整不同威脅的處理方式。5.2 自動(dòng)阻斷的實(shí)現(xiàn)方式本地防火墻規(guī)則聯(lián)動(dòng)自動(dòng)阻斷最直接的方式是調(diào)用操作系統(tǒng)的防火墻命令把惡意IP加入黑名單。在Linux上我用的是iptablesiptables -A INPUT -s 192.168.1.100 -j DROP在Windows上則是netsh advfirewall firewall add rule nameIDS_Block dirin actionblock remoteip192.168.1.100在Python里用subprocess模塊執(zhí)行這些命令即可。這里有兩個(gè)必須提前想清楚的問(wèn)題。第一權(quán)限問(wèn)題。執(zhí)行防火墻命令需要管理員權(quán)限所以在啟動(dòng)系統(tǒng)時(shí)就要判斷當(dāng)前進(jìn)程是否有管理員權(quán)限如果權(quán)限不足自動(dòng)阻斷功能要給出明確的提示而不是運(yùn)行到一半才報(bào)權(quán)限錯(cuò)誤。第二回退策略。自動(dòng)阻斷是有風(fēng)險(xiǎn)的一旦誤判可能把正常用戶(hù)擋在門(mén)外。我的做法是阻斷規(guī)則默認(rèn)帶有一個(gè)過(guò)期時(shí)間比如10分鐘或者30分鐘到期后自動(dòng)刪除。可以用一個(gè)后臺(tái)線(xiàn)程做定時(shí)回退也可以把阻斷命令的時(shí)間戳記到數(shù)據(jù)庫(kù)里下次啟動(dòng)時(shí)通過(guò)比對(duì)時(shí)間戳清理過(guò)期規(guī)則。這個(gè)“自動(dòng)撤銷(xiāo)”的設(shè)計(jì)在答辯時(shí)是一個(gè)很好的討論點(diǎn)說(shuō)明你不僅考慮了怎么阻斷還考慮了誤報(bào)后的恢復(fù)問(wèn)題。5.3 日志記錄與可視化日志是畢設(shè)系統(tǒng)里非常容易被低估的功能。我所說(shuō)的日志不只是控制臺(tái)打印而是包含每一次檢測(cè)判定的完整審計(jì)記錄包括這條流量為什么被判定為異常、命中了哪條規(guī)則、當(dāng)時(shí)的特征值是多少。用Python的logging模塊配置同時(shí)輸出到控制臺(tái)和文件文件按天滾動(dòng)保證日志不會(huì)無(wú)限膨脹。日志格式建議采用結(jié)構(gòu)化格式包含時(shí)間戳、等級(jí)、事件類(lèi)型、源IP、目的IP、檢測(cè)依據(jù)等字段。如果想在答辯時(shí)更直觀(guān)可以用Flask做一個(gè)簡(jiǎn)單的Web頁(yè)面展示最近告警列表、按嚴(yán)重程度統(tǒng)計(jì)的柱狀圖、按攻擊類(lèi)型統(tǒng)計(jì)的餅圖。這一步不難但視覺(jué)效果好得多。不用做得太復(fù)雜數(shù)據(jù)從SQLite里查詢(xún)出來(lái)用Chart.js畫(huà)圖表一天時(shí)間就能搞定。6. 效果驗(yàn)證不靠“感覺(jué)”靠數(shù)據(jù)和場(chǎng)景畢設(shè)答辯時(shí)最怕被問(wèn)“你這個(gè)系統(tǒng)效果怎么樣”如果你只能回答“跑起來(lái)感覺(jué)還行”那就很被動(dòng)。真正的效果驗(yàn)證要分三步走公開(kāi)數(shù)據(jù)集評(píng)測(cè)、本地模擬攻擊測(cè)試、性能指標(biāo)量化。6.1 用公開(kāi)數(shù)據(jù)集做離線(xiàn)評(píng)測(cè)NSL-KDD數(shù)據(jù)集仍然是目前做入侵檢測(cè)畢設(shè)用得最多的公開(kāi)數(shù)據(jù)集因?yàn)樗呀?jīng)清洗過(guò)包含訓(xùn)練集和測(cè)試集標(biāo)簽清晰而且文件不大處理起來(lái)很友好。評(píng)測(cè)流程是用測(cè)試集跑一遍整個(gè)檢測(cè)流程把每條記錄的預(yù)測(cè)標(biāo)簽和真實(shí)標(biāo)簽做比對(duì)計(jì)算出準(zhǔn)確率、精確率、召回率和F1分?jǐn)?shù)。特別要注意的是NSL-KDD不僅是二分類(lèi)正常/攻擊還有具體的攻擊類(lèi)型標(biāo)簽所以除了整體指標(biāo)外還可以針對(duì)不同類(lèi)型攻擊單獨(dú)計(jì)算召回率分析系統(tǒng)對(duì)哪種攻擊的檢測(cè)能力弱。這在論文里可以單獨(dú)開(kāi)一個(gè)章節(jié)來(lái)分析。6.2 本地環(huán)境模擬攻擊測(cè)試為了讓答辯有現(xiàn)場(chǎng)演示效果必須在本地搭建一個(gè)測(cè)試環(huán)境通過(guò)真實(shí)模擬攻擊流量來(lái)驗(yàn)證系統(tǒng)。在局域網(wǎng)內(nèi)可以用自己的兩臺(tái)機(jī)器做實(shí)驗(yàn)一臺(tái)跑檢測(cè)系統(tǒng)另一臺(tái)發(fā)起攻擊模擬。幾種比較安全的模擬方式端口掃描工具掃描檢測(cè)機(jī)的端口驗(yàn)證系統(tǒng)能否識(shí)別掃描行為。用現(xiàn)成的安全測(cè)試工具對(duì)本地Web服務(wù)發(fā)起SQL注入請(qǐng)求驗(yàn)證內(nèi)容匹配規(guī)則。大量向本地端口發(fā)送特殊標(biāo)志位的TCP包驗(yàn)證DoS類(lèi)檢測(cè)規(guī)則。要注意的是做這些測(cè)試時(shí)一定要在自己的測(cè)試環(huán)境里確保行為經(jīng)過(guò)授權(quán)不要對(duì)著公網(wǎng)IP或者別人的系統(tǒng)做實(shí)驗(yàn)。為了演示效果更穩(wěn)定我更推薦在測(cè)試時(shí)先用離線(xiàn)pcap文件播放。抓一份帶有攻擊流量的pcap文件讓系統(tǒng)離線(xiàn)讀取并分析這樣可以反復(fù)調(diào)整檢測(cè)規(guī)則不用擔(dān)心真實(shí)網(wǎng)絡(luò)環(huán)境的不確定性。6.3 性能指標(biāo)怎么算系統(tǒng)性能指標(biāo)主要包括檢測(cè)率和誤報(bào)率。真正例TP攻擊流量被正確識(shí)別為攻擊。假正例FP正常流量被判為攻擊。真負(fù)例TN正常流量被正確識(shí)別為正常。假負(fù)例FN攻擊流量漏判為正常。基于這四個(gè)值精確率是TP / (TP FP)代表檢測(cè)出的告警中有多少是真的攻擊召回率是TP / (TP FN)代表所有攻擊中有多少被檢測(cè)出來(lái)了F1分?jǐn)?shù)是精確率和召回率的調(diào)和平均。實(shí)際檢測(cè)中常見(jiàn)的困境是精確率和召回率此消彼長(zhǎng)。規(guī)則太嚴(yán)格漏報(bào)少但誤報(bào)多規(guī)則太寬松誤報(bào)少但漏報(bào)多。畢設(shè)里不需要追求極致的最優(yōu)解但一定要在論文里對(duì)這兩者的平衡做充分的分析說(shuō)明你在什么閾值下取得了什么樣的結(jié)果以及為什么這樣設(shè)置是合理的。7. 畢設(shè)文檔與答辯把“做了”變成“講得清楚”7.1 論文結(jié)構(gòu)怎么安排項(xiàng)目源碼寫(xiě)得再好論文寫(xiě)不清楚也很吃虧。畢設(shè)論文的邏輯主線(xiàn)應(yīng)該圍繞“解決什么問(wèn)題-怎么解決-如何驗(yàn)證”展開(kāi)。第一章緒論寫(xiě)研究背景和意義結(jié)合網(wǎng)絡(luò)安全形勢(shì)引出入侵檢測(cè)系統(tǒng)的重要性第二章相關(guān)工作介紹現(xiàn)有的入侵檢測(cè)系統(tǒng)Snort、Suricata等和研究現(xiàn)狀重點(diǎn)突出你在這個(gè)基礎(chǔ)上做了哪些改進(jìn)或補(bǔ)充第三章系統(tǒng)設(shè)計(jì)給出整體架構(gòu)圖、模塊圖、流程圖、數(shù)據(jù)庫(kù)設(shè)計(jì)這一章是篇幅最大的第四章系統(tǒng)實(shí)現(xiàn)按模塊介紹核心代碼和實(shí)現(xiàn)思路第五章系統(tǒng)測(cè)試寫(xiě)數(shù)據(jù)集的評(píng)測(cè)結(jié)果、本地模擬測(cè)試的場(chǎng)景和結(jié)果、性能指標(biāo)分析第六章總結(jié)與展望寫(xiě)系統(tǒng)的不足和后續(xù)可以考慮的改進(jìn)方向。第三章和第四章最容易犯的錯(cuò)誤是大段貼代碼。論文不是代碼倉(cāng)庫(kù)應(yīng)該用接口設(shè)計(jì)、流程描述、核心算法偽代碼來(lái)解釋“怎么做”完整代碼放在附錄或者在GitHub上開(kāi)源論文里只保留最關(guān)鍵的實(shí)現(xiàn)片段。7.2 答辯時(shí)老師最?lèi)?ài)追問(wèn)的四個(gè)問(wèn)題根據(jù)我?guī)н^(guò)的項(xiàng)目經(jīng)驗(yàn)答辯時(shí)老師針對(duì)這類(lèi)題目問(wèn)得最多的問(wèn)題基本是固定的提前準(zhǔn)備好就沒(méi)有難度。第一個(gè)問(wèn)題“你為什么要用Python來(lái)做入侵檢測(cè)性能能跟得上嗎”回答的要點(diǎn)是承認(rèn)Python在性能上的不足同時(shí)強(qiáng)調(diào)畢設(shè)場(chǎng)景的定位是演示原型并且你已經(jīng)通過(guò)多線(xiàn)程、隊(duì)列緩沖、特征聚合等方式在工程上做了性能優(yōu)化。如果能把具體數(shù)據(jù)——比如單核CPU下每秒處理多少包——講出來(lái)會(huì)更有說(shuō)服力。第二個(gè)問(wèn)題“你的系統(tǒng)和Snort這類(lèi)成熟工具相比有什么優(yōu)勢(shì)”這個(gè)問(wèn)題很容易被問(wèn)“倒”。誠(chéng)實(shí)的回答是功能上肯定不如成熟產(chǎn)品但你的系統(tǒng)在規(guī)則可配置性、代碼可讀性、面向特定場(chǎng)景的定制能力上有自己的設(shè)計(jì)思路。重點(diǎn)是展示你理解了Snort的工作方式并且能夠用Python獨(dú)立重新實(shí)現(xiàn)核心邏輯這是一個(gè)學(xué)習(xí)深度的體現(xiàn)。第三個(gè)問(wèn)題“如何降低誤報(bào)率”這是一個(gè)開(kāi)放問(wèn)題可以從規(guī)則閾值可調(diào)、事件聚合去重、統(tǒng)計(jì)基線(xiàn)自適應(yīng)、人工反饋機(jī)制等角度回答。我建議在系統(tǒng)里預(yù)留一個(gè)“誤報(bào)標(biāo)記”功能用戶(hù)在管理界面上可以標(biāo)記某條告警為誤報(bào)系統(tǒng)記錄這些反饋后自動(dòng)調(diào)整相關(guān)規(guī)則的權(quán)重哪怕只做了雛形也是一個(gè)非常加分的創(chuàng)新點(diǎn)。第四個(gè)問(wèn)題“系統(tǒng)的實(shí)時(shí)性如何”要提前用數(shù)據(jù)說(shuō)話(huà)。我實(shí)際測(cè)試過(guò)規(guī)則匹配引擎在普通PC上單線(xiàn)程每秒能處理幾千個(gè)包的解析和匹配對(duì)實(shí)驗(yàn)室環(huán)境完全夠用。如果流量更大可以擴(kuò)展用DPDK、PF_RING這類(lèi)高性能抓包方案或者把檢測(cè)模塊部署成獨(dú)立的服務(wù)橫向擴(kuò)展但這是后續(xù)工作了。最后的經(jīng)驗(yàn)之談如果從頭再做一次這個(gè)項(xiàng)目我會(huì)建議按照“先離線(xiàn)、再實(shí)時(shí)”的順序推進(jìn)。先拿一份帶攻擊流量的pcap文件在離線(xiàn)模式下把規(guī)則匹配、特征提取、告警存儲(chǔ)整條鏈路跑通驗(yàn)證邏輯正確之后再切換到實(shí)時(shí)抓包模式去處理真實(shí)環(huán)境中的各種異常數(shù)據(jù)。這樣調(diào)試成本低很多也不會(huì)一上來(lái)就被實(shí)時(shí)抓包的性能問(wèn)題干擾。還有一個(gè)容易被忽略的點(diǎn)版本管理。從一開(kāi)始就用Git管理代碼寫(xiě)論文時(shí)、調(diào)規(guī)則時(shí)、改架構(gòu)時(shí)都是提交點(diǎn)回退起來(lái)非常方便。很多同學(xué)到了答辯前才急急忙忙找歷史版本那時(shí)候真的是欲哭無(wú)淚。這個(gè)題目其實(shí)是一個(gè)性?xún)r(jià)比很高的畢業(yè)設(shè)計(jì)選題——技術(shù)棧通用、方向明確、做出來(lái)也好看。把架構(gòu)想清楚把模塊拆干凈把驗(yàn)證做扎實(shí)你的論文和答辯都不會(huì)差。本文還有配套的精品資源點(diǎn)擊獲取