网络流量异常检测是网络安全领域的重要工作,通过识别偏离正常模式的流量数据,可以及时发现DDoS攻击、端口扫描、恶意入侵等安全事件。使用Python实现网络流量异常检测时,特征工程的质量直接决定了后续模型的检测效果,合理构造特征能够让异常流量和正常流量的区分度更高。

网络流量异常检测的基本流程
完整的网络流量异常检测流程主要包含四个环节,特征工程处于数据预处理和模型训练之间,是承上启下的关键步骤:
- 数据采集:通过网络抓包工具或者流量监控系统获取原始的网络数据包,常见的格式有pcap、netflow等
- 数据预处理:对原始流量数据进行清洗,处理缺失值、异常值,将非结构化的数据包解析为结构化的数据
- 特征工程:从预处理后的数据中提取、构造能够有效区分正常和异常流量的特征
- 模型训练与检测:使用提取的特征训练异常检测模型,再用模型对新的流量数据进行异常判断
网络流量特征工程的核心技巧
1. 基础流量特征提取
基础流量特征是最直接从网络数据包中提取的信息,不需要复杂的计算,能够快速反映流量的基本属性。常见的特征包括数据包长度、协议类型、源端口、目的端口、传输层协议等。
以下是使用scapy库解析pcap文件提取基础特征的示例代码:
from scapy.all import rdpcap, IP, TCP, UDP
import pandas as pd
# 读取pcap文件
packets = rdpcap("test.pcap")
# 存储提取的特征
features = []
for pkt in packets:
# 只处理有IP层的包
if IP in pkt:
feature = {
"src_ip": pkt[IP].src,
"dst_ip": pkt[IP].dst,
"pkt_len": len(pkt),
"proto": pkt[IP].proto
}
# 处理TCP协议相关特征
if TCP in pkt:
feature["src_port"] = pkt[TCP].sport
feature["dst_port"] = pkt[TCP].dport
feature["tcp_flags"] = pkt[TCP].flags
# 处理UDP协议相关特征
elif UDP in pkt:
feature["src_port"] = pkt[UDP].sport
feature["dst_port"] = pkt[UDP].dport
feature["tcp_flags"] = None
else:
feature["src_port"] = None
feature["dst_port"] = None
feature["tcp_flags"] = None
features.append(feature)
# 转换为DataFrame
df = pd.DataFrame(features)
print(df.head())
2. 时序特征构造
网络流量具有明显的时间属性,很多异常流量会在短时间内出现突增、突降等时序变化,因此构造时序特征能够有效提升检测效果。常见的时序特征包括固定时间窗口内的流量包数量、流量字节数、端口访问频率等。
以下是构造1秒时间窗口内流量特征的示例代码:
import pandas as pd
# 假设df已经包含时间戳列ts,单位为秒
# 将时间戳转换为时间格式
df["ts"] = pd.to_datetime(df["ts"], unit="s")
# 设置时间索引
df.set_index("ts", inplace=True)
# 构造1秒时间窗口的统计特征
time_window_features = df.resample("1S").agg({
"pkt_len": ["sum", "mean", "count"], # 窗口内包长度总和、平均值、包数量
"src_ip": "nunique", # 窗口内源IP数量
"dst_port": "nunique" # 窗口内目的端口数量
})
# 重置列名
time_window_features.columns = ["total_bytes", "avg_pkt_len", "pkt_count", "unique_src_ip", "unique_dst_port"]
time_window_features = time_window_features.reset_index()
print(time_window_features.head())
3. 统计特征计算
统计特征通过对流量数据的分布、离散程度等属性进行计算得到,能够帮助模型捕捉流量的整体分布规律。常见的统计特征包括流量长度的方差、偏度、峰度,端口分布的熵值等。
以下是计算流量统计特征的示例代码:
import pandas as pd
import numpy as np
from scipy import stats
# 计算单个流的各项统计特征
def calculate_stat_features(flow_df):
if len(flow_df) == 0:
return None
pkt_lens = flow_df["pkt_len"].values
features = {
"pkt_len_var": np.var(pkt_lens), # 包长度方差
"pkt_len_skew": stats.skew(pkt_lens), # 包长度偏度
"pkt_len_kurtosis": stats.kurtosis(pkt_lens), # 包长度峰度
"pkt_len_max_min_diff": np.max(pkt_lens) - np.min(pkt_lens) # 包长度极差
}
return features
# 假设按照源IP和目的IP分组得到单流数据
flow_groups = df.groupby(["src_ip", "dst_ip"])
stat_features = []
for (src_ip, dst_ip), flow_df in flow_groups:
feat = calculate_stat_features(flow_df)
if feat:
feat["src_ip"] = src_ip
feat["dst_ip"] = dst_ip
stat_features.append(feat)
stat_df = pd.DataFrame(stat_features)
print(stat_df.head())
4. 交互特征构造
交互特征是结合多个基础特征计算得到的新特征,能够反映不同特征之间的关联关系。比如源端口和目的端口的比值、包长度和包数量的比值等,这类特征往往能够捕捉到单一特征无法体现的异常模式。
特征工程后的模型应用
完成特征工程后,就可以使用提取的特征训练异常检测模型。常用的无监督异常检测模型包括孤立森林、One-Class SVM、LOF局部离群因子等,这些模型不需要标注的异常数据,适合网络流量中异常样本较少的场景。
以下是使用孤立森林模型进行异常检测的示例代码:
from sklearn.ensemble import IsolationForest
import pandas as pd
# 假设feature_df是已经完成特征工程的特征数据,已经做了缺失值处理和标准化
# 标准化特征
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaled_features = scaler.fit_transform(feature_df)
# 初始化孤立森林模型
model = IsolationForest(n_estimators=100, contamination=0.01, random_state=42)
# 训练模型
model.fit(scaled_features)
# 预测异常,-1表示异常,1表示正常
predictions = model.predict(scaled_features)
feature_df["is_anomaly"] = predictions
# 输出异常流量
anomaly_df = feature_df[feature_df["is_anomaly"] == -1]
print(f"检测到{len(anomaly_df)}条异常流量")
特征工程的注意事项
在进行网络流量特征工程时,需要注意几个问题。首先是要避免特征维度过高,过多的冗余特征会导致模型过拟合,检测效果下降,可以通过特征选择方法筛选有效特征。其次是要保证特征的实时性,在线检测场景下需要控制特征计算的时间开销,避免延迟过高。最后是要定期更新特征集合,网络流量的模式会随时间变化,旧的特征可能无法适配新的流量场景。