规则过滤
waf规则过滤,默认提供了六种规则,分别是cc规则,api(uri)规则,ip规则,cookie规则,header规则,param(args)规则。
其对应的过滤顺序为 ip > api > cc > header > cookie > param
,如果执行完过滤链后,没有命中规则,说明通过waf。否则命中waf
接下来我们看各种规则的实现流程。这里主要对cc规则和api规则进行说明,其他的规则实现类似
CC规则
cc规则,是对cc攻击次数的拦截,一般用某个特定key来限制,可以理解为一定时间内的次数访问限制。如,规则设置为,1分钟访问100次,超过100次认定为cc,对当前请求的 key
进行限制1分钟不能访问。
CC-Key
tl-ops-manage的cc规则的key是 ip + url 组成,由于key的生成会依赖url,但由于url长度不可控,所以默认截取url的前50个字符。
后续可能会支持到自定义变量key,如host, ip, url等,
对于cc规则具体实现代码如下
# 代码位置 : waf/tl_ops_waf_cc.lua
local tl_ops_waf_core_cc_filter_global_pass = function()
-- 作用域
local cc_scope, _ = cache_cc:get(tl_ops_constant_waf_cc.cache_key.scope);
if not cc_scope then
return true
end
-- 根据作用域进行waf拦截
if cc_scope ~= waf_scope.global then
return true
end
-- 配置列表
local cc_list, _ = cache_cc:get(tl_ops_constant_waf_cc.cache_key.list);
if not cc_list then
return true
end
local cc_list_table = cjson.decode(cc_list);
if not cc_list_table then
return true
end
-- 获取当前url
local request_uri = string.sub(tl_ops_utils_func:get_req_uri(), 1, MAX_URL_LEN);
if not request_uri then
request_uri = ""
end
-- 获取当前ip
local ip = tl_ops_utils_func:get_req_ip();
if not ip then
ip = ""
end
-- cc key
local cc_key = tl_ops_constant_waf_cc.cache_key.prefix .. ip .. request_uri
local cur_host = ngx.var.host
if not cur_host then
return true
end
for _, cc in ipairs(cc_list_table) do
repeat
local host = cc.host
local time = cc.time
local count = cc.count
-- 域名为空跳过规则
if host == nil or host == '' then
break
end
-- 域名不匹配跳过规则
if host ~= "*" and host ~= cur_host then
break
end
-- 首次
local res, _ = shared_waf:get(cc_key)
if not res then
shared_waf:set(cc_key, 1, time)
break
end
-- 没有达到cc次数
if res < count then
shared_waf:incr(cc_key, 1)
break
end
-- 触发cc
return false
until true
end
tlog:dbg("tl_ops_waf_cc done")
return true
end
API规则
对API规则来说,主要思路是规则的匹配,也就是正则字符串匹配,对相应的api进行对比拦截处理。同负载api规则一样,waf也是支持到域名级别的匹配,以便于分流处理不同业务
具体实现如下 :
# 代码位置 : waf/tl_ops_waf_api.lua
local tl_ops_waf_core_api_filter_global_pass = function()
-- 作用域
local api_scope, _ = cache_api:get(tl_ops_constant_waf_api.cache_key.scope);
if not api_scope then
return true
end
-- 根据作用域进行waf拦截
if api_scope ~= waf_scope.global then
return true
end
-- 是否开启拦截
local open, _ = cache_api:get(tl_ops_constant_waf_api.cache_key.open);
if not open then
return true
end
-- 配置列表
local api_list, _ = cache_api:get(tl_ops_constant_waf_api.cache_key.list);
if not api_list then
return true
end
local api_list_table = cjson.decode(api_list);
if not api_list_table then
return true
end
-- 获取当前url
local request_uri = tl_ops_utils_func:get_req_uri();
if not request_uri then
return true
end
local cur_host = ngx.var.host
if not cur_host then
return true
end
...
for _, api in ipairs(api_list_table) do
repeat
local value = api.value
local host = api.host
local white = api.white
-- 此前已处理白名单
if white then
break
end
-- 域名为空跳过规则
if host == nil or host == '' then
break
end
-- 域名不匹配跳过规则
if host ~= "*" and host ~= cur_host then
break
end
-- 未命中拦截规则,进行下一个
local res, _ = find(request_uri , value , 'joi');
if not res then
break
end
-- 命中规则的api
return false
until true
end
return true
end
相较于API规则来说,其他的waf规则实现也是类似。如ip规则,header规则,cookie规则,param规则,都是在请求阶段拿到不同的数据进行规则匹配