WAF开发之自学习模式开发实战
一、前言
灵感来自于一次群里的讨论,因为现在市面上关于自学习功能的公开资料比较少,加之没有碰过相应的设备,只能自己瞎想来构思功能实现,码完功能后发现效果还不错,特此分享。
首先来看白名单功能的描述,各大厂商对白名单功能的定义有些微差别,但大体上是一致的,总结起来就是利用各种技术实现如下目标:
1、无需用户干预,或是只需用户少量操作。
2、降低waf漏报率。
3、提升检测速度(下篇讲)
从目前公开的资料来看,各大厂商主要还是基于概率统计学为核心来实现上述功能,通过对网站的流量进行安全分析与收敛来实现网站的规则自适应配置或防护模型的生成。
然而根据群里讨论的反馈,基于概率统计学来生成模型普遍存在两个问题,一个是学习时间太长,或者说,在业务频繁变更的场景下,模型生成成本较高,. 例如上线新业务或者业务变更的时候,进行自学习,结果还没学习结束,又有新功能上线,导致算法模型一直无法收敛。还有就是每次业务变更都需重写学习生成模型,导致业务一当变动就得重新训练。第二个则是误报率较高,一当线上业务被误拦截,用户即下线该功能,进而使功能成为摆设,这个问题我认为得分为两个方面来看,一个是很多用户并非专业的安全人员,导致无法对功能的一些参数为针对网站的情况进行定制配置,另外一个我认为是概率统计学在一些业务场景下存在的缺陷。例如用户评论场景,在学习过程中,用户一般输入都不会超过100字符,那么模型就会认为该参数在100字符以内是合理,当用户输入超过100字符,比如500字符时,就可能触发模型进而被拦截。概率统计学对于输入的数值范围,或者字符的识别都可能存在一样问题,虽然理论上只要数据量足够,学习的时间足够长,是能优化这块的问题。但是现实跟理论的差距还是有距离的···
总结一下就是
1、不敢用 //担心误报阻断业务
2、不好用 //学习成本较高
以上分析为瞎扯,理解有误欢迎讨论。
针对概率统计学存在的情况,所以jxwaf的自学习模式不打算用概率统计学来做,就像空肥皂盒和电风扇故事里的那样,这次要实现的就是那个小风扇,后面在慢慢升级为机器手臂。
二、功能实现
首先来谈谈功能防护的核心逻辑,这涉及到一个问题,什么样的输入是攻击?也就是如何区分用户输入的是正常数据,还是攻击语句。根据经验,像sql注入,XSS,远程执行等,都是将用户输入的数据,当成程序的执行逻辑去处理,进而导致攻击发生。所以如果我们站在这个方面去去思考,就很清晰了,以lua为例,是如何区分数据和执行逻辑的呢?这里有个绕过关键是就是特殊字符,你不可能输入”asdasdasdas1312312″然后让程序去理解执行,必须输入类似”local a=b”的字符串,这样解样器通过空格和=符号,语义分析后才知道你要干什么,所以防护的关键就是将用户输入的特殊字符给拎出来进而进行识别分析。
目前jxwaf的自学习模式已经实现了三个维度的分析,分别如下:
正则自适应匹配
长度分析
词法分析
jxwaf的自学习模式分为学习过程和检测过程,先说第一个维度正则自适应匹配,核心代码如下:
学习过程的正则自适应匹配函数:
local function white_learn_rx(value)
local learn_value = value
local level
local level_one = _white_config.level_one or [=[\W]=]
local level_two = _white_config.level_two or [==[[^\w ,"().]]==]
local level_three = _white_config.level_three or [==[[^\w ,"().@-_/:]]==]
local level_four = _white_config.level_four or [==[['\*%#~?;]]==]
if (not ngx.re.find(learn_value, level_one,"oij")) then
level = 1
elseif (not ngx.re.find(learn_value, level_two,"oij")) then
level = 2
elseif (not ngx.re.find(learn_value, level_three,"oij")) then
level = 3
elseif (not ngx.re.find(learn_value, level_four,"oij")) then
level = 4
else
level = 6
end
return level
end
在该维度主要是对web请求的参数值进行筛选,进而自动匹配生成适合该参数值的白名单正则表达式,一共分为五层:
第一层,参数值为数字字母和_组成
第二层,参数值为数字字母和_,“().组成 //含常用字符
第三层,参数值为数字字母和_,“().@-/组成 //含常见特殊字符
第四层,参数值不包含‘*%#~?; // 不含危险特殊字符
第五层,你赢了 //含任意字符
当用户的web请求过来的时候,正则自适应匹配函数会自行进行识别,进而返回相应函数的匹配值,当相同url的请求再次接收时,又再次进行一次匹配,如果匹配的数值高于之前的匹配结果,那么对应参数的匹配值将被重置。举个例子,如第一次输入数据为a=”AAABBB2123123″,那么参数a的匹配值为1,如果后续输入的数据为”AAVBBJKKKAD@”,那么匹配到的值为3,针对该参数a的匹配将被重置为3,即在web请求学习的过程中,对数据的检测只会越来越宽松,而不会越收越紧,这样的好处是可以显著的降低误报的情况,即宁可放过不错杀,而漏报的情况,则是通过用户人工审核来处理。例如输入的数据被识别为6,即可以包含任意字符的场景,那么可以通过用户人工审核进行调整,如果人工审核分析发现该参数值为固定值,比如用户ID类的数据,那么可以将6强行修改为1,并设置为不可修改即可。以目前线上业务的复杂情况,指望靠一种技术完美解决安全问题是不可能的,所以引入用户人工审核是有必要的,当然就算不审核,因为宁可放过不错杀的原则,至少能保证业务不受影响,代价则是漏报率会高些,但是配合后续两个维度,以及黑名单规则的防护及其他系统的防护,整体风险是可以接受的。
检测过程的正则自适应匹配函数
local function white_check_rx(value,level)
一、前言
灵感来自于一次群里的讨论,因为现在市面上关于自学习功能的公开资料比较少,加之没有碰过相应的设备,只能自己瞎想来构思功能实现,码完功能后发现效果还不错,特此分享。
首先来看白名单功能的描述,各大厂商对白名单功能的定义有些微差别,但大体上是一致的,总结起来就是利用各种技术实现如下目标:
1、无需用户干预,或是只需用户少量操作。
2、降低waf漏报率。
3、提升检测速度(下篇讲)
从目前公开的资料来看,各大厂商主要还是基于概率统计学为核心来实现上述功能,通过对网站的流量进行安全分析与收敛来实现网站的规则自适应配置或防护模型的生成。
然而根据群里讨论的反馈,基于概率统计学来生成模型普遍存在两个问题,一个是学习时间太长,或者说,在业务频繁变更的场景下,模型生成成本较高,. 例如上线新业务或者业务变更的时候,进行自学习,结果还没学习结束,又有新功能上线,导致算法模型一直无法收敛。还有就是每次业务变更都需重写学习生成模型,导致业务一当变动就得重新训练。第二个则是误报率较高,一当线上业务被误拦截,用户即下线该功能,进而使功能成为摆设,这个问题我认为得分为两个方面来看,一个是很多用户并非专业的安全人员,导致无法对功能的一些参数为针对网站的情况进行定制配置,另外一个我认为是概率统计学在一些业务场景下存在的缺陷。例如用户评论场景,在学习过程中,用户一般输入都不会超过100字符,那么模型就会认为该参数在100字符以内是合理,当用户输入超过100字符,比如500字符时,就可能触发模型进而被拦截。概率统计学对于输入的数值范围,或者字符的识别都可能存在一样问题,虽然理论上只要数据量足够,学习的时间足够长,是能优化这块的问题。但是现实跟理论的差距还是有距离的···
www.wnhack.com
总结一下就是
1、不敢用 //担心误报阻断业务
2、不好用 //学习成本较高
以上分析为瞎扯,理解有误欢迎讨论。
针对概率统计学存在的情况,所以jxwaf的自学习模式不打算用概率统计学来做,就像空肥皂盒和电风扇故事里的那样,这次要实现的就是那个小风扇,后面在慢慢升级为机器手臂。
二、功能实现
首先来谈谈功能防护的核心逻辑,这涉及到一个问题,什么样的输入是攻击?也就是如何区分用户输入的是正常数据,还是攻击语句。根据经验,像sql注入,XSS,远程执行等,都是将用户输入的数据,当成程序的执行逻辑去处理,进而导致攻击发生。所以如果我们站在这个方面去去思考,就很清晰了,以lua为例,是如何区分数据和执行逻辑的呢?这里有个绕过关键是就是特殊字符,你不可能输入”asdasdasdas1312312″然后让程序去理解执行,必须输入类似”local a=b”的字符串,这样解样器通过空格和=符号,语义分析后才知道你要干什么,所以防护的关键就是将用户输入的特殊字符给拎出来进而进行识别分析。 本文来自无奈人生安全网
目前jxwaf的自学习模式已经实现了三个维度的分析,分别如下:
正则自适应匹配
长度分析
词法分析
jxwaf的自学习模式分为学习过程和检测过程,先说第一个维度正则自适应匹配,核心代码如下:
学习过程的正则自适应匹配函数:
local function white_learn_rx(value)
local learn_value = value
local level
local level_one = _white_config.level_one or [=[\W]=]
local level_two = _white_config.level_two or [==[[^\w ,"().]]==]
local level_three = _white_config.level_three or [==[[^\w ,"().@-_/:]]==]
local level_four = _white_config.level_four or [==[['\*%#~?;]]==]
if (not ngx.re.find(learn_value, level_one,"oij")) then
level = 1
elseif (not ngx.re.find(learn_value, level_two,"oij")) then
level = 2
elseif (not ngx.re.find(learn_value, level_three,"oij")) then
level = 3
elseif (not ngx.re.find(learn_value, level_four,"oij")) then
level = 4
else
level = 6
end
return level 本文来自无奈人生安全网
end
在该维度主要是对web请求的参数值进行筛选,进而自动匹配生成适合该参数值的白名单正则表达式,一共分为五层:
第一层,参数值为数字字母和_组成
第二层,参数值为数字字母和_,“().组成 //含常用字符
第三层,参数值为数字字母和_,“().@-/组成 //含常见特殊字符
第四层,参数值不包含‘*%#~?; // 不含危险特殊字符
第五层,你赢了 //含任意字符
当用户的web请求过来的时候,正则自适应匹配函数会自行进行识别,进而返回相应函数的匹配值,当相同url的请求再次接收时,又再次进行一次匹配,如果匹配的数值高于之前的匹配结果,那么对应参数的匹配值将被重置。举个例子,如第一次输入数据为a=”AAABBB2123123″,那么参数a的匹配值为1,如果后续输入的数据为”AAVBBJKKKAD@”,那么匹配到的值为3,针对该参数a的匹配将被重置为3,即在web请求学习的过程中,对数据的检测只会越来越宽松,而不会越收越紧,这样的好处是可以显著的降低误报的情况,即宁可放过不错杀,而漏报的情况,则是通过用户人工审核来处理。例如输入的数据被识别为6,即可以包含任意字符的场景,那么可以通过用户人工审核进行调整,如果人工审核分析发现该参数值为固定值,比如用户ID类的数据,那么可以将6强行修改为1,并设置为不可修改即可。以目前线上业务的复杂情况,指望靠一种技术完美解决安全问题是不可能的,所以引入用户人工审核是有必要的,当然就算不审核,因为宁可放过不错杀的原则,至少能保证业务不受影响,代价则是漏报率会高些,但是配合后续两个维度,以及黑名单规则的防护及其他系统的防护,整体风险是可以接受的。 copyright 无奈人生
检测过程的正则自适应匹配函数
local function white_check_rx(value,level)