config = conf\redis.lua
opts = conf\opts.lua
Init阶段
调用waf.lua 的init函数,从本地配置文件读取规则,具体实现在\resty\waf\readrule.lua init_rules_from_localhost 函数中:
init_rules_from_localhost 函数实现:
1\) 设置waf运行的模式,来自conf\redis.lua 的 default\\_mode 配置, 初始化时 为 SIMULATE 表示只记录 不阻断
2\) 从 rules\default.json中 读取默认规则集合,主要包括access、header\_filter、body\_filter 三个阶段规则
3\) 然后计算每个规则的偏移 \_calculate\_offset , 默认偏移都为1 ,如果需要两个规则配合使用的chain,则偏移会发生变化
4\) 将规则保存到共享内存default 中
注意: init阶段不允许出现网络请求,因此初始化不能从redis读取规则
Access阶段
调用waf:new() 函数进行初始化:
1\) 获得共享内存中的运行模式,若为空 则将运行模式设置为 INACTIVE
2\) config.waf\_status == 'on' 运行模式才生效,否则关闭模式
3\) 若 config.servers 有值,则表示此nginx下,仅有特定域名启用waf功能
4\) 将每个请求域名进行保存,\_servers将会记录所有保存过的域名
调用 waf:exec()函数实现主要功能:
1\) 判断当前阶段是否有效,只接收 access header\_filter、body\_filter
2\) access阶段,请求头包含x-opsec-key,并且值为设置值,则表示是命令请求
2.1\) command:{"action":"reload\_rules"} 调用readrule.get\_waf\_rules\_from\_redis 从redis读取规则
2.2\) command: {"action": "get\_info"} 获得当前运行模式,和所有server列表
2.3\) command:{"action":"set\_mode","mode":"ACTIVE"} 设置模式,取值范围 INACTIVE, ACTIVE ,SIMULATE
2.4\) command:{"action":"delete\_rules"} 删除所有规则,并且设置模式为INACTIVE
2.5\) command:{"action":"list\_rules"} 列举当前所有规则
2.6\) 结束本阶段请求
3) 若运行模式为 INACTIVE 则直接返回
4) 初始化运行环境变量
5) 从resty.waf.collections 读取每个阶段需要的变量
6) 判断是否为多次调用,在body_filter可能会多次调用,通过设置标志位 ctx.short_circuit
7) 根据规则 进行安全检测 _process_rule
7.1\) 根据规则action addheader 添加请求头,规则类型如下:
{"vars":[{"header":"server","value":"website80.com"},{"header":"x-powered-by","value":"website80.com"}], "pattern":"", "operator":"", "actions": {"addheader": "yes"}, "msg":"", "id":2005}
7.2\) 根据规则var.parse配置,获得特定检测项
7.3\) 获得transform旋转后内容
7.4\) 根据规则进行解析匹配
7.5\) 无条件匹配,检测 var.unconditional
7.6\) 规则匹配 取反操作op\_negated
7.7\) 匹配成功后,记录log
7.8\) 执行对应action
Log阶段
write\_log\_events 将记录的变量信息,根据配置写入到目标位置 文件、socket、kafka等