本文档说明
这里的策略处理以读取MainRule策略为例。
以naxsi_core.rules的首条策略做示例:
MainRule "rx:select|union|update|delete|insert|table|from|ascii|hex|unhex|drop|load_file|substr|group_concat|dumpfile" "msg:sql keywords" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1000;
MainRule配置文件处理过程
处理入口
/* command handled by the module */
static ngx_command_t ngx_http_naxsi_commands[] = {
/* BasicRule (in main) */
{ ngx_string(TOP_MAIN_BASIC_RULE_T),
NGX_HTTP_MAIN_CONF | NGX_CONF_1MORE,
ngx_http_naxsi_read_main_conf, // 当读到以TOP_MAIN_BASIC_RULE_T,即MainRule开头配置时,就会调用该函数去解析
NGX_HTTP_MAIN_CONF_OFFSET,
0,
NULL },
ngx_http_naxsi_read_main_conf函数
如何读入配置策略信息
value = cf->args->elts; // nginx已读取的策略内容
/* parse the line, fill rule struct */
NX_LOG_DEBUG(_debug_main_conf, NGX_LOG_EMERG, cf, 0, "XX-TOP READ CONF %s", value[0].data);
// 无 MainRule 和 basic_rule 任何策略,退出
if (ngx_strcmp(value[0].data, TOP_MAIN_BASIC_RULE_T) &&
ngx_strcmp(value[0].data, TOP_MAIN_BASIC_RULE_N)) {
ngx_http_naxsi_line_conf_error(cf, value);
return (NGX_CONF_ERROR);
}
value 的内容通过gdb调试输入如下:
(gdb) p value[0]
$1 = {len = 8, data = 0x7a0cc0 "MainRule"}
(gdb) p value[1]
$2 = {len = 107, data = 0x7a0cc9 "rx:select|union|update|delete|insert|table|from|ascii|hex|unhex|drop|load_file|substr|group_concat|dumpfile"}
(gdb) p value[2]
$3 = {len = 16, data = 0x7a0d35 "msg:sql keywords"}
(gdb) p value[3]
$4 = {len = 36, data = 0x7a0d46 "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie"}
(gdb) p value[4]
$5 = {len = 8, data = 0x7a0d6b "s:$SQL:4"}
(gdb) p value[5]
$6 = {len = 7, data = 0x7a0d74 "id:1000"}
(gdb) p value[6]
$7 = {len = 0, data = 0x0}
ngx_http_naxsi_cfg_parse_one_rule // 策略分析函数
ngx_http_naxsi_cfg_parse_one_rule函数主要部分:
看这部分前,请先看先看下下面rule_parser的定义:
// check each word of config line against each rule
// nb_elem为数组value的长度
for (i = 1; i < nb_elem && value[i].len > 0; i++) {
valid = 0;
for (z = 0; rule_parser[z].pars; z++) {
ngx_http_naxsi_parser_t* np = &rule_parser[z];
/*
如:当value[i].data 为 "id:1000" 与 np->prefix 为 "id:"的前缀相等时,则调用 ret = np->pars(cf, &value[i], current_rule);
即 naxsi_id 做"id:1000"这部分策略的解析
*/
if (!ngx_strncmp(value[i].data, np->prefix, np->prefix_len)) {
ret = np->pars(cf, &value[i], current_rule);
if (ret != NGX_CONF_OK) {
NX_LOG_DEBUG(_debug_cfg_parse_one_rule,
NGX_LOG_EMERG,
cf,
0,
"XX-FAILED PARSING '%s'",
value[i].data);
return (ret);
}
valid = 1;
}
}
return_value_if(!valid, NGX_CONF_ERROR);
}
先看下rule_parser的定义:
/*
MainRule “rx:select|union|update|delete|insert|table|from|ascii|hex|unhex|drop|load_file|substr|group_concat|dumpfile” “msg:sql keywords” “mz:BODY|URL|ARGS| H E A D E R S V A R : C o o k i e " " s : HEADERS_VAR:Cookie" "s: HEADERSVAR:Cookie""s:SQL:4” id:1000;
如上策略的每一部分都有对应的处理
*/
static ngx_http_naxsi_parser_t rule_parser[] = {
{ ID_T, const_len(ID_T), naxsi_id }, // id:1000 部分的处理
{ SCORE_T, const_len(SCORE_T), naxsi_score }, // "s:$SQL:4" 部分的处理
{ MSG_T, const_len(MSG_T), naxsi_msg }, // "msg:sql keywords" 部分的处理
{ RX_T, const_len(RX_T), naxsi_rx }, // "rx:select|union| 部分的处理
{ STR_T, const_len(STR_T), naxsi_str }, // 如果不是正则,即不是"rx: 开头,是str: 开头的话则调用naxsi_str函数做处理
{ LIBINJ_XSS_T, const_len(LIBINJ_XSS_T), naxsi_libinj_xss },
{ LIBINJ_SQL_T, const_len(LIBINJ_SQL_T), naxsi_libinj_sql },
{ MATCH_ZONE_T, const_len(MATCH_ZONE_T), naxsi_zone },
{ NEGATIVE_T, const_len(NEGATIVE_T), naxsi_negative },
{ WHITELIST_T, const_len(WHITELIST_T), naxsi_whitelist },
{ NULL, 0, NULL }
};
策略每部分的解析函数,如 naxsi_id:
void*
naxsi_id(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule)
{
rule->rule_id = atoi((const char*)tmp->data + strlen(ID_T));
return (NGX_CONF_OK);
}
ngx_http_naxsi_read_main_conf函数的后半部分
通过上面分析完策略后,下面就是对文章来源:https://www.toymoban.com/news/detail-595143.html
ngx_http_naxsi_main_conf_t* alcf = conf;
结构体的填充,依据匹配区域的压缩到结构体ngx_http_naxsi_main_conf_t定义的动态数组中,也即用户自定义的数据结构conf
如:文章来源地址https://www.toymoban.com/news/detail-595143.html
if (rule.br->headers || rule.br->headers_var) {
NX_LOG_DEBUG(
_debug_main_conf, NGX_LOG_EMERG, cf, 0, "pushing rule %d in header rules", rule.rule_id);
if (alcf->header_rules == NULL) {
alcf->header_rules = ngx_array_create(cf->pool, 2, sizeof(ngx_http_rule_t)); // nginx的动态数组实现
if (alcf->header_rules == NULL)
return NGX_CONF_ERROR; /* LCOV_EXCL_LINE */
}
// 返回指向新增加元素的指针,即 alcf->header_rules == rule_r
rule_r = ngx_array_push(alcf->header_rules); // nginx的动态数组实现, push时,当空间不够时,会自动扩容动态数组空间
if (!rule_r)
return (NGX_CONF_ERROR); /* LCOV_EXCL_LINE */
memcpy(rule_r, &rule, sizeof(ngx_http_rule_t));
}
到了这里,关于基于nginx的waf方案naxsi源码理解(6)_策略处理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!