基于访问日志的异常请求检测
字数 2054 2025-08-25 22:58:20
基于访问日志的异常请求检测技术详解
1. 技术背景与核心思想
1.1 问题背景
- 传统安全检测方法(如规则匹配)存在局限性:无法检测未知攻击模式(0day)和变种payload
- 现有基于HMM的方法需要对每个URL建立单独模型,不适用于具有大量URL的网站
- 需要一种通用的、能自动适应不同业务模型的异常检测方法
1.2 核心思想
- 无监督学习:无需预先标记的训练数据
- 聚类算法:利用"正常请求相似,异常请求各异"的特性
- 密度聚类:通过DBSCAN算法将正常请求聚为一类,异常请求作为噪声点凸显
2. 数据处理流程
2.1 数据来源与预处理
- 数据来源:Web服务器访问日志(示例中使用480万条、800MB的博客访问日志)
- 关注字段:主要关注URL路径和参数,忽略IP、请求方法和状态码
- 数据清洗步骤:
- 提取日志中的URL部分(路径和参数)
- 过滤静态资源请求(如.css, .js, .jpg等)
- 处理特殊请求(如首页"/")
2.2 数据泛化规则
- 中文字符:统一替换为"cn"
- 例:"用户=张三" → "用户=cn"
- 数字:统一替换为"5"
- 例:"id=123" → "id=5"
- 特殊字符:统一替换为"_"
- 例:"cmd=ls -l" → "cmd=ls_l"
泛化后示例:
原始URL:/search?q=测试123&page=1
泛化后:/search?q=cn5&page=5
3. 特征工程
3.1 词袋模型构建
- 使用TF-IDF(词频-逆文档频率)将文本转换为数值向量
- 相比简单的词典映射(如nltk),TF-IDF能更好反映词语的重要性
- 特征向量包含:
- URL路径分词结果
- 参数名和泛化后的参数值
3.2 特征选择考量
- 排除请求方法和状态码:这些特征不会改变请求本身的异常性质
- 专注于URL结构和参数模式:更能反映请求的本质特征
4. 聚类算法实现
4.1 算法选择:DBSCAN
-
相比K-means的优势:
- 不需要预先指定簇数量
- 能发现任意形状的簇
- 自动将噪声点识别为异常
-
关键参数:
- eps:邻域半径
- minPts:形成簇所需的最小点数
4.2 参数自动优化
- 使用K-平均最近邻算法自动确定最佳参数
- 实现步骤:
- 计算不同K值下的平均最近邻距离
- 找到距离变化的"拐点"作为最佳eps
- 根据数据分布确定minPts
示例参数计算:
当K=331时,eps=0.47,minPts≈5
4.3 聚类结果解读
- 标签>0:正常请求形成的簇
- 例:标签1对应feed请求,标签2对应文章查阅
- 标签-1:噪声点(潜在异常请求)
5. 异常检测结果分析
5.1 成功检测的异常类型
- 目录爆破:
- 特征:请求不存在的路径(如/wp-admin/, /backup/)
- 扫描器行为:
- 特征:已知扫描工具特征(如Nikto扫描器)
- 漏洞利用尝试:
- 特征:包含可疑参数(如sql注入、后门查找)
5.2 存在的误报问题
- 随机化参数:
- 如token、session ID等服务器生成的随机值
- 解决方案:建立白名单过滤已知无害的随机参数
- 低频正常请求:
- 如管理员后台访问(因访问量少被误判为异常)
- 解决方案:结合业务逻辑调整密度阈值
6. 可视化分析
6.1 降维技术:t-SNE
- 将高维特征空间降至2D/3D便于观察
- 可视化结果:
- 正常请求形成紧密的簇
- 异常请求(-1)分散在边缘区域
7. 技术局限性与改进方向
7.1 主要局限性
- 无法实时检测:聚类算法适合离线分析
- 参数随机化问题:需要额外白名单机制
- 低频正常请求误报:需结合业务知识调整
7.2 改进建议
-
多维度特征:
- 加入请求长度、参数数量、访问频率等特征
- 示例检测逻辑:
- 99%请求带2个参数,异常请求带>2个参数
- 正常并发<20,异常>100
- 正常状态码有限(200/302/301),异常多样(403/400/500)
-
词向量替代:
- 尝试Word2Vec代替TF-IDF,可能获得更好的语义表示
-
混合方法:
- 结合聚类和有监督分类
- 先聚类,再人工标记簇属性(爬虫/正常/攻击)
-
参数优化:
- 对不同业务区域设置不同密度阈值
- 对关键功能区域使用更严格的检测
8. 实现代码关键点(伪代码)
# 数据泛化
def generalize_url(url):
url = re.sub(r'[\u4e00-\u9fa5]', 'cn', url) # 中文替换
url = re.sub(r'\d+', '5', url) # 数字替换
url = re.sub(r'[^\w]', '_', url) # 特殊字符替换
return url
# 自动参数优化
def find_optimal_eps(data):
knn = NearestNeighbors(n_neighbors=331)
knn.fit(data)
distances, _ = knn.kneighbors(data)
distances = np.sort(distances[:, -1])
eps = distances[int(len(distances)*0.95)] # 取95%分位数
return eps
# 主流程
logs = load_logs() # 加载日志
cleaned_urls = [clean_url(log) for log in logs]
generalized = [generalize_url(url) for url in cleaned_urls]
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(generalized)
optimal_eps = find_optimal_eps(X.toarray())
dbscan = DBSCAN(eps=optimal_eps, min_samples=5)
labels = dbscan.fit_predict(X.toarray())
anomalies = [log for log, label in zip(logs, labels) if label == -1]
9. 实际应用建议
-
部署方式:
- 每日定时运行分析前24小时日志
- 对检测出的异常人工审核后加入规则库
-
性能优化:
- 对大型网站,按功能模块分区分析
- 使用Spark等分布式计算框架处理海量日志
-
结果处理:
- 对确认的恶意IP加入自动封锁列表
- 对可疑参数模式生成新的WAF规则
-
持续改进:
- 定期评估误报/漏报率
- 根据业务变化调整泛化规则和聚类参数
10. 总结
基于访问日志的无监督异常检测提供了一种通用性强、适应性好的安全检测方法,特别适合缺乏先验知识的场景。虽然存在误报等问题,但通过结合业务知识、优化特征工程和算法参数,可以构建出实用的异常检测系统。这种方法与传统规则引擎形成互补,能有效发现未知威胁和变种攻击。