WAF开发之自学习模式开发实战
字数 1583 2025-08-18 11:37:20

WAF自学习模式开发实战教学文档

一、自学习模式概述

1.1 传统WAF白名单功能的问题

  • 基于概率统计学的传统方法存在两个主要问题:
    • 学习时间过长,业务频繁变更时模型难以收敛
    • 误报率较高,导致用户下线功能

1.2 自学习模式的目标

  1. 无需或只需少量用户干预
  2. 降低WAF漏报率
  3. 提升检测速度

1.3 jxwaf自学习模式的创新点

  • 不采用概率统计学方法
  • 实现三个维度的分析:
    • 正则自适应匹配
    • 长度分析
    • 词法分析

二、核心实现原理

2.1 基本思路

  • 通过分析用户输入中的特殊字符来区分正常数据和攻击语句
  • 防护关键:识别用户输入中的特殊字符

2.2 正则自适应匹配

2.2.1 学习过程

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

2.2.2 五层匹配规则

  1. 第一层:参数值为数字、字母和_组成
  2. 第二层:参数值为数字、字母和_、"、()、.组成
  3. 第三层:参数值为数字、字母和_组成(含常见特殊字符)
  4. 第四层:参数值不包含<、>、=等危险特殊字符
  5. 第五层:含任意字符

2.2.3 检测过程

local function white_check_rx(value,level)
    local check_value = value
    local check_level = 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 [==[<>=]=]
    
    local result = nil
    if check_level == 1 and ngx.re.find(check_value, level_one,"oij") then
        result = 1
    elseif check_level == 2 and ngx.re.find(check_value, level_two,"oij") then
        result = 2
    elseif check_level == 3 and ngx.re.find(check_value, level_three,"oij") then
        result = 3
    elseif check_level == 4 and ngx.re.find(check_value, level_four,"oij") then
        result = 4
    elseif type(check_level) == string and ngx.re.find(check_value,check_level,"oij") then
        result = 5
    else
    end
    return result
end

2.3 长度分析

2.3.1 相关配置

  • Learn length bypass: true/false(检测到异常只告警不拦截)
  • Learn length bypass length: 数字(默认30,小于该值不处理)
  • Learn length limit: 数字(默认1500,参数值最大长度)
  • Learn length update count: 数字(默认5,长度参数迭代次数)

2.3.2 实现特点

  • 新参数值长度比旧值大时会覆盖旧长度
  • 迭代次数超过限制时,长度值将被设置为Learn length limit

2.4 词法分析

2.4.1 核心处理函数

local function _process_string(arg)
    local result = {}
    local _arg = arg
    local char = nil
    for count=1,#_arg,1 do
        local tmp = string.byte(_arg,count)
        if (tmp >= 0 and tmp <= 31) or tmp == 127 then
            -- control
            if char ~= 'c' then
                table.insert(result,'c')
                char = 'c'
            end
        elseif (tmp >= 48 and tmp <= 57) or (tmp >= 65 and tmp <= 90) or (tmp >= 97 and tmp <= 122) or tmp > 127 then
            -- normal
            if char ~= 'n' then
                table.insert(result,'n')
                char = 'n'
            end
        elseif (tmp >= 32 and tmp <=34) or tmp == 40 or tmp == 41 or tmp == 44 or tmp == 46 or tmp == 64 or tmp == 95 or tmp == 63 then
            -- usual char (space)
            if char ~= 'u' then
                table.insert(result,'u')
                char = 'u'
            end
        elseif (tmp >= 35 and tmp <= 39 ) or tmp == 42 or tmp == 43 or tmp== 45 or tmp == 47 or (tmp >= 58 and tmp <= 62) or (tmp >= 91 and tmp <=96) or (tmp >= 123 and tmp <= 126) then
            -- anomaly char
            if char ~= 'a' then
                table.insert(result,'a')
                char = 'a'
            end
        else
            ngx.log(ngx.ERR,"process string error ",_arg)
        end
    end
    return table.concat(result)
end

2.4.2 字符分类规则

  1. 控制字符(0~31及127):标记为'c'
  2. 数字、字母、中文等:标记为'n'
  3. 空格等常见字符:标记为'u'
  4. 其他特殊字符:标记为'a'

2.4.3 特征合并

  • 相同特征合并为一个,如"aaaaaabbbbb哇哇哇哇"→"n"
  • 特征数超过5个时,检测进入bypass模式

三、全局配置

3.1 主要配置项

  • Force_reject: true/false(默认为false,未被学习到的参数和URL请求是否拒绝)
  • Igonre uri: 正则(Force_reject为true时,匹配该正则的URL请求放行)
  • check_reject: true/false(默认为true,未能通过检测的请求是否拒绝)
  • learn_count: 数字(默认为1000,同一URL请求的学习迭代次数)

四、案例分析(以DVWA登录接口为例)

4.1 学习过程

  • 初始学习数据示例:
    "Login":[1,5,["n"],"false"]
    "user_token":[1,32,["n"],"false"]
    "username":[1,5,["n"],"false"]
    "password":[1,8,["n"],"false"]
    

4.2 学习后数据变化

  1. Login参数:固定值"Login",学习数据不变
  2. user_token:32位十六进制数据,学习数据不变
  3. username参数:
    • 正则自适应匹配值由1→3
    • 长度达到21
    • 词法特征增加"nunun"
  4. password参数:
    • 正则自适应匹配值由1→6(任意字符)
    • 长度维度失效
    • 词法分析维度失效

4.3 攻击检测示例

  1. SQL注入:' and 1=(select @@VERSION)
    • 正则匹配值:6
    • 长度:24
    • 词法特征:"aununununu"
    • 结果:拒绝
  2. 命令执行:ls -al
    • 正则匹配值:3
    • 长度:6
    • 词法特征:"nun"
    • 结果:拒绝
  3. 代码执行:phpinfo()
    • 正则匹配值:2
    • 长度:9
    • 词法特征:"nu"
    • 结果:拒绝

五、总结

5.1 解决的问题

  1. 模型收敛问题:通过增量更新(边检测边学习)
  2. 误报问题:采用"宁放过不错杀"原则

5.2 引入的新问题

  1. 提高了用户介入度
  2. 提高了漏报率

5.3 整体防护策略

  • 黑名单+全局白名单+自学习+机器学习多层防护
  • 性能消耗低(相当于多1-2条规则)
  • 支持管理界面审计功能优化
WAF自学习模式开发实战教学文档 一、自学习模式概述 1.1 传统WAF白名单功能的问题 基于概率统计学的传统方法存在两个主要问题: 学习时间过长,业务频繁变更时模型难以收敛 误报率较高,导致用户下线功能 1.2 自学习模式的目标 无需或只需少量用户干预 降低WAF漏报率 提升检测速度 1.3 jxwaf自学习模式的创新点 不采用概率统计学方法 实现三个维度的分析: 正则自适应匹配 长度分析 词法分析 二、核心实现原理 2.1 基本思路 通过分析用户输入中的特殊字符来区分正常数据和攻击语句 防护关键:识别用户输入中的特殊字符 2.2 正则自适应匹配 2.2.1 学习过程 2.2.2 五层匹配规则 第一层:参数值为数字、字母和_ 组成 第二层:参数值为数字、字母和_ 、"、()、.组成 第三层:参数值为数字、字母和_ 组成(含常见特殊字符) 第四层:参数值不包含 <、>、=等危险特殊字符 第五层:含任意字符 2.2.3 检测过程 2.3 长度分析 2.3.1 相关配置 Learn length bypass : true/false(检测到异常只告警不拦截) Learn length bypass length : 数字(默认30,小于该值不处理) Learn length limit : 数字(默认1500,参数值最大长度) Learn length update count : 数字(默认5,长度参数迭代次数) 2.3.2 实现特点 新参数值长度比旧值大时会覆盖旧长度 迭代次数超过限制时,长度值将被设置为 Learn length limit 2.4 词法分析 2.4.1 核心处理函数 2.4.2 字符分类规则 控制字符(0~31及127):标记为'c' 数字、字母、中文等:标记为'n' 空格等常见字符:标记为'u' 其他特殊字符:标记为'a' 2.4.3 特征合并 相同特征合并为一个,如"aaaaaabbbbb哇哇哇哇"→"n" 特征数超过5个时,检测进入bypass模式 三、全局配置 3.1 主要配置项 Force_reject : true/false(默认为false,未被学习到的参数和URL请求是否拒绝) Igonre uri : 正则(Force_ reject为true时,匹配该正则的URL请求放行) check_reject : true/false(默认为true,未能通过检测的请求是否拒绝) learn_count : 数字(默认为1000,同一URL请求的学习迭代次数) 四、案例分析(以DVWA登录接口为例) 4.1 学习过程 初始学习数据示例: 4.2 学习后数据变化 Login参数:固定值"Login",学习数据不变 user_ token:32位十六进制数据,学习数据不变 username参数: 正则自适应匹配值由1→3 长度达到21 词法特征增加"nunun" password参数: 正则自适应匹配值由1→6(任意字符) 长度维度失效 词法分析维度失效 4.3 攻击检测示例 SQL注入: ' and 1=(select @@VERSION) 正则匹配值:6 长度:24 词法特征:"aununununu" 结果:拒绝 命令执行: ls -al 正则匹配值:3 长度:6 词法特征:"nun" 结果:拒绝 代码执行: phpinfo() 正则匹配值:2 长度:9 词法特征:"nu" 结果:拒绝 五、总结 5.1 解决的问题 模型收敛问题:通过增量更新(边检测边学习) 误报问题:采用"宁放过不错杀"原则 5.2 引入的新问题 提高了用户介入度 提高了漏报率 5.3 整体防护策略 黑名单+全局白名单+自学习+机器学习多层防护 性能消耗低(相当于多1-2条规则) 支持管理界面审计功能优化