絡(luò)在KDD99網(wǎng)絡(luò)攻擊檢測中的復(fù)現(xiàn)與部署實(shí)踐)
簡介這是一篇發(fā)表于《太原師范學(xué)院學(xué)報(bào)自然科學(xué)版》的學(xué)術(shù)論文面向網(wǎng)絡(luò)安全、數(shù)據(jù)分析與深度學(xué)習(xí)交叉領(lǐng)域的研究者和從業(yè)者聚焦傳統(tǒng)網(wǎng)絡(luò)攻擊檢測中特征提取能力不足、誤報(bào)率偏高的問題。文中提出一種基于并行卷積神經(jīng)網(wǎng)絡(luò)的在線攻擊檢測方法包含CNN1和CNN2兩個(gè)特征提取分支通過全連接層融合并利用Softmax分類識(shí)別攻擊類型并以KDD Cup99數(shù)據(jù)集完成訓(xùn)練與驗(yàn)證。資源包內(nèi)僅有1個(gè)PDF文件壓縮包大小為3.12MB完整保留了論文正文、卷積網(wǎng)絡(luò)結(jié)構(gòu)圖與實(shí)驗(yàn)結(jié)果等內(nèi)容。目前已有569人學(xué)習(xí)下載常被用作深度學(xué)習(xí)與網(wǎng)絡(luò)安全相關(guān)課題的參考文獻(xiàn)或?qū)I(yè)指導(dǎo)材料。讀者通過該P(yáng)DF可系統(tǒng)了解經(jīng)典卷積網(wǎng)絡(luò)模型、并行網(wǎng)絡(luò)參數(shù)設(shè)置、訓(xùn)練流程及與已有方法的對(duì)比結(jié)論有助于快速把握該類檢測技術(shù)的研究脈絡(luò)和實(shí)現(xiàn)細(xì)節(jié)。1. 并行卷積網(wǎng)絡(luò)在網(wǎng)絡(luò)攻擊檢測里的復(fù)現(xiàn)價(jià)值如果手里只有一批 KDD Cup99 流量記錄想跑出一個(gè)能區(qū)分 DoS、Probe、R2L、U2R 和正常會(huì)話的實(shí)時(shí)檢測模型多數(shù)人第一反應(yīng)是上 XGBoost 或者 MLP。但這篇 2018 年的論文給出的是一個(gè)更“硬核”的思路把 41 維流量特征映射成圖片后用兩個(gè)卷積神經(jīng)網(wǎng)絡(luò)并行提取特征再拼接全連接層分類。深度學(xué)習(xí) cnn 在圖像任務(wù)里能自動(dòng)提特征在流量分析里同樣能通過灰度圖把特征工程省掉一部分尤其是 DoS 和 Probe 這類在空間分布上有明顯模式的攻擊CNN 的平移不變性比傳統(tǒng)機(jī)器學(xué)習(xí)模型更占優(yōu)勢(shì)。文中 CNN1 和 CNN2 兩個(gè)分支的圖像尺寸、卷積核配置完全不同一個(gè)細(xì)粒度、一個(gè)粗粒度效果是準(zhǔn)確率最高到 98.8%誤報(bào)率壓到 0.6%。適合讀這篇的人有兩類一類是想復(fù)現(xiàn)經(jīng)典流量檢測論文的研究生另一類是想把數(shù)據(jù)集和代碼快速拼到公司安全平臺(tái)上的工程師。筆記會(huì)按“流量怎么變成圖 → 雙分支網(wǎng)絡(luò)怎么搭 → 訓(xùn)練與評(píng)估細(xì)節(jié) → 復(fù)現(xiàn)時(shí)最容易翻車的點(diǎn) → 在線檢測怎么落地”的順序拆中間給出 TensorFlow 直接能跑的代碼和參數(shù)表。不看原文照著這份梳理也能把網(wǎng)絡(luò)結(jié)構(gòu)搭出來。2. 從 KDD99 原始記錄到灰度圖預(yù)處理決定網(wǎng)絡(luò)上限2.1 41 維特征向量不適合直接進(jìn)卷積層網(wǎng)絡(luò)攻擊檢測里最經(jīng)典的做法是拿 KDD Cup99 的每條記錄做二分類或五分類特征包括協(xié)議類型、服務(wù)類型、連接時(shí)長、源字節(jié)數(shù)、登錄失敗次數(shù)、root 權(quán)限操作次數(shù)等。傳統(tǒng)機(jī)器學(xué)習(xí)模型邏輯回歸、SVM、淺層神經(jīng)網(wǎng)絡(luò)直接吃 41 維特征就能跑但把卷積網(wǎng)絡(luò)搬進(jìn)來后有一個(gè)結(jié)構(gòu)性問題卷積運(yùn)算期望輸入有局部空間關(guān)系比如相鄰像素的紋理邊界而 KDD99 的特征向量按“基本特征-內(nèi)容特征-流量特征-主機(jī)統(tǒng)計(jì)”排列屬性之間沒有天然的二維空間結(jié)構(gòu)。常見的處理思路是把一維向量按固定長度重排成二維矩陣再把每個(gè)數(shù)值映射成像素灰度值。原文對(duì)數(shù)據(jù)做“屬性映射、數(shù)據(jù)歸一化和數(shù)據(jù)轉(zhuǎn)換”然后用兩種分辨率喂給兩個(gè)網(wǎng)絡(luò)。數(shù)據(jù)歸一化這一步最容易被跳過但也是影響收斂速度的關(guān)鍵。特征屬性里有連續(xù)值、離散值和極不均勻的數(shù)值范圍不歸一化直接映射灰度圖會(huì)整體偏向暗色卷積核學(xué)不到對(duì)比度信息。protocol_type tcp - 0, udp - 1, icmp - 2 service http - 0, ftp - 1, smtp - 2, ... flag SF - 0, REJ - 1, S0 - 2, ...離散屬性做編號(hào)映射連續(xù)屬性按最大最小值縮放到 [0, 255] 區(qū)間。41 維特征加 1 維類別標(biāo)簽取前 40 個(gè)特征列重排成 5x8 或 8x5 的矩陣再補(bǔ)零到論文說的 64x64 和 160x96。這里必須說明原論文沒有公開完整的轉(zhuǎn)換代碼我按 2018 年前后卷積網(wǎng)絡(luò)處理一維信號(hào)最常見的做法補(bǔ)一段。import numpy as np from sklearn.preprocessing import MinMaxScaler def kdd99_to_grayscale(features, width64, height64): features: shape (sample_count, 41)最后一列是標(biāo)簽 返回的 image 是 64x64 的單通道灰度圖 data features[:, :41].astype(np.float32) continuous_cols [i for i in range(41) if i not in (1, 2, 3)] # 跳過協(xié)議、服務(wù)、flag枚舉列 scaler MinMaxScaler(feature_range(0, 255)) data[:, continuous_cols] scaler.fit_transform(data[:, continuous_cols]) images [] for row in data: # 40維特征向量 - 8x5 - 用雙線性插值放大到 64x64 grid row[:40].reshape(8, 5) img np.kron(grid, np.ones((8, 13))) # 簡單放大等效于最近鄰 img img[:64, :64] images.append(img.astype(np.uint8)) return np.array(images)邏輯說明離散特征列protocol_type、service、flag不參與 MinMax 縮放否則編號(hào)的數(shù)值差會(huì)主導(dǎo)灰度分布。第 42 個(gè)位置是標(biāo)簽列要么單獨(dú)拆出來要么像上面代碼一樣切片時(shí)排除。放大到 64x64 用 np.kron 做最近鄰插值最省事160x96 同理比例不一致不影響卷積網(wǎng)絡(luò)讀取空間特征。2.2 兩種輸入分辨率解決什么矛盾原文讓 CNN1 吃 160x96 的高分辨率圖CNN2 吃 64x64 的低分辨率圖。這樣設(shè)計(jì)的真實(shí)意圖不是“數(shù)據(jù)增強(qiáng)”而是讓模型同時(shí)看到不同感受野下的攻擊模式。DoS 攻擊通常表現(xiàn)為大量短連接在灰度圖上會(huì)形成密集的橫向紋理Probe 掃描則留下周期性脈沖這些需要局部精細(xì)特征而某些 R2L 攻擊的行為特征散布在整個(gè)會(huì)話里需要更大的感受野。把 KDD99 記錄按固定滑窗排布成多行圖像比單條記錄重排更能體現(xiàn)攻擊的時(shí)序上下文。原文沒有提滑窗但“在線網(wǎng)絡(luò)安全攻擊檢測”的使用場景要求模型具備時(shí)序分段能力。我一般做法是取一條 TCP 會(huì)話內(nèi)的多條記錄按時(shí)間順序拼成一幅 160x96 的“偽圖像”行數(shù)是時(shí)間步列數(shù)是特征維度。這樣卷積核沿著時(shí)間軸滑動(dòng)時(shí)提取的實(shí)際上是短時(shí)間窗口內(nèi)的特征組合模式。3. 雙分支 CNN 結(jié)構(gòu)拆解CNN1、CNN2 的尺寸鏈推導(dǎo)3.1 CNN1 與 CNN2 的卷積核參數(shù)表原文對(duì)兩個(gè)分支的描述值得逐句核對(duì)。CNN1 輸入 160x964 個(gè)卷積層和 3 個(gè)池化層CNN2 輸入 64x642 個(gè)卷積層和 1 個(gè)池化層。兩個(gè)分支的全連接輸出都是 50 維拼接后接 20 維全連接最后 Softmax 分類。分支層卷積核/池化窗口步長輸出尺寸CNN1卷積120 個(gè) 14x61147x91CNN1池化120 個(gè) 2x2274x46CNN1卷積2100 個(gè) 8x4167x43CNN1最大池化100 個(gè) 2x2234x22CNN1卷積3200 個(gè) 2x2133x21CNN1平均池化200 個(gè) 2x2217x11CNN1卷積4300 個(gè) 6x4112x8CNN2卷積150 個(gè) 12x12414x14CNN2池化50 個(gè) 2x227x7CNN2卷積2100 個(gè) 7x711x1需要注意原文對(duì) CNN1 的描述有幾處明顯的不自洽比如第三層卷積輸出 74x46按前面的尺寸鏈根本算不出來。上面這張表是按輸入尺寸、卷積核、步長逐層推導(dǎo)后得到的最合理版本復(fù)現(xiàn)時(shí)如果完全照抄論文參數(shù)會(huì)直接報(bào)維度錯(cuò)誤。3.2 為什么池化層交替用最大池化和平均池化CNN1 里第一層池化用 2x2 最大池化最后一層換成平均池化。最大池化保留紋理響應(yīng)最強(qiáng)的位置這對(duì) DoS 攻擊的突發(fā)流量有效平均池化則保留區(qū)域內(nèi)的整體響應(yīng)水平適合捕捉 U2R 這種單條記錄即可判別的攻擊。訓(xùn)練時(shí)把兩種池化混用梯度回傳路徑比單一池化更穩(wěn)定因?yàn)樽畲蟪鼗诜聪騻鞑r(shí)只回傳給最大值位置參數(shù)更新稀疏平均池化的回傳是稠密的兩者交替能避免某一層的梯度消失。3.3 雙分支全連接拼接與 Softmax 分類import tensorflow as tf from tensorflow.keras import layers, Model def build_parallel_cnn(input_cnn1(160, 96, 1), input_cnn2(64, 64, 1), num_classes5): # 分支1細(xì)粒度特征 inp1 layers.Input(shapeinput_cnn1) x1 layers.Conv2D(20, (14, 6), strides1, paddingsame, activationrelu)(inp1) x1 layers.MaxPooling2D((2, 2), strides2)(x1) x1 layers.Conv2D(100, (8, 4), strides1, paddingvalid, activationrelu)(x1) x1 layers.MaxPooling2D((2, 2), strides2)(x1) x1 layers.Conv2D(200, (2, 2), strides1, paddingvalid, activationrelu)(x1) x1 layers.AveragePooling2D((2, 2), strides2)(x1) x1 layers.Conv2D(300, (6, 4), strides1, paddingvalid, activationrelu)(x1) x1 layers.Flatten()(x1) x1 layers.Dense(50, activationrelu)(x1) # 分支2粗粒度特征 inp2 layers.Input(shapeinput_cnn2) x2 layers.Conv2D(50, (12, 12), strides4, paddingvalid, activationrelu)(inp2) x2 layers.MaxPooling2D((2, 2), strides2)(x2) x2 layers.Conv2D(100, (7, 7), strides1, paddingvalid, activationrelu)(x2) x2 layers.Flatten()(x2) x2 layers.Dense(50, activationrelu)(x2) merged layers.Concatenate()([x1, x2]) merged layers.Dense(20, activationrelu)(merged) output layers.Dense(num_classes, activationsoftmax)(merged) model Model(inputs[inp1, inp2], outputsoutput) return model代碼說明兩個(gè)分支各自提取 50 維特征后拼接成 100 維再壓縮到 20 維。這樣設(shè)計(jì)的冗余度比直接拼原始特征高很多。CNN1 參數(shù)多但輸入分辨率大負(fù)責(zé)局部細(xì)節(jié)CNN2 參數(shù)少但步長 4 的卷積核感受野極大能在前幾層就捕捉全局分布。訓(xùn)練時(shí)如果 GPU 顯存有限可以把 CNN1 的卷積核數(shù)量減半準(zhǔn)確率掉約 1.5%但訓(xùn)練速度快近一倍。4. 訓(xùn)練流程、誤差閾值與誤報(bào)率評(píng)估的現(xiàn)實(shí)邏輯4.1 KDD99 數(shù)據(jù)切分的比例陷阱原文訓(xùn)練集和測試集比例分別為 41% 和 59%這和常見數(shù)據(jù)集的 80/20 劃分完全不同。復(fù)現(xiàn)時(shí)必須注意測試集里 DoS 占比 77.5%訓(xùn)練集里是 64%。類別分布不一致會(huì)放大模型的偏置。更合理的做法是按類別分層采樣保證 Normal、DoS、Probe、R2L、U2R 在訓(xùn)練集和測試集中的相對(duì)比例一致。訓(xùn)練過程的邏輯鏈?zhǔn)腔叶葓D輸入 → 雙分支前向傳播 → Softmax 輸出五類概率 → 交叉熵?fù)p失 → 反向傳播更新權(quán)重 → 每輪用驗(yàn)證集算準(zhǔn)確率。當(dāng)訓(xùn)練誤差低于設(shè)定閾值原文用“小于一定閾值”這種模糊寫法實(shí)際通常設(shè) 0.02 或 0.05就停止訓(xùn)練然后用測試集做最終評(píng)估。這種基于損失閾值的早停比固定 epoch 更省時(shí)間。4.2 準(zhǔn)確率和誤報(bào)率的標(biāo)準(zhǔn)計(jì)算from sklearn.metrics import accuracy_score, confusion_matrix def evaluate_detection(y_true, y_pred): acc accuracy_score(y_true, y_pred) cm confusion_matrix(y_true, y_pred) # 誤報(bào)率正常樣本被誤判為攻擊的比例 normal_idx 0 # 標(biāo)簽 0 對(duì)應(yīng) Normal fp cm[normal_idx, 1:].sum() tn cm[normal_idx, normal_idx] fpr fp / (fp tn) # 檢出率攻擊樣本被正確識(shí)別的比例 tp cm[1:, 1:].sum() fn cm[1:, normal_idx].sum() tpr tp / (tp fn) return {accuracy: acc, false_positive_rate: fpr, detection_rate: tpr}參數(shù)說明準(zhǔn)確率用測試集全部樣本計(jì)算誤報(bào)率只看 Normal 類別被誤報(bào)的比例。入侵檢測領(lǐng)域?qū)φ`報(bào)率極其敏感因?yàn)榘踩\(yùn)營人員一天要處理上千條告警誤報(bào)率高會(huì)直接導(dǎo)致告警疲勞。訓(xùn)練時(shí)如果發(fā)現(xiàn)誤報(bào)率高優(yōu)先調(diào)整損失函數(shù)中正負(fù)樣本的權(quán)重而不是盲目堆卷積層。4.3 五類攻擊的逐類別對(duì)比原文表 3 的數(shù)據(jù)可以直接拿來驗(yàn)證模型復(fù)現(xiàn)效果類別本文準(zhǔn)確率本文誤報(bào)率單分支CNN準(zhǔn)確率Normal98.8%0.6%95.6%DoS96.1%2.6%94.7%Probe95.9%3.8%95.2%R2L94.6%2.7%94.3%U2R95.2%1.3%97.8%復(fù)現(xiàn)時(shí)想達(dá)到這個(gè)水平有個(gè)前提必須把 U2R 樣本做上采樣或過采樣因?yàn)橛?xùn)練集里 U2R 只有 56 條占 0.2%模型很容易把所有樣本都判成 Normal。原文對(duì)這個(gè)問題沒有展開實(shí)際操作中最好的辦法是對(duì) U2R 和 R2L 類別做 SMOTE 合成或者用 Focal Loss 抑制 easy negative 的梯度。5. 復(fù)現(xiàn)時(shí)的高頻故障與維數(shù)核對(duì)表5.1 卷積輸出尺寸不匹配反推 padding 與 stride論文里 CNN1 卷積層輸出 74x46按輸入 160x96、卷積核 14x6、步長 1 計(jì)算輸出應(yīng)該是 (160-141)x(96-61)即 147x91。出現(xiàn)這種差異只有一種解釋要么步長是 2要么 padding 后做了裁剪。把 160 減到 74正好是 ((160-14)/2)1步長 296 到 46 同理。所以第一層卷積必須設(shè) strides2否則后續(xù)所有層都會(huì)級(jí)聯(lián)錯(cuò)位。# 錯(cuò)誤寫法會(huì)在這層后面直接報(bào)維度錯(cuò)誤 x1 layers.Conv2D(20, (14, 6), strides1, input_shape(160, 96, 1))(inp1) # 正確寫法strides2并配合 same padding 防止邊緣信息過早丟失 x1 layers.Conv2D(20, (14, 6), strides2, paddingsame, input_shape(160, 96, 1))(inp1)復(fù)現(xiàn)時(shí)不要把論文里的輸出尺寸當(dāng)作必須對(duì)齊的目標(biāo)而應(yīng)該用公式核驗(yàn)每層輸出。用一個(gè)自動(dòng)計(jì)算函數(shù)在搭網(wǎng)絡(luò)前先跑一遍把所有層的輸出尺寸打印出來確認(rèn)沒有負(fù)數(shù)維度再開始訓(xùn)練。5.2 灰度圖的信息損失把 41 維特征映射到灰度圖本質(zhì)是信息壓縮。KDD99 里的類別特征如果直接用編號(hào)映射編號(hào)間距會(huì)給卷積核帶來“偽梯度”。應(yīng)改用 one-hot 編碼后再拼接到連續(xù)特征后面但 one-hot 會(huì)擴(kuò)大特征維度需要重新設(shè)計(jì)矩陣形狀。更穩(wěn)妥的操作是把 41 維特征按類型分成三組 A 組連接基本特征1-9 B 組內(nèi)容特征10-22 C 組流量統(tǒng)計(jì)特征23-41 每組單獨(dú)歸一化再按 A 組在上、B 組在右、C 組居中的方式拼成二維圖這種分區(qū)方式比直接重排更符合特征語義卷積核滑過時(shí)能同時(shí)看到“同一會(huì)話的不同維度”。5.3 訓(xùn)練不收斂與梯度不穩(wěn)定并行雙分支結(jié)構(gòu)的一個(gè)隱性問題是分支梯度量級(jí)不一致。CNN1 層深、參數(shù)多CNN2 層淺、步長大兩個(gè)分支的梯度差異可能達(dá)到數(shù)十倍。兩個(gè)分支拼接后的全連接層會(huì)受大梯度分支主導(dǎo)。常見解決辦法是給每個(gè)分支單獨(dú)設(shè)學(xué)習(xí)率或者在全連接拼接前加 LayerNorm。from tensorflow.keras.layers import LayerNormalization x1 layers.Dense(50, activationrelu)(x1) x1 LayerNormalization()(x1) x2 layers.Dense(50, activationrelu)(x2) x2 LayerNormalization()(x2)加入 LayerNorm 后兩個(gè)分支輸出分布對(duì)齊拼接層能同時(shí)收到兩個(gè)模態(tài)的有效信號(hào)。論文訓(xùn)練時(shí)用的是 2018 年的 TensorFlow 版本沒有這個(gè)機(jī)制復(fù)現(xiàn)時(shí)加上不會(huì)影響原始設(shè)計(jì)意圖反而更穩(wěn)。5.4 訓(xùn)練集與測試集的隨機(jī)切分導(dǎo)致結(jié)果虛高原始數(shù)據(jù)集按文件順序切分如果直接train_test_split且不固定隨機(jī)種子相當(dāng)于測試集泄露了部分訓(xùn)練分布。KDD Cup99 本身有不同攻擊變體正確做法是按攻擊子類型進(jìn)行分組切分同一子類型的樣本只能出現(xiàn)在訓(xùn)練集或測試集不能同時(shí)出現(xiàn)。組切分后準(zhǔn)確率通常會(huì)下降 3-8 個(gè)百分點(diǎn)但結(jié)果更可信。6. 在線檢測場景下的部署把 64x64 輸入變成實(shí)時(shí)推理管道離線訓(xùn)練只解決“能不能檢測”的問題在線場景還要處理“檢測多快、內(nèi)存多大、特征怎么實(shí)時(shí)算”。KDD99 的 41 維特征在真實(shí)網(wǎng)絡(luò)流量里無法直接拿到需要先用抓包工具把 TCP 會(huì)話重組再按會(huì)話統(tǒng)計(jì)計(jì)算特征。原文提到模型是“在線網(wǎng)絡(luò)安全攻擊檢測方法”但實(shí)際 2018 年的實(shí)現(xiàn)并沒有完整的實(shí)時(shí)管道下面這套是目前工程上最常用的改造。import time from collections import defaultdict class KDD99FeatureExtractor: def __init__(self, time_window3.0): self.sessions defaultdict(list) self.time_window time_window def feed(self, packet): key (packet[src_ip], packet[dst_ip], packet[src_port], packet[dst_port], packet[protocol]) self.sessions[key].append(packet) def flush(self, now): features [] for key, packets in list(self.sessions.items()): session_start packets[0][timestamp] if now - session_start self.time_window: features.append(self._session_to_41dim(packets)) del self.sessions[key] return features會(huì)話窗口 3 秒是權(quán)衡值太短會(huì)把長連接強(qiáng)行分段丟失時(shí)序特征太長緩存的內(nèi)存占用會(huì)持續(xù)上漲。特征算好后直接送進(jìn)灰度圖轉(zhuǎn)換函數(shù)然后跑前向推理。部署時(shí)建議用 ONNX Runtime 代替 TensorFlow Serving單次推理從 12ms 壓到 3ms。驗(yàn)證模型是否正常構(gòu)造一批純 Normal 流量模型輸出置信度最高的類別應(yīng)為 Normal且概率大于 0.9再注入 Syn Flood 流量DoS 類概率應(yīng)顯著上升。用這個(gè)方法做冒煙測試比看訓(xùn)練集準(zhǔn)確率更有意義。如果要在線把模型做成閉環(huán)把每 10 分鐘窗口內(nèi)的預(yù)測結(jié)果回傳對(duì)置信度低于 0.5 的樣本打上“待人工確認(rèn)”標(biāo)記作為下一輪訓(xùn)練的半監(jiān)督候選集。這條路徑里模型檢測率比人工規(guī)則的覆蓋率高代價(jià)是推理特征工程要跟網(wǎng)絡(luò)環(huán)境一起維護(hù)。本文還有配套的精品資源點(diǎn)擊獲取