9.3 示例:使用支持向量机算法识别XSS

下面以常见的XSS检测来说明下SVM的简单应用。完整演示代码请见本书GitHub上的9-2.py。

1.处理流程

数据处理流程如图9-10所示。

图9-10 数据处理流程

2.数据搜集和数据清洗

由于我们的例子比较简单,把上述两个步骤合并即可,准备数量相等的正常Web访问日志和XSS攻击的Web日志,最简单的方法是参考我以前的文章《基于WAVSEP的靶场搭建指南》,使用WVS等扫描器仅扫描XSS相关漏洞即可获取XSS攻击的Web日志。

3.特征化

实践中数据搜集&数据清洗是最费时间的,特征化是最烧脑的,因为世界万物是非常复杂的,具有很多属性,然而机器学习通常只能理解数字向量,这个从现实世界的物体转变成计算世界的数字的过程就是特征化,也叫向量化。比如要你特征化你前女友,你总不能说漂亮、温柔这些词,需要对最能代表她的特点的方面进行数字化,如图9-11所示。

图9-11 现实生活中将事物向量化的例子

你会发现各个向量之间的数据范围差别很大,一个月消费能力可能就干掉其他特征对结果的影响了,虽然现实生活中这个指标确实影响很大,但是不足以干掉其他全部特征,所以我们还需要对特征进行标准化,常见的方式为:

·标准化;

·均方差缩放;

·去均值。

回到XSS的问题上,我们需要针对Web日志进行特征化,如图9-12所示。

图9-12 Web日志特征举例

特征提取的示例代码如下:


def get_len(url):
    return len(url)
def get_url_count(url):
    if re.search('(http://)|(https://)', url, re.IGNORECASE) :
        return 1
    else:
        return 0
def get_evil_char(url):
    return len(re.findall("[<>,\'\"/]", url, re.IGNORECASE))
def get_evil_word(url):
    return len(re.findall("(alert)|(script=)(%3c)|(%3e)|(%20)|(onerror)|(onload)|(eval)|(src=)|(prompt)",url,re.IGNORECASE))

数据标准化使用如下代码即可:


min_max_scaler = preprocessing.MinMaxScaler()
x_min_max=min_max_scaler.fit_transform(x)

4.数据打标

XSS标记为1,正常访问标记为0。

5.数据拆分

这一步是为了随机把数据区分成训练组和测试组,通常直接使用cross_validation.train_test_split即可,通常40%作为测试样本,60%作为训练样本,这个比例可以根据自己的需要进行调节:


x_train, x_test, y_train, y_test = cross_validation.train_test_split(x,y, test_size=0.4, random_state=0)

6.数据训练

使用Scikit-Learn的SVM模型即可,SVM用于分类的模型称为SVC,我们使用最简单的核函数linear:


clf = svm.SVC(kernel='linear', C=1).fit(x, y)
joblib.dump(clf,"xss-svm-200000-module.m")

7.模型验证

通过加载训练后的模型,针对测试集合进行预测,将预测结果与打标结果进行比对:


clf=joblib.load("xss-svm-200000-module.m")
y_test=[]
y_test=clf.predict(x)
print metrics.accuracy_score(y_test, y)

在测试环节中,我们在一个各有20万个样本的黑白模型上进行训练,在一个各有5万个样本的黑白测试集上进行校验,任何黑白预测错都判断为错误,最后运行结果准确率为80%,对于机器学习而言,仅依靠模型优化,这个比例已经很高了。通过在更大的数据集合上进行训练(比如大型CDN&云WAF集群的日志),进一步增加特征个数以及增加后面环节的自动化或者半自动化的验证,可以进一步提高这个比例,最后我们做到了准确率90%以上。图9-13是特征扩展的举例,大家可以根据实际情况增加个数。

图9-13 Web日志特征

8.异常数据

通过SVM我们识别出了异常数据,经过人工确认,除了变形的XSS以外,还有不少其他攻击行为,由于测试时只打开了XSS的规则签名,所以其他攻击行为没有拦截,也进入了白样本,举例如下:


/.|./.|./.|./.|./.|./.|./.|./.|./.|./.|./.|./windows/win.ini
/index.php?op=viewarticle&articleid=9999/**/union/**/select/**/1331908730,1,1,1,1,1,1,1--&blogid=1
/index.php?go=detail&id=-99999/**/union/**/select/**/0,1,concat(1331919200,0x3a,512612977),3,4,5,6,7,8,9,10,11,12,13,14,15,16
/examples/jsp/num/.|./.|./.|./.|./.|./.|./.|./.|./.|./.|./.|./.|./windows/win.ini
/cgi-bin/modules/tinymce/content_css.php?templateid=-1/**/union/**/select/**/1331923205,1,131076807--
/manager/ajax.php?rs=__exp__getfeedcontent&rsargs[]=-99 union select 1161517009,2,1674610116,4,5,6,7,8,9,0,1,2,3 --

从广义上讲,XSS和SQL注入都是属于代码注入导致的漏洞。我们推测由于训练样本中混入了SQL注入的样本,所以导致训练结果中也出现了了SQL注入。