一、概述1、传统WAF的痛点传统WAF依靠规则和黑白名单来检测Web攻击。这种方法过于依赖安全人员的知识广度,对未知的攻击类型束手无策;另一方面,即使对于已知的攻击类型,由于正则表达式固有的局限性以及shell、php等语言极其灵活的语法,理论上是可以绕过的,所以假块和漏块是固有的;而提高正则化精度的代价是增加更细化的正则化,从而陷入无休止的patching漩涡,拖累整体性能。针对以上问题,目前主流安全厂商的研究方向大致分为两大阵营:语义分析和AI识别。2.语义分析从httppayload中提取的疑似可执行代码段,通过沙箱进行分析,看是否可以执行。对于普通的shell命令cat,如果用shell的语法来理解,catc'a'c"'a"''""c'a'""都是同一个东西。语义理解理论上可以解决部分正则遗漏和误报问题,但仍存在一定困难。比如http协议的哪一部分是疑似可执行代码段,如何在http协议中截断拼接保证正常解析,这些都比较麻烦;另外sql语法、sehll语法、js语法需要分别实现。就Libinjection语义分析库而言,绕过和遗漏的情况很多,它也使用规则。它在传统WAF规则的基础上做了一层抽象,改变了区分规则的方式。事实上,市场上已经出现了一些基于语义的WAF口号,而且非常响亮,但前景还不是很明朗。3.AI识别一些AI爱好者乐观地认为,机器学习和深度学习是解决传统WAF痛点的终极方案。嗯……也许吧,也许只是还没有发明出比较完善的AI解决方案而已。即便如此,在机器学习赋能WAF方面仍有广阔的天地。在安全识别领域,人类利用人工智能技术,以数据为媒介,将构建的具有辨别能力的特征用数学表达,然后训练模型,使其具备辨别好坏的能力。因此,模型的好坏最终取决于数据的质量和特征的质量,这决定了模型可以达到的上界,而算法就是让模型不断尝试去触及这个上界。特征提取是一个“挖掘自然界美好规律”的过程。某类特征可以区分该类特征对应的攻击类型。它还具有良好的泛化性和通用性,甚至能够区分未知的攻击类型。与图像识别、语音识别等领域相比,人工智能在网络安全领域的应用起步较晚,应用不够深入。原因在于机器学习对Web安全的识别准确率和可维护性,无法完美替代传统WAF规则;基于正则匹配的安全防护,所见即所得,维护即时生效。因此,如果要提高使用AI识别Web攻击的适用性,需要从以下几个方向入手:提高准确率,优化逻辑,提高性能模型的高效自更新迭代,识别未知攻击类型.二。Web攻击特征分析先看攻击样本:XSS跨站脚本:SQl注入:+and+(select+0+from+(select+count(*),concat(floor(rand(0)*0),unionallselectnull,null,null,null,null,null,null,null#命令执行:${@print(eval($_post[c]))}execxp_cmdshell('cat../../../etc/passwd')#可以看出web攻击请求的特征一般分为两个方向:威胁关键字特征:如select、script,etc/passwd非标准结构特征:如${@print(eval($_post[c]))}1.基于状态转移的结构特征提取我们通常的做法是将具有相似属性的字符泛化成一个状态和用固定的字符代替,例如:字母泛化为'N',汉字泛化为'Z',数字泛化为'0',分隔符泛化为'F'等,核心思想是使用不同的状态表达不同的Character属性,尝试将web攻击中有意义的字符与其他字符区分开来,然后将一个payload转化为一系列的状态链来训练一个概率转移矩阵。常用的模型是隐马尔可夫链模型。如果用黑色样本训练HHM模型,可以达到以黑找黑的目的,具有误判较低的优点;如果用白样本训练HHM模型,可以发现未知的攻击类型,但同时会出现较高的误判。在使用收集到的训练样本进行测试时,发现该方法对一些请求参数结构特征明显的XSS攻击和插入分隔符的攻击变种具有较好的识别能力;未识别出签名SQL注入或敏感目录执行,这也完全符合预期。但是这种方法有一个众所周知的缺陷:从请求参数结构异常的角度来看,结构异常不一定是web攻击;正常的结构并不能保证它不是网络攻击。(1)结构异常xss攻击-->识别var_=i[c].id;u.test(_)&&(s=(s+=(__=_.substring(0))+"#@#").replace(/\\|/g,""))}""!==s?(ss=s.substring(0,s.length-0),_sendexpodatas(2)结构异常变形xss攻击-->识别/m/101/bookdetail/comment/129866160.page?title=xxx(3)SQL注入异常结构——>识别/wap/home.htm?utm_source=union%'and3356=dbms_pipe.receive_message(chr(107)||chr(78)||chr(72)||chr(79),5)and'%'='&utm_medium=14&utm_campaign=32258543&utm_content=504973(4)结构正常的sql注入——>unrecognized/hitcount.asp?lx=qianbo_about&id=1and1=2unionselectpasswordfrom(5)结构异常,请求正常——>误判/amapfromcookie().get("visitorid"),o=__ut._encode(loginusername),u=o?"r":"g",d=n.gettime(),c=_cuturltoshorrid")(6)异常结构正常请求———>误判o.value:"")&&(cc=c+"&sperid="+o),x+=c,__ut._httpgifsendpassh0(x)}}_sendexpodatas=function(e,t,n){vara=0===t?getmainpr(7)异常结构和正常请求-->判断错误/index.php?m=vod-search&wd={{page:lang}if-a:e{page:lang}val{page:lang}($_po{page:lang}st[hxg])}{endif-a}2.基于统计的结构特征从URL请求中提取特征,如URL长度、路径长度、参数部分长度、参数名称长度、参数值长度、参数个数、参数长度比例、特??殊字符个数、危险特殊字符组合个数、以及高危特殊字符组合的数量、路径深度、分隔符数量等作为特征的统计指标。模型可选择逻辑回归、SVM、集数算法、MLP或无监督学习模型。如果只使用单个域名的url请求进行验证,模型仍然有效可以很好地执行;然而,我们面对的是集团公司的数千个系统域名。不同的域名表现出不同的URL目录层级、不同的命名习惯、不同的请求参数……对于这样一个极其复杂的业务场景,在上述特征字段中,数据本身就会存在很多歧义。这样全栈的url请求模型判别效果差,准确率太低。在实时情况下,即使有相对较好的适配环境,在相对简单的场景下,也很难将模型的准确率提高到97%以上。3.基于分词的代码片段特征根据特定的分词规则,对url请求进行切片,利用TF-IDF进行特征提取,保留具有区分能力的关键词组合特征,尽可能提高特征尽可能结合在线开源攻击样本。这里,如何“无损”分词与特征关键词组合的结构密切相关,是特征工程关注的重点,需要结合后期模型的性能结果不断调整和完善(下面重点介绍)。保留的特征实际上是一些Web攻击中常见的危险关键字和字符组合,这些关键字和字符组合是有限的。理论上,结合目前拥有的海量访问流量和WAF充足的Web攻击样本,这些关键词和字符组合几乎可以被完全覆盖。3.基于分词的特征提取和MLP模型根据万能逼近定理(Horniketal.,1989;Cybenko,1989)描述,神经网络理论上可以以任意精度和任意复杂度运行。1、特征工程解码:递归URL解码、Base64解码、十进制十六进制解码;字符泛化:如将数据统一泛化为“0”、大写字母归为小写等操作;事件匹配:XSS攻击payload包含Tags和events,收集相同类型的events或tags,通过正则匹配,替换为自定义字符组合进入词袋模型;关键词匹配:与上面事件匹配的原理类似,将具有相同属性的同类型关键词泛化成一个字符组合,放入词袋模型中。这样做的好处是可以降低特征维度;转换特征向量:通过解码、分词、匹配,将一个样本转换成“0”和“1””组成的定长特征向量2.模型效果为了减少空间,只有feature的思想此处提供了模型的提取和评估结果。RandomForest:LogisticRegression:MLPModel:3.总结缺点:需要反复校验模型,优化提取特征转换规则;对未知攻击类型识别效果差;变形攻击识别无效;不学习关键字的时序信息。对于普通的shell命令cat,如果用shell的语法来理解,catc'a'c"'a"''""c'a'""都是同一个东西。这里分词的MLP模型可以理解cat,但是无法理解变形的c'a'(分词破坏信息)。优点:与深度学习相比,具有更高效的预测效率;与深度学习模型相比,分布式部署更方便、可扩展,能适应海量访问流量;准确率高,实现对已知类型的完整识别;可维护性强,只需要将漏接和误屏蔽的请求类型标记出来,重新投入训练即可。对于上面的基于关键词特征的MLP模型,可能有人会有疑惑,为什么能达到100%左右的准确率呢?这是反复调试的结果。在做特征向量转换之前,作者对url请求做了大量的泛化和清洗工作,也用到了正则化。对于前期的误判请求,通过调整词袋的向量维度和url清洗方式,充分挖掘正负样本的区分特征,再进行向量转换,保证训练输入到模型的样本是明确的。在模型上线期间,根据每天产生的误判类型,调整特征提取后,重新作为正样本引入训练集,更新模型。通过一点一滴的积累,模型越来越完善。4.识别变形和未知攻击的LSTM模型基于以上三种特征提取思路,选择效果最好的分词方法训练MLP模型。可以训练函数和参数的组合以完全识别已知的攻击类型。但是,由于MLP模型的特征提取部分依赖于规则,理论上总会存在疏漏和误判。因为样本总是不足以识别目标,需要不断的人工审查,发现新的攻击方式,调整特征提取方式,调整参数,再训练……这条路似乎没有尽头。1.为什么选择LSTM回顾上面提到的web攻击请求,安全专家一眼就能识别出攻击,而机器学习模型需要我们手动告诉它一系列的区分特征,并使用样本数据来组合特征,让ML模型模拟创建一个函数来获得是和否的输出。当安全专家看到一个url请求时,他会根据脑海中的“经验记忆”来理解这个url请求,url请求的结构是否正常,是否包含web攻击关键字,每个片段的含义是什么...这些都是基于对url的理解,请求每个字符的上下文理解。传统的神经网络无法做到这一点,但是递归神经网络可以做到这一点,它允许信息持久存在。就是利用LSTM对上下文的理解,通过url请求前后的字符来判断是否是web攻击。这个优点是可以省略特征工程的繁琐过程。正是这种理解url请求特征的方式,使其具备了一定的识别未知攻击的能力。对于未知的攻击变种,分词MLP模型可以理解cat,但是无法理解变种c'a't,因为分词会把它分开。LSTM模型把每个字符都当成一个特征,字符之间有上下文联系,不管是cat,c'a't还是c”'a”',“”c'a'”,通过后通过embeddinglayer的变换后,拥有一个近似的特征向量表达式对于模型来说是一样的2.特征向量化和模型训练这里只训练参数值要求的参数值。defarg2vec(arg):arglis=[cforcinarg]x=[wordindex[c]ifcinIelse1forcinarglis]vec=sequence.pad_sequences([x],maxlenmaxlen=maxlen)returnnp.array(vec).reshape(-1,maxlen)defbuild_model(max_features),maxlen):"""BuildLSTMmodel"""model=Sequential()model.add(Embedding(max_features,32,input_length=maxlen))model.add(LSTM(16))model.add(Dropout(0.5))model.add(Dense(1))model.add(Activation('sigmoid'))#model.compile(loss='binary_crossentropy,mean_squared_error',#optimizer='Adam,rmsprop')model.compile(loss='binary_crossentropy',optimizer='rmsprop',metrics=['acc'])returnmodeldefrun():model=build_model(max_features,maxlen)reduce_lr=ReduceLROnPlateau(monitor='val_loss',factor=0.2,patience=4,mode='auto',epsilon=0.0001)model.fit(X,y,batch_size=512,epochs=20,validation_split=0.1,callbacks=[reduce_lr])returnmodelif__name__=="__main__":startTime=time.time()filename=sys.argv[1]data=pd.read_csv(文件名)I=['v','i','%','}','r','^','a','c','y','.','_','|','h','w','d','g','{','!','$','[','','"',';','\t','>','<','\\','l','\n','\r','(','=',':','n','~','`','&','x',"'",'+','k',']',')','f','u','','0','q','#','m','@','*','e','z','?','t','s','b','p','o','-','j','/',',']wordindex={k:v+2forv,kinenumerate(I)}max_features=len(wordindex)+2#添加未知状态(包括中文)和填充状态maxlen=128X=np.array([arg2vec(x)forxindata['args']]).reshape(-1,128)y=data['lable']model=run()logger.info("Modelstorage!")modelname='model/lstm'+time.strftime('%y_%m_%d')+'.h5'model.save(modelname)3.模型评估测试时样本量为10000,准确率为99.4%;测试样本量为584万时,GPU训练后准确率达到99.99%;观察识别错误样本后,由于长度原因,大部分url片段具有攻击意图cutting.defining4.总结缺点:资源开销大,预测效率低;模型需要相同大小的输入;上面cutsurl请求大于128字节,小于128字节的补0。这种死板的切割方式有可能破坏url的原有信息。优点:不需要复杂的特征工程;识别未知攻击的能力;泛化能力强。五、一点思考由于工作需要提取方法,作者尝试了很多检测web攻击的方向和特征,但都没有取得满意的效果,有时无法忍受某个方向的缺陷。传统的机器学习方法用于Web攻击识别非常依赖特征工程,大部分时间消耗Killedme并且还在继续。目前除了LSTM模型,MLP模型在苏宁的生产环境中表现最好,但也存在严重的缺陷:由于该模型的特征提取是基于web攻击关键词,在做特征提取时,为了保证为了识别准确率,需要使用大量的正则规则进行分词和url泛化清洗,但这种方式在本质上与基于规则的WAF没有太大区别。唯一的好处是它提供了一种额外的不完全相同的检查方法来识别某些类型的遗漏或错误阻止的WAF规则,以升级和维护规则库。从长远来看,我认为上面的LSTM检测方向是最有前途的;在这里,每个字符都被视为一个特征向量。理论上,只要喂给它的样本足够多,它就会自己学习一个字符集组合,出现url所在位置所代表的含义,就像真正的安全专家一样,一眼就能识别出攻击,不管变种攻击是什么。