基于监督学习的Web入侵检测系统:从特征工程到模型部署的毕业设计实战
发布时间:2026/10/10 20:39:12 锦皓数字建站

简介这份资源是面向高校学生与初学者的毕业设计/期末大作业级项目主题为基于监督学习的Web入侵检测系统适合需要完成课程设计、毕设或想入门机器学习安全应用的人群。压缩包共60个文件约2.25MB以ipynb实验笔记、txt样本与词表、html原始请求页面、py脚本为主另含pkl/pickle模型文件与md说明覆盖数据爬取、字符处理、去重、参数提取、模型保存等完整流程。已有145人学习下载。代码注释详尽新手也能看懂下载后简单部署即可运行可直接作为高分项目参考。目录按功能模块划分清晰包含正常与恶意请求样本、关键词列表及多份实验记录便于理解监督学习在Web攻击识别中的特征工程与训练思路也方便在此基础上二次修改与扩展。1. 从一份毕业设计说起监督学习怎么做 Web 入侵检测很多同学做毕业设计时第一反应是「找个开源 WAF 改一改」结果发现规则库看不懂、日志格式对不上、答辩时被问「你的模型在哪」直接卡壳。基于监督学习的 Web 入侵检测系统核心思路其实很朴素把 HTTP 请求当成一条样本用带标签的历史流量训练分类器让模型自己学会区分正常请求和攻击请求。它解决的是传统规则匹配「写不完、跟不上、误报高」的问题适合安全方向毕业生、刚接触 ML 的运维以及想给现有站点加一层智能检测的开发者。这一章先把「监督学习 Web 入侵检测」这条链路讲清楚后面几章再落到源码结构、特征工程、模型训练和文档说明怎么写。2. 系统架构与源码目录先看懂再动手2.1 为什么选监督学习而不是无监督Web 入侵检测的公开数据集如 CSIC 2010、ECML/PKDD 2007都带正常/异常标签这天然适合监督学习。无监督方法如孤立森林虽然不需要标注但毕业设计答辩时很难解释「为什么这条被判为攻击」——你拿不出一个明确的决策边界。监督学习可以用准确率、召回率、F1 值量化论文里好写代码里好调。常见做法是先用随机森林或 XGBoost 跑基线再用 LSTM 或 TextCNN 做序列特征对比最后选一个综合指标最好的作为主模型。选型时注意Web 请求是短文本字符级特征比词级更稳因为攻击载荷里经常出现../、script、union select这类没有自然语言语义的片段。我一般会先做字符级 TF-IDF再上 n-gram最后才考虑深度学习。2.2 源码目录应该长什么样一个能跑通、能写进文档说明的工程目录不要贪多按职责分四层就够web_ids/ ├── data/ # 原始数据集与预处理后的特征文件 │ ├── raw/ # CSIC 2010 等原始数据 │ └── processed/ # 向量化后的 npz / csv ├── src/ │ ├── preprocess.py # 请求解析、URL 解码、特征提取 │ ├── features.py # TF-IDF / n-gram / 统计特征 │ ├── train.py # 模型训练与交叉验证 │ ├── evaluate.py # 混淆矩阵、ROC、指标输出 │ └── detect.py # 单条请求推理接口 ├── models/ # 保存的模型文件joblib / h5 ├── configs/ │ └── config.yaml # 路径、超参数、阈值 ├── docs/ │ └── 文档说明.md # 环境、数据、训练、推理、指标 └── requirements.txt这个结构的好处是preprocess.py和features.py分离答辩时能说清「数据清洗」和「特征工程」是两件事detect.py单独提供推理入口方便演示。文档说明里要写清楚每个文件的作用、输入输出格式、运行顺序不要只贴代码。2.3 环境依赖与最小可运行配置# Python 3.8建议用虚拟环境 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install numpy pandas scikit-learn xgboost joblib flask pyyaml # 如果要用深度学习模型再加 pip install torch torchvision # 或 tensorflowrequirements.txt里锁定版本比如scikit-learn1.3.0避免答辩现场因为版本差异跑不起来。配置文件config.yaml把路径和超参数抽出来data: raw_path: data/raw/csic2010.txt processed_path: data/processed/features.npz model: type: random_forest n_estimators: 200 max_depth: 20 test_size: 0.2 random_state: 42 detect: threshold: 0.5参数说明n_estimators是树的数量200 在 CSIC 数据集上已经能到 0.98 左右的准确率max_depth控制过拟合20 是经验值threshold是判定为攻击的概率阈值演示时可以调到 0.3 让攻击样本更容易被检出但误报会上升。3. 特征工程与模型训练把 HTTP 请求变成向量3.1 请求解析与标签对齐CSIC 2010 的原始格式是「请求行 请求头 请求体」正常请求和攻击请求混在一起。预处理第一步是把每条请求拆成方法、URL、参数、Body 四部分然后统一做 URL 解码和大小写归一化。import urllib.parse import re def parse_request(raw_line): 把一行原始请求解析成结构化字段 parts raw_line.strip().split( , 2) if len(parts) 3: return None method, url, body parts # URL 解码攻击载荷里常见 %2e%2e%2f 这类编码 url_decoded urllib.parse.unquote(url) body_decoded urllib.parse.unquote(body) # 提取参数个数、特殊字符数等统计特征 special_chars len(re.findall(r[\;()], url_decoded body_decoded)) return { method: method, url: url_decoded, body: body_decoded, url_len: len(url_decoded), body_len: len(body_decoded), special_count: special_chars, has_sql_keyword: int(bool(re.search(r(union|select|insert|drop), (url_decoded body_decoded).lower()))) }逻辑说明urllib.parse.unquote把%2e%2e%2f还原成../否则模型学不到路径穿越特征。special_count统计特殊字符数量SQL 注入和 XSS 载荷通常比正常请求多。has_sql_keyword是一个简单的规则特征和 TF-IDF 互补。参数上url_len和body_len对异常检测很有效因为攻击载荷往往比正常参数长。标签对齐时注意CSIC 数据集里正常请求和攻击请求是分开的文件合并后要打上label0/1并且打乱顺序否则训练集和测试集分布不一致。3.2 字符级 TF-IDF 与 n-gram 参数怎么设from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.model_selection import train_test_split import numpy as np def build_features(texts, labels): # 字符级 n-gramngram_range(1,3) 覆盖单字符到三字符组合 vectorizer TfidfVectorizer( analyzerchar, ngram_range(1, 3), max_features5000, min_df2, sublinear_tfTrue ) X vectorizer.fit_transform(texts) y np.array(labels) return X, y, vectorizer # 假设 texts 是 url body 拼接后的字符串列表 X, y, vec build_features(texts, labels) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy )参数说明analyzerchar是关键Web 攻击载荷里、、/这些字符单独出现就有意义词级分词会丢掉。ngram_range(1,3)能捕捉../、script、union select这类片段再大容易过拟合。max_features5000在 CSIC 上足够太多会拖慢训练。min_df2过滤只出现一次的特征降低噪声。sublinear_tfTrue用对数缩放词频避免高频字符主导。如果要用统计特征和 TF-IDF 拼接用scipy.sparse.hstackfrom scipy.sparse import hstack # stats_matrix 是 parse_request 输出的数值特征矩阵 X_combined hstack([X, stats_matrix])注意稀疏矩阵拼接时维度要对齐stats_matrix也要转成csr_matrix。3.3 随机森林训练与交叉验证from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import cross_val_score from sklearn.metrics import classification_report, confusion_matrix import joblib clf RandomForestClassifier( n_estimators200, max_depth20, min_samples_split5, class_weightbalanced, random_state42, n_jobs-1 ) # 5 折交叉验证看模型稳定性 cv_scores cross_val_score(clf, X_train, y_train, cv5, scoringf1) print(fCV F1: {cv_scores.mean():.4f} (/- {cv_scores.std():.4f})) clf.fit(X_train, y_train) y_pred clf.predict(X_test) print(classification_report(y_test, y_pred)) print(confusion_matrix(y_test, y_pred)) joblib.dump(clf, models/rf_model.pkl) joblib.dump(vec, models/tfidf_vectorizer.pkl)参数说明class_weightbalanced在攻击样本少于正常样本时很重要否则模型会偏向多数类。min_samples_split5防止过拟合。n_jobs-1用满 CPU 核。交叉验证的 F1 均值如果低于 0.95检查特征工程是否有漏或者数据集标签是否对齐。训练完把模型和向量化器一起保存推理时必须用同一个向量化器否则特征维度对不上。3.4 推理接口与阈值调整import joblib import numpy as np model joblib.load(models/rf_model.pkl) vectorizer joblib.load(models/tfidf_vectorizer.pkl) def detect(request_text, threshold0.5): X vectorizer.transform([request_text]) prob model.predict_proba(X)[0][1] # 攻击类概率 return { is_attack: bool(prob threshold), probability: round(float(prob), 4) } # 演示 result detect(GET /admin.php?id1 OR 11 HTTP/1.1) print(result) # {is_attack: True, probability: 0.97}阈值threshold是演示时最常被问的参数。默认 0.5 平衡误报和漏报如果答辩时想展示检出率可以调到 0.3但要说清「生产环境需要根据业务容忍度调整」。predict_proba返回的是概率比predict的硬标签更有解释力。4. 避坑与排查那些答辩现场容易翻车的地方4.1 现象训练准确率 0.99测试只有 0.6原因数据泄露。常见错误是在train_test_split之前就做了 TF-IDF 拟合导致测试集的信息进入训练。解决先划分训练集和测试集再在训练集上fit_transform测试集只transform。# 正确顺序 X_train_text, X_test_text, y_train, y_test train_test_split( texts, labels, test_size0.2, random_state42, stratifylabels ) vectorizer TfidfVectorizer(analyzerchar, ngram_range(1,3), max_features5000) X_train vectorizer.fit_transform(X_train_text) X_test vectorizer.transform(X_test_text) # 只 transform4.2 现象模型把正常请求判成攻击误报高原因正常请求里也有select、script这类词比如搜索框输入「select 教程」。解决不要只用关键词规则TF-IDF 的上下文 n-gram 能区分select单独出现和union select组合出现。另外可以加白名单机制对已知正常参数放行。4.3 现象推理时报「特征维度不匹配」原因保存模型时用了max_features5000推理时重新fit了一个新的向量化器维度可能变成 4800。解决向量化器和模型必须一起保存、一起加载推理时只调用transform不要重新fit。4.4 现象CSIC 数据集加载后标签全是 0原因CSIC 2010 的正常请求和攻击请求在不同文件合并时忘了给攻击文件打label1。解决写一个load_csic函数分别读取两个文件正常文件label0攻击文件label1然后pd.concat并sample(frac1)打乱。4.5 现象答辩时被问「你的模型可解释性在哪」原因只报了准确率没有特征重要性。解决随机森林可以输出feature_importances_取 Top 20 特征对应回字符 n-gram就能解释「模型主要看哪些字符组合」。import numpy as np importances clf.feature_importances_ feature_names vectorizer.get_feature_names_out() top_idx np.argsort(importances)[-20:][::-1] for i in top_idx: print(f{feature_names[i]}: {importances[i]:.4f})5. 文档说明怎么写才像一份能交付的工程文档5.1 文档结构从环境到指标缺一不可一份合格的文档说明至少包含六部分环境依赖、数据说明、目录结构、训练步骤、推理步骤、指标结果。不要写成论文的「绪论」风格直接按操作顺序写。比如「数据说明」里要写清楚 CSIC 2010 的下载来源、文件格式、样本数量、标签定义「训练步骤」里写python src/train.py --config configs/config.yaml并说明每个参数的含义。5.2 指标表格与对比实验文档里放一张对比表把随机森林、XGBoost、TextCNN 的指标列出来答辩时一目了然模型准确率召回率F1训练耗时随机森林0.9820.9760.97912sXGBoost0.9850.9810.98325sTextCNN0.9780.9700.9743min表格里的数字要来自你自己的evaluate.py输出不要抄网上的。训练耗时也写上体现工程意识。5.3 一个容易被忽略的细节推理演示脚本文档最后附一个demo.py读一条请求输出检测结果和概率。答辩现场直接跑比 PPT 截图有说服力。# demo.py from src.detect import detect test_requests [ GET /index.html HTTP/1.1, GET /admin.php?id1 OR 11 HTTP/1.1, POST /comment?textscriptalert(1)/script HTTP/1.1 ] for req in test_requests: print(req[:50], -, detect(req, threshold0.5))这个脚本要能在 10 秒内跑完依赖越少越好。如果模型加载慢可以在启动时预加载不要每次调用都joblib.load。5.4 版本控制与可复现性把requirements.txt、config.yaml、models/下的模型文件一起提交但模型文件如果太大超过 100MB可以只提交训练脚本和随机种子文档里写清楚「运行train.py可复现模型」。随机种子固定random_state42保证每次训练结果一致。我自己的习惯是答辩前一周把整个工程拷到一台干净机器上从pip install开始跑一遍把遇到的每个报错都记下来补进文档的「常见问题」里。这样现场不管谁问你都有答案。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。