首页 / 资讯中心 / 文章详情

基于监督学习的Web入侵检测毕设源码:从数据到模型全流程解析

基于监督学习的Web入侵检测毕设源码:从数据到模型全流程解析 ★ FEATURED ARTICLE
简介这份资源是面向计算机相关专业学生与从业者的高分毕业设计源码包主题为基于监督学习的Web入侵检测系统采用Python实现评审得分达97分可直接用于毕业设计、期末课程设计或课程大作业等场景。压缩包共60个文件约2.25MB以18个ipynb实验笔记、14个txt样本与词表、14个html页面样本、8个py脚本为主另含pkl与pickle模型文件、md说明文档等覆盖数据采集、字符处理、去重、特征提取与模型保存等完整流程。内容预览显示项目包含爬虫脚本、正常与恶意请求样本、关键词表及多份Jupyter实验记录便于理解监督学习在Web入侵检测中的特征工程与建模思路。目前已有188人学习下载适合需要完整项目方案、可运行代码与排错参考的读者借鉴使用。1. 从一份 97 分毕设源码说起监督学习做 Web 入侵检测到底靠不靠谱很多同学做毕设时都会卡在同一个地方题目选好了方向也定了但真正动手时发现要么数据找不到要么模型跑不通要么代码写完自己都不知道对不对。这份基于监督学习的 Web 入侵检测系统 Python 源码就是冲着这个痛点来的——它是一套完整可运行的毕设级项目从 HTTP 请求日志的采集、payload 参数提取、字符级特征处理到监督学习模型训练和检测整条链路都有对应的脚本和 notebook。它解决的核心问题是把原始 Web 访问日志变成模型能吃的特征向量再用监督学习算法判断某条请求是正常访问还是恶意攻击。适合计算机相关专业的本科生做毕业设计、期末大作业也适合刚入行安全方向、想动手跑一遍入侵检测流程的从业者。源码里包含了爬虫脚本、字符处理脚本、去重脚本、参数提取 notebook、模型核心代码以及多个 pickle/joblib 序列化文件结构上覆盖了从数据到模型的全流程。下面我按实际拆包的顺序把这份资源怎么用、参数怎么调、哪里容易翻车讲清楚。2. 拆开源码包reptile.py 到 core.py 的数据链路与模块职责2.1 从 reptile.py 到 payload.txt原始请求怎么变成可训练数据拿到源码包后第一件事不是急着跑模型而是先理清数据从哪来、经过哪些脚本、最终变成什么格式。这份资源的根目录下有几个关键文件reptile.py负责爬取或采集原始 HTTP 请求数据wordProcess.py做字符级处理removeRepeat.py去重makeChar.py生成字符集core.py是模型训练和检测的核心逻辑。src目录下存放的是原始素材包括大量ff_*.html、ff_*.txt以及access_log_payload*.txt、payload.txt、normal_require.txt、safe_key.txt、normal-use1.txt等文件。这些文件的分工大致是这样的ff_*.html和ff_*.txt是原始请求样本access_log_payload*.txt是从访问日志中提取出的 payload 片段payload.txt是汇总后的恶意 payload 集合normal_require.txt和normal-use1.txt是正常请求样本safe_key.txt是安全关键词白名单。整个数据链路可以概括为原始日志 → payload 提取 → 字符处理 → 去重 → 特征向量 → 模型训练。我一般会先打开README.md确认作者标注的运行顺序然后用count.py统计一下各类样本的数量分布。这一步很关键因为监督学习最怕的就是正负样本严重不均衡。如果恶意样本只有几十条而正常样本有几千条后面训练出来的模型大概率会偏向多数类检测效果会很难看。# 先看目录结构和文件数量心里有个底 ls -la find . -name *.py | head -20 find . -name *.txt | wc -l find . -name *.html | wc -l # 统计关键样本文件的行数判断正负样本比例 wc -l src/payload.txt wc -l src/normal_require.txt wc -l src/normal-use1.txt wc -l src/safe_key.txt上面这几条命令的作用是快速摸清数据规模。find . -name *.py列出所有 Python 脚本确认核心文件是否齐全wc -l统计样本行数如果payload.txt只有几十行而normal_require.txt有上千行那后面就必须做样本均衡处理否则模型会严重偏斜。常见做法是用欠采样把正常样本降到和恶意样本同一量级或者用 SMOTE 做过采样但这份源码里没有内置均衡逻辑需要自己补。2.2 wordProcess.py 与 removeRepeat.py字符级特征处理的两个关键脚本wordProcess.py是整个特征工程的核心入口。它的作用是把原始请求字符串拆成字符序列再做归一化处理。Web 入侵检测和自然语言处理有个相似点请求 payload 本身就是一串字符SQL 注入、XSS、命令注入这些攻击在字符层面有比较明显的模式比如大量单引号、尖括号、分号、union select、../等。所以用字符级特征做监督学习是合理的不一定非要上词向量。removeRepeat.py负责去重避免同一条 payload 在训练集里反复出现导致模型过拟合。这个脚本通常会读取payload.txt和normal_require.txt对每一行做哈希或字符串比对输出去重后的文件。makeChar.py则是生成字符集字典把所有出现过的字符映射成整数索引供模型输入使用。# wordProcess.py 的典型处理逻辑根据源码结构还原 import re def normalize_payload(payload: str) - str: 对原始 payload 做归一化转小写、URL 解码、去除多余空白 payload payload.strip().lower() # URL 解码把 %27 还原成单引号等 payload re.sub(r%([0-9a-fA-F]{2}), lambda m: chr(int(m.group(1), 16)), payload) # 把连续空白压成一个空格 payload re.sub(r\s, , payload) return payload def char_tokenize(payload: str, char2idx: dict, max_len: int 200): 把字符串转成整数索引序列超长截断不足补零 ids [char2idx.get(ch, char2idx.get(UNK, 0)) for ch in payload[:max_len]] ids [0] * (max_len - len(ids)) return ids这段代码的逻辑说明normalize_payload先做小写化和 URL 解码因为攻击者经常用编码绕过简单规则char_tokenize把字符映射成整数max_len控制序列长度太短会丢信息太长会增加计算量。参数方面max_len200是一个经验值Web 请求的 payload 通常不会超过这个长度如果数据集里有很多超长请求可以调到 500 甚至 1000但要注意显存或内存占用。UNK是未知字符的兜底索引防止测试时遇到训练集没出现过的字符直接报错。提示wordProcess.py和wordProcess.pyc同时存在说明作者可能用py_compile编译过。直接跑.py就行.pyc是缓存不用管。2.3 core.py 与 pickle/joblib 文件模型训练与持久化的实际流程core.py是模型训练和推理的主入口。从目录里的save_with_pickle.ipynb、save_with_joblib.ipynb、test.pickle、jpblib.pkl、joblib.pkl可以看出作者用了 pickle 和 joblib 两种方式做模型持久化。core.ipynb和core.py内容应该基本一致notebook 方便调试.py方便直接运行。监督学习部分常见做法是用 scikit-learn 里的分类器比如朴素贝叶斯、逻辑回归、随机森林或 SVM。考虑到字符级特征维度较高朴素贝叶斯和逻辑回归比较轻量随机森林效果通常更稳但训练慢一些。源码里没有明确写用哪个算法但从core.py的命名和getNormalPara.py、getPayloadPrarmaters.ipynb这些文件来看作者应该是先提取正常请求和恶意请求的参数特征再喂给分类器。# core.py 的典型训练流程根据源码结构还原 import joblib import numpy as np from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report # 假设 X 是字符索引矩阵y 是标签0 正常1 恶意 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) clf RandomForestClassifier( n_estimators100, # 树的数量越多越稳但越慢 max_depth20, # 控制过拟合太深会记住训练集 min_samples_leaf2, # 叶子节点最少样本数防止噪声影响 random_state42, n_jobs-1 # 用满所有 CPU 核心 ) clf.fit(X_train, y_train) # 输出评估报告重点看恶意类的 recall y_pred clf.predict(X_test) print(classification_report(y_test, y_pred, target_names[normal, malicious])) # 持久化模型后面检测时直接加载 joblib.dump(clf, web_ids_rf.joblib)参数说明n_estimators100是随机森林的默认起点如果训练集很大可以加到 200 或 300max_depth20是为了防止树长得太深导致过拟合实际调参时可以用交叉验证选stratifyy保证训练集和测试集里正负样本比例一致这个在样本不均衡时特别重要。评估时不要只看 accuracy因为如果恶意样本只占 5%全预测成正常也有 95% 的准确率但实际毫无用处。重点看 malicious 类的 recall 和 F1-score。save_with_pickle.ipynb和save_with_joblib.ipynb的区别在于序列化方式。pickle 是 Python 标准库通用但跨版本兼容性差joblib 对 numpy 数组优化更好文件更小、加载更快。我一般优先用 joblib尤其是模型里包含大量数组参数时。3. 把源码跑起来环境配置、notebook 执行顺序与参数调整3.1 Python 环境与依赖安装numpy、scikit-learn、joblib 一个都不能少这份源码是纯 Python 项目没有复杂的深度学习框架依赖所以环境配置不算麻烦。但有几个库是必须的numpy做数值计算scikit-learn做模型训练和评估joblib做模型持久化pandas可能在 notebook 里用于数据查看。如果reptile.py里用了 requests 或 scrapy还需要装对应的爬虫库。# 建议用虚拟环境避免污染系统 Python python -m venv venv source venv/bin/activate # Linux/Mac # venv\Scripts\activate # Windows # 安装核心依赖 pip install numpy scikit-learn joblib pandas pip install requests beautifulsoup4 # reptile.py 可能需要 # 确认版本避免 scikit-learn 版本差异导致模型加载失败 python -c import sklearn; print(sklearn.__version__) python -c import numpy; print(numpy.__version__)这里有个血泪经验scikit-learn 不同版本之间pickle/joblib 文件的兼容性可能有问题。如果加载test.pickle时报AttributeError或ModuleNotFoundError大概率是版本不匹配。解决办法是看README.md里有没有标注版本或者用pip install scikit-learn1.x.x装一个接近的版本。如果实在加载不了就重新跑一遍core.py训练不要死磕旧模型文件。注意jpblib.pkl这个文件名看起来像是joblib.pkl的拼写变体加载时先确认实际文件名不要直接照抄代码里的路径。3.2 notebook 执行顺序从 firstTry 到 core 的推荐路径源码包里有一堆.ipynb文件firstTry.ipynb、justTest.ipynb、some test.ipynb、getPayloadPrarmaters.ipynb、getNormalParamaters.ipynb、core.ipynb、save_with_pickle.ipynb、save_with_joblib.ipynb。这些 notebook 不是随便放的它们反映了作者的开发顺序。我建议按以下顺序执行第一步打开firstTry.ipynb看看作者最初怎么读取数据、怎么定义标签。这个文件通常比较粗糙但能帮你快速理解数据格式。第二步跑getPayloadPrarmaters.ipynb和getNormalParamaters.ipynb这两个负责从恶意和正常样本中提取参数特征。第三步跑wordProcess.py和removeRepeat.py生成去重后的字符序列。第四步跑core.ipynb或core.py训练模型并输出评估结果。最后用save_with_joblib.ipynb保存模型方便后续检测调用。# 在 notebook 里检查数据加载是否正常 import pandas as pd # 读取 payload 和正常请求注意编码问题 with open(src/payload.txt, r, encodingutf-8, errorsignore) as f: malicious [line.strip() for line in f if line.strip()] with open(src/normal_require.txt, r, encodingutf-8, errorsignore) as f: normal [line.strip() for line in f if line.strip()] print(f恶意样本数: {len(malicious)}) print(f正常样本数: {len(normal)}) print(f正负比: 1:{len(normal)/max(len(malicious),1):.1f}) # 看几条样本确认数据质量 for s in malicious[:3]: print(MAL:, s[:120]) for s in normal[:3]: print(NOR:, s[:120])这段代码的关键是errorsignore因为原始日志里可能有非 UTF-8 字符不加这个参数会直接报UnicodeDecodeError。打印正负比是为了判断要不要做样本均衡。如果比例超过 1:10建议先欠采样正常样本再训练。查看前几条样本可以直观感受数据质量如果恶意样本里混了大量正常请求说明数据标注有问题需要手动清洗。3.3 关键参数怎么调max_len、n_estimators 与 test_size 的取舍这份源码里没有集中的配置文件参数散落在各个脚本和 notebook 里。根据我的经验有三个参数对结果影响最大字符序列长度max_len、随机森林的n_estimators、以及训练集划分的test_size。max_len决定每条请求保留多少字符。设得太小比如 50长 payload 的关键攻击特征会被截掉设得太大比如 1000特征维度爆炸训练慢且容易过拟合。Web 请求的 payload 大部分在 100 到 300 字符之间所以max_len200到300是比较稳的选择。可以在 notebook 里画一下 payload 长度分布选覆盖 90% 样本的长度作为max_len。n_estimators是随机森林的树数量。树越多模型越稳定但训练和推理时间线性增长。100 棵树在几千条样本上通常够用如果样本上万可以加到 200。但不要盲目加到 1000收益递减很明显而且模型文件会变大。test_size一般设 0.2 到 0.3。如果样本量很小比如总共只有几百条可以设 0.3 让测试集更有代表性如果样本上万0.2 就够了。关键是加stratifyy保证正负样本在训练集和测试集里比例一致。# 画 payload 长度分布辅助选择 max_len import matplotlib.pyplot as plt lengths [len(s) for s in malicious normal] plt.hist(lengths, bins50) plt.xlabel(payload length) plt.ylabel(count) plt.title(Payload Length Distribution) plt.axvline(x200, colorr, linestyle--, labelmax_len200) plt.legend() plt.show() # 输出 90 分位数作为 max_len 参考 import numpy as np print(f90% 分位数: {np.percentile(lengths, 90):.0f}) print(f95% 分位数: {np.percentile(lengths, 95):.0f})这段代码帮你用数据说话而不是拍脑袋定max_len。如果 90 分位数是 180那max_len200就能覆盖绝大多数样本如果 90 分位数是 500那就要考虑调大或者对长 payload 做特殊处理。plt.axvline画出参考线直观看到截断位置。4. 避坑与排查这份源码跑不起来时先查这五件事4.1 现象加载 pickle/joblib 文件报版本不兼容 → 原因scikit-learn 版本差异 → 解决重训或降版本这是最常见的问题。test.pickle、jpblib.pkl、joblib.pkl这些文件是在作者的环境里序列化的如果你本地的 scikit-learn 版本和作者不一致加载时就会报AttributeError: module sklearn.ensemble has no attribute ...或者ValueError: node array from the pickle has an incompatible dtype。解决办法有两个一是看README.md里有没有写版本号装一个接近的版本二是直接删掉旧模型文件重新跑core.py训练一遍。我一般选第二种因为重训虽然花几分钟但能保证环境和代码完全匹配后面调试也省心。4.2 现象notebook 里中文注释乱码或读取文件报 UnicodeDecodeError → 原因编码不一致 → 解决统一用 utf-8 errorsignore原始日志和 HTML 文件可能来自不同系统编码格式不统一。Windows 下可能是 GBKLinux 下可能是 UTF-8混在一起就会报UnicodeDecodeError。解决办法是在所有open()调用里加encodingutf-8, errorsignore。如果确认是 GBK 文件就单独用encodinggbk读。notebook 里如果中文注释显示乱码检查文件本身的编码用 VS Code 或 Notepad 转成 UTF-8。4.3 现象模型评估 accuracy 很高但实际检测效果差 → 原因样本不均衡导致模型偏向多数类 → 解决看 recall 和 F1做欠采样或过采样如果正常样本有 5000 条恶意样本只有 200 条模型全预测成正常就能拿到 96% 的 accuracy但恶意请求一条都抓不到。这是监督学习在入侵检测里最典型的翻车场景。解决办法是不要只看 accuracy重点看classification_report里 malicious 类的 recall 和 F1-score。如果 recall 低于 0.8就要做样本均衡欠采样正常样本到和恶意样本同一量级或者用 SMOTE 生成合成恶意样本。这份源码里没有内置均衡逻辑需要自己在core.py里加。4.4 现象reptile.py 跑不动或爬取超时 → 原因目标站点反爬或网络环境变化 → 解决跳过爬虫直接用 src 目录里的现成数据reptile.py是爬虫脚本依赖外部站点的可用性。如果目标站点改了结构、加了反爬或者你的网络环境访问不了这个脚本就跑不通。但好消息是src目录里已经包含了大量现成的ff_*.html、ff_*.txt和access_log_payload*.txt完全可以直接用这些数据做训练跳过爬虫步骤。我一般会先检查src目录的数据量如果够用就不跑reptile.py省得折腾。4.5 现象joblib.dump 保存的模型文件特别大 → 原因随机森林树太多或 max_depth 太大 → 解决限制树数量和深度或改用逻辑回归随机森林的模型大小和树的数量、深度成正比。如果n_estimators500且max_depthNone模型文件可能几百 MB加载慢、传输也不方便。解决办法是把n_estimators降到 100 到 200max_depth限制在 20 到 30。如果对模型大小有严格要求可以改用逻辑回归或朴素贝叶斯模型文件通常只有几 KB 到几十 KB虽然效果可能略差但部署方便很多。5. 从能跑到好用用交叉验证和混淆矩阵把检测效果压榨出来5.1 用交叉验证替代单次 train_test_split结果更可信单次train_test_split的结果受随机种子影响很大换一个random_state可能 F1 差好几个百分点。更稳的做法是做 5 折或 10 折交叉验证看平均 F1 和标准差。如果标准差很大说明模型不稳定需要调参或增加数据。from sklearn.model_selection import cross_val_score from sklearn.ensemble import RandomForestClassifier clf RandomForestClassifier(n_estimators100, max_depth20, random_state42, n_jobs-1) scores cross_val_score(clf, X, y, cv5, scoringf1) print(f5 折 F1: {scores}) print(f平均 F1: {scores.mean():.4f} (/- {scores.std():.4f}))cv5表示 5 折交叉验证scoringf1直接优化 F1 而不是 accuracy。如果平均 F1 在 0.9 以上且标准差小于 0.03说明模型比较稳如果标准差超过 0.05就要检查数据里是不是有噪声样本或者分布不均。5.2 混淆矩阵告诉你模型到底错在哪classification_report给的是汇总指标混淆矩阵能让你看到具体有多少正常请求被误判成恶意、多少恶意请求被漏掉。在入侵检测场景里漏报恶意判正常通常比误报正常判恶意更严重所以要根据业务需求调整分类阈值。from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay import matplotlib.pyplot as plt cm confusion_matrix(y_test, y_pred) disp ConfusionMatrixDisplay(confusion_matrixcm, display_labels[normal, malicious]) disp.plot(cmapBlues) plt.title(Confusion Matrix) plt.show() # 手动计算漏报率和误报率 tn, fp, fn, tp cm.ravel() print(f漏报率恶意判正常: {fn/(fntp):.4f}) print(f误报率正常判恶意: {fp/(fptn):.4f})cm.ravel()按[tn, fp, fn, tp]顺序展开。漏报率是fn/(fntp)误报率是fp/(fptn)。如果漏报率太高可以降低判定为恶意的阈值牺牲一点误报率来换取更低的漏报。如果误报率太高就提高阈值。这个权衡没有标准答案取决于你的系统能承受多少误报。5.3 一个实用技巧把模型预测概率存下来方便后续调阈值默认的clf.predict()直接输出 0 或 1但很多时候我们需要根据业务调整阈值。用clf.predict_proba()拿到恶意类的概率存成 CSV后面想改阈值不用重新训练。import pandas as pd proba clf.predict_proba(X_test)[:, 1] # 恶意类的概率 result pd.DataFrame({ true_label: y_test, malicious_proba: proba, pred_label: (proba 0.5).astype(int) }) result.to_csv(detection_scores.csv, indexFalse) # 试几个阈值看漏报和误报怎么变 for thresh in [0.3, 0.4, 0.5, 0.6, 0.7]: pred (proba thresh).astype(int) tn, fp, fn, tp confusion_matrix(y_test, pred).ravel() print(f阈值 {thresh}: 漏报率{fn/(fntp):.4f}, 误报率{fp/(fptn):.4f})这段代码把预测概率和真实标签一起存成 CSV后面不管是用 Excel 分析还是写脚本调阈值都很方便。for thresh in [...]循环试了五个阈值输出对应的漏报率和误报率帮你找到业务上最能接受的平衡点。我一般会把这个 CSV 留着答辩时直接展示不同阈值下的效果对比比只报一个 accuracy 有说服力得多。从那以后我每次跑完入侵检测模型都会强制走一遍混淆矩阵和阈值扫描不看到漏报率和误报率的具体数字心里就不踏实。希望这份源码和上面的步骤能帮你少走点弯路顺利把毕设跑通。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站