diff --git a/inc/ngx_http_waf_module_check.h b/inc/ngx_http_waf_module_check.h index 5b8ec526..996247af 100644 --- a/inc/ngx_http_waf_module_check.h +++ b/inc/ngx_http_waf_module_check.h @@ -117,6 +117,14 @@ ngx_int_t ngx_http_waf_handler_check_white_referer(ngx_http_request_t* r); ngx_int_t ngx_http_waf_handler_check_black_referer(ngx_http_request_t* r); +/** + * @brief 检查 Cookie 是否在黑名单中 + * @return 如果在返回 MATCHED,反之返回 NOT_MATCHED。 + * @retval MATCHED 在黑名单中。 + * @retval NOT_MATCHED 不在黑名单中 +*/ +ngx_int_t ngx_http_waf_handler_check_white_cookie(ngx_http_request_t* r); + /** * @brief 检查 Cookie 是否在黑名单中 * @return 如果在返回 MATCHED,反之返回 NOT_MATCHED。 @@ -125,6 +133,22 @@ ngx_int_t ngx_http_waf_handler_check_black_referer(ngx_http_request_t* r); */ ngx_int_t ngx_http_waf_handler_check_black_cookie(ngx_http_request_t* r); +/** + * @brief 检查 TLS Fingerprint 是否在黑名单中 + * @return 如果在返回 MATCHED,反之返回 NOT_MATCHED。 + * @retval MATCHED 在黑名单中。 + * @retval NOT_MATCHED 不在黑名单中 +*/ +//ngx_int_t ngx_http_waf_handler_check_white_tls_fprint(ngx_http_request_t* r); + +/** + * @brief 检查 TLS Fingerprint 是否在黑名单中 + * @return 如果在返回 MATCHED,反之返回 NOT_MATCHED。 + * @retval MATCHED 在黑名单中。 + * @retval NOT_MATCHED 不在黑名单中 +*/ +//ngx_int_t ngx_http_waf_handler_check_black_tls_fprint(ngx_http_request_t* r); + /** * @brief 检查请求体内容是否存在于黑名单中,存在则拦截,反之放行。 diff --git a/inc/ngx_http_waf_module_macro.h b/inc/ngx_http_waf_module_macro.h index 8c28da95..2e4ebde9 100644 --- a/inc/ngx_http_waf_module_macro.h +++ b/inc/ngx_http_waf_module_macro.h @@ -17,6 +17,9 @@ #define NGX_HTTP_WAF_ARGS_FILE ("args") #define NGX_HTTP_WAF_UA_FILE ("user-agent") #define NGX_HTTP_WAF_REFERER_FILE ("referer") +//#define NGX_HTTP_WAF_WHITE_TLS_FPRINT_FILE ("white-tls-fingerprint") +//#define NGX_HTTP_WAF_TLS_FPRINT_FILE ("tls-fingerprint") +#define NGX_HTTP_WAF_WHITE_COOKIE_FILE ("white-cookie") #define NGX_HTTP_WAF_COOKIE_FILE ("cookie") #define NGX_HTTP_WAF_POST_FILE ("post") #define NGX_HTTP_WAF_WHITE_IPV4_FILE ("white-ipv4") @@ -243,6 +246,12 @@ */ #define NGX_HTTP_WAF_MODE_INSPECT_REFERER (NGX_HTTP_WAF_MODE_INSPECT_COOKIE << 1) +/** + * @def NGX_HTTP_WAF_MODE_INSPECT_TLS_FINGERPRINT + * @brief 启用 TLS FINGERPRINT 检查规则 +*/ +#define NGX_HTTP_WAF_MODE_INSPECT_TLS_FINGERPRINT (NGX_HTTP_WAF_MODE_INSPECT_REFERER << 1) + /** * @def NGX_HTTP_WAF_MODE_CMN_METH @@ -305,6 +314,7 @@ | NGX_HTTP_WAF_MODE_INSPECT_ARGS \ | NGX_HTTP_WAF_MODE_INSPECT_UA \ | NGX_HTTP_WAF_MODE_INSPECT_COOKIE \ + | NGX_HTTP_WAF_MODE_INSPECT_TLS_FINGERPRINT \ | NGX_HTTP_WAF_MODE_CMN_METH) diff --git a/inc/ngx_http_waf_module_tls_fingerprint.h b/inc/ngx_http_waf_module_tls_fingerprint.h new file mode 100644 index 00000000..4ab3775d --- /dev/null +++ b/inc/ngx_http_waf_module_tls_fingerprint.h @@ -0,0 +1,16 @@ +#ifndef __NGX_HTTP_WAF_TLS_FINGERPRINT_H__ +#define __NGX_HTTP_WAF_TLS_FINGERPRINT_H__ + +#include +#include +#include +#include +#include +#include + +#define IS_GREASE_CODE(code) (((code)&0x0f0f) == 0x0a0a && ((code)&0xff) == ((code)>>8)) + +int ngx_ssl_fingerprint(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *fingerprint); +int ngx_http2_fingerprint(ngx_connection_t *c, ngx_http_v2_connection_t *h2c, ngx_pool_t *pool, ngx_str_t *fingerprint); + +#endif // __NGX_HTTP_WAF_TLS_FINGERPRINT_H__ diff --git a/inc/ngx_http_waf_module_type.h b/inc/ngx_http_waf_module_type.h index 77d7edd2..3a386892 100644 --- a/inc/ngx_http_waf_module_type.h +++ b/inc/ngx_http_waf_module_type.h @@ -257,6 +257,7 @@ typedef enum { ACTION_FLAG_FROM_CC_DENY = 0x200, ACTION_FLAG_FROM_MODSECURITY = 0x400, ACTION_FLAG_FROM_CAPTCHA = 0x800, + ACTION_FLAG_FROM_TLS_FINGERPRINT= 0x900, ACTION_FLAG_FROM_UNDER_ATTACK = 0x1000, ACTION_FLAG_FROM_VERIFY_BOT = 0x2000, ACTION_FLAG_CAPTCHA = 0x4000, @@ -392,6 +393,9 @@ typedef struct ngx_http_waf_loc_conf_s { ngx_array_t *black_args; /**< args 黑名单 */ ngx_array_t *black_ua; /**< user-agent 黑名单 */ ngx_array_t *black_referer; /**< Referer 黑名单 */ +// ngx_array_t *white_tls_fprint; /**< White TLS Fingerprint 黑名单 */ +// ngx_array_t *black_tls_fprint; /**< TLS Fingerprint 黑名单 */ + ngx_array_t *white_cookie; /**< White Cookie 黑名单 */ ngx_array_t *black_cookie; /**< Cookie 黑名单 */ ngx_array_t *black_post; /**< 请求体内容黑名单 */ ip_trie_t *white_ipv4; /**< IPV4 白名单 */ @@ -406,6 +410,9 @@ typedef struct ngx_http_waf_loc_conf_s { lru_cache_t *black_args_inspection_cache; /**< ARGS 黑名单检查缓存 */ lru_cache_t *black_ua_inspection_cache; /**< User-Agent 黑名单检查缓存 */ lru_cache_t *black_referer_inspection_cache; /**< Referer 黑名单检查缓存 */ +// lru_cache_t *white_tls_fprint_inspection_cache; /**< White TLS Fingerprint 黑名单检查缓存 */ +// lru_cache_t *black_tls_fprint_inspection_cache; /**< TLS Fingerprint 黑名单检查缓存 */ + lru_cache_t *white_cookie_inspection_cache; /**< White Cookie 黑名单检查缓存 */ lru_cache_t *black_cookie_inspection_cache; /**< Cookie 黑名单检查缓存 */ lru_cache_t *white_url_inspection_cache; /**< URL 白名单检查缓存 */ lru_cache_t *white_referer_inspection_cache; /**< Referer 白名单检查缓存 */ diff --git a/src/.ngx_http_waf_module_var.c.swp b/src/.ngx_http_waf_module_var.c.swp new file mode 100644 index 00000000..ea2ac636 Binary files /dev/null and b/src/.ngx_http_waf_module_var.c.swp differ diff --git a/src/ngx_http_waf_module_check.c b/src/ngx_http_waf_module_check.c index e6d2ec7f..625294a3 100644 --- a/src/ngx_http_waf_module_check.c +++ b/src/ngx_http_waf_module_check.c @@ -4,787 +4,876 @@ extern ngx_module_t ngx_http_waf_module; /**< 模块详情 */ ngx_int_t ngx_http_waf_handler_check_white_ip(ngx_http_request_t* r) { - ngx_http_waf_dp_func_start(r); - - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); - - ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; - action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); - - ngx_http_waf_set_action_decline(action, ACTION_FLAG_FROM_WHITE_LIST); - - if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_IP)) { - ngx_http_waf_dp(r, "nothing to do ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - ip_trie_node_t* ip_trie_node = NULL; - inx_addr_t inx_addr; - ngx_http_waf_make_inx_addr(r, &inx_addr); - - if (r->connection->sockaddr->sa_family == AF_INET) { - ngx_http_waf_dp(r, "matching ipv4"); - if (ip_trie_find(loc_conf->white_ipv4, &inx_addr, &ip_trie_node) == NGX_HTTP_WAF_SUCCESS) { - ngx_http_waf_dpf(r, "matched(%s)", ip_trie_node->data); - ctx->gernal_logged = 1; - ctx->blocked = 0; - ngx_http_waf_set_rule_info(r, "WHITE-IPV4", ip_trie_node->data, - NGX_HTTP_WAF_TRUE, NGX_HTTP_WAF_FALSE); - ngx_http_waf_append_action(r, action); - ret_value = NGX_HTTP_WAF_MATCHED; - } else { - ngx_http_waf_dp(r, "not matched"); - } - } -#if (NGX_HAVE_INET6) - else if (r->connection->sockaddr->sa_family == AF_INET6) { - ngx_http_waf_dp(r, "matching ipv6"); - if (ip_trie_find(loc_conf->white_ipv6, &inx_addr, &ip_trie_node) == NGX_HTTP_WAF_SUCCESS) { - ngx_http_waf_dpf(r, "matched(%s)", ip_trie_node->data); - ctx->gernal_logged = 1; - ctx->blocked = 0; - ngx_http_waf_set_rule_info(r, "WHITE-IPV6", ip_trie_node->data, - NGX_HTTP_WAF_TRUE, NGX_HTTP_WAF_FALSE); - ngx_http_waf_append_action(r, action); - ret_value = NGX_HTTP_WAF_MATCHED; - } else { - ngx_http_waf_dp(r, "not matched"); - } - } -#endif - - ngx_http_waf_dp_func_end(r); - return ret_value; + ngx_http_waf_dp_func_start(r); + + ngx_http_waf_ctx_t* ctx = NULL; + ngx_http_waf_loc_conf_t* loc_conf = NULL; + ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); + + ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; + action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); + + ngx_http_waf_set_action_decline(action, ACTION_FLAG_FROM_WHITE_LIST); + + if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_IP)) { + ngx_http_waf_dp(r, "nothing to do ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + ip_trie_node_t* ip_trie_node = NULL; + inx_addr_t inx_addr; + ngx_http_waf_make_inx_addr(r, &inx_addr); + + if (r->connection->sockaddr->sa_family == AF_INET) { + ngx_http_waf_dp(r, "matching ipv4"); + if (ip_trie_find(loc_conf->white_ipv4, &inx_addr, &ip_trie_node) == NGX_HTTP_WAF_SUCCESS) { + ngx_http_waf_dpf(r, "matched(%s)", ip_trie_node->data); + ctx->gernal_logged = 1; + ctx->blocked = 0; + ngx_http_waf_set_rule_info(r, "WHITE-IPV4", ip_trie_node->data, + NGX_HTTP_WAF_TRUE, NGX_HTTP_WAF_FALSE); + ngx_http_waf_append_action(r, action); + ret_value = NGX_HTTP_WAF_MATCHED; + } else { + ngx_http_waf_dp(r, "not matched"); + } + } + #if (NGX_HAVE_INET6) + else if (r->connection->sockaddr->sa_family == AF_INET6) { + ngx_http_waf_dp(r, "matching ipv6"); + if (ip_trie_find(loc_conf->white_ipv6, &inx_addr, &ip_trie_node) == NGX_HTTP_WAF_SUCCESS) { + ngx_http_waf_dpf(r, "matched(%s)", ip_trie_node->data); + ctx->gernal_logged = 1; + ctx->blocked = 0; + ngx_http_waf_set_rule_info(r, "WHITE-IPV6", ip_trie_node->data, + NGX_HTTP_WAF_TRUE, NGX_HTTP_WAF_FALSE); + ngx_http_waf_append_action(r, action); + ret_value = NGX_HTTP_WAF_MATCHED; + } else { + ngx_http_waf_dp(r, "not matched"); + } + } + #endif + + ngx_http_waf_dp_func_end(r); + return ret_value; } ngx_int_t ngx_http_waf_handler_check_black_ip(ngx_http_request_t* r) { - ngx_http_waf_dp_func_start(r); - - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); - - ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; - action_t* action = NULL; - - ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_blacklist); - - if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_IP)) { - ngx_http_waf_dp(r, "nothing to do ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - ip_trie_node_t *ip_trie_node = NULL; - inx_addr_t inx_addr; - ngx_http_waf_make_inx_addr(r, &inx_addr); - - if (r->connection->sockaddr->sa_family == AF_INET) { - ngx_http_waf_dp(r, "matching ipv4"); - if (ip_trie_find(loc_conf->black_ipv4, &inx_addr, &ip_trie_node) == NGX_HTTP_WAF_SUCCESS) { - ngx_http_waf_dpf(r, "matched(%s)", ip_trie_node->data); - ctx->gernal_logged = 1; - ctx->blocked = 1; - ngx_http_waf_set_rule_info(r, "BLACK-IPV4", ip_trie_node->data, - NGX_HTTP_WAF_TRUE, NGX_HTTP_WAF_TRUE); - ngx_http_waf_append_action_chain(r, action); - ret_value = NGX_HTTP_WAF_MATCHED; - } else { - ngx_http_waf_dp(r, "not matched"); - } - } -#if (NGX_HAVE_INET6) - else if (r->connection->sockaddr->sa_family == AF_INET6) { - ngx_http_waf_dp(r, "matching ipv6"); - if (ip_trie_find(loc_conf->black_ipv6, &inx_addr, &ip_trie_node) == NGX_HTTP_WAF_SUCCESS) { - ngx_http_waf_dpf(r, "matched(%s)", ip_trie_node->data); - ctx->gernal_logged = 1; - ctx->blocked = 1; - ngx_http_waf_set_rule_info(r, "BLACK-IPV6", ip_trie_node->data, - NGX_HTTP_WAF_TRUE, NGX_HTTP_WAF_TRUE); - ngx_http_waf_append_action_chain(r, action); - ret_value = NGX_HTTP_WAF_MATCHED; - } else { - ngx_http_waf_dp(r, "not matched"); - } - } -#endif - - ngx_http_waf_dp_func_end(r); - return ret_value; + ngx_http_waf_dp_func_start(r); + + ngx_http_waf_ctx_t* ctx = NULL; + ngx_http_waf_loc_conf_t* loc_conf = NULL; + ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); + + ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; + action_t* action = NULL; + + ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_blacklist); + + if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_IP)) { + ngx_http_waf_dp(r, "nothing to do ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + ip_trie_node_t *ip_trie_node = NULL; + inx_addr_t inx_addr; + ngx_http_waf_make_inx_addr(r, &inx_addr); + + if (r->connection->sockaddr->sa_family == AF_INET) { + ngx_http_waf_dp(r, "matching ipv4"); + if (ip_trie_find(loc_conf->black_ipv4, &inx_addr, &ip_trie_node) == NGX_HTTP_WAF_SUCCESS) { + ngx_http_waf_dpf(r, "matched(%s)", ip_trie_node->data); + ctx->gernal_logged = 1; + ctx->blocked = 1; + ngx_http_waf_set_rule_info(r, "BLACK-IPV4", ip_trie_node->data, + NGX_HTTP_WAF_TRUE, NGX_HTTP_WAF_TRUE); + ngx_http_waf_append_action_chain(r, action); + ret_value = NGX_HTTP_WAF_MATCHED; + } else { + ngx_http_waf_dp(r, "not matched"); + } + } + #if (NGX_HAVE_INET6) + else if (r->connection->sockaddr->sa_family == AF_INET6) { + ngx_http_waf_dp(r, "matching ipv6"); + if (ip_trie_find(loc_conf->black_ipv6, &inx_addr, &ip_trie_node) == NGX_HTTP_WAF_SUCCESS) { + ngx_http_waf_dpf(r, "matched(%s)", ip_trie_node->data); + ctx->gernal_logged = 1; + ctx->blocked = 1; + ngx_http_waf_set_rule_info(r, "BLACK-IPV6", ip_trie_node->data, + NGX_HTTP_WAF_TRUE, NGX_HTTP_WAF_TRUE); + ngx_http_waf_append_action_chain(r, action); + ret_value = NGX_HTTP_WAF_MATCHED; + } else { + ngx_http_waf_dp(r, "not matched"); + } + } + #endif + + ngx_http_waf_dp_func_end(r); + return ret_value; } ngx_int_t ngx_http_waf_handler_check_cc(ngx_http_request_t* r) { - ngx_http_waf_dp_func_start(r); - - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); - - ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; - time_t now = time(NULL); - action_t* action = NULL; - - ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_cc_deny); - - if (ngx_http_waf_is_unset_or_disable_value(loc_conf->waf_cc_deny)) { - ngx_http_waf_dp(r, "nothing to do ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - if (ngx_http_waf_is_unset_or_disable_value(loc_conf->waf_cc_deny_duration) - || ngx_http_waf_is_unset_or_disable_value(loc_conf->waf_cc_deny_limit) - || ngx_http_waf_is_unset_or_disable_value(loc_conf->waf_cc_deny_cycle) - || !ngx_http_waf_is_valid_ptr_value(loc_conf->shm_zone_cc_deny) - || !ngx_http_waf_is_valid_ptr_value(loc_conf->ip_access_statistics)) { - ngx_http_waf_dp(r, "invalid configuratiion ... return"); - ngx_http_waf_append_action_return(r, NGX_HTTP_INTERNAL_SERVER_ERROR, ACTION_FLAG_FROM_CC_DENY); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - ngx_http_waf_dp(r, "generating inx_addr_t"); - inx_addr_t inx_addr; - ngx_http_waf_make_inx_addr(r, &inx_addr); - ngx_http_waf_dp(r, "success"); - - ngx_int_t limit = loc_conf->waf_cc_deny_limit; - ngx_int_t duration = loc_conf->waf_cc_deny_duration; - ip_statis_t* statis = NULL; - ngx_http_waf_dpf(r, "limit: %i, duration: %i", limit, duration); - - - ngx_slab_pool_t *shpool = (ngx_slab_pool_t *)loc_conf->shm_zone_cc_deny->shm.addr; - ngx_http_waf_dp(r, "locking shared memory"); - ngx_shmtx_lock(&shpool->mutex); - ngx_http_waf_dp(r, "success"); - - ngx_http_waf_dp(r, "getting cache"); - lru_cache_find_result_t tmp0 = lru_cache_find(loc_conf->ip_access_statistics, &inx_addr, sizeof(inx_addr_t)); - if (tmp0.status == NGX_HTTP_WAF_KEY_EXISTS) { - ngx_http_waf_dp(r, "found"); - statis = *(tmp0).data; - } else { - ngx_http_waf_dp(r, "not found"); - - ngx_http_waf_dp(r, "adding cache"); - lru_cache_add_result_t tmp1 = lru_cache_add( - loc_conf->ip_access_statistics, - &inx_addr, - sizeof(inx_addr_t), - loc_conf->waf_cc_deny_cycle); - - if (tmp1.status == NGX_HTTP_WAF_SUCCESS) { - statis = mem_pool_calloc(loc_conf->ip_access_statistics->pool, sizeof(ip_statis_t)); - if (statis == NULL) { - ngx_http_waf_dp(r, "no memroy ... exception"); - goto exception; - } - statis->count = 0; - statis->is_blocked = NGX_HTTP_WAF_FALSE; - statis->record_time = now; - statis->block_time = 0; - ctx->rate = 0; - *(tmp1.data) = statis; - ngx_http_waf_dp(r, "success"); - - } else { - goto exception; - } - } - - // double diff_second_record = difftime(now, statis->record_time); - // double diff_second_block = difftime(now, statis->block_time); - - if (statis->count != NGX_MAX_INT_T_VALUE) { - statis->count++; - } - - ctx->rate = statis->count; - - if (statis->count > loc_conf->waf_cc_deny_limit) { - if (statis->count -1 <= loc_conf->waf_cc_deny_limit) { - lru_cache_set_expire(loc_conf->ip_access_statistics, &inx_addr, sizeof(inx_addr_t), - loc_conf->waf_cc_deny_duration); - } - - goto matched; - } - - // /* 如果已经被拦截 */ - // if (statis->is_blocked == NGX_HTTP_WAF_TRUE) { - // /* 如果还在拦截时间内 */ - // if (diff_second_block < duration) { - // ngx_http_waf_dp(r, "still blocked"); - // goto matched; - // } else { - // ngx_http_waf_dp(r, "reset record"); - // statis->count = 1; - // statis->is_blocked = NGX_HTTP_WAF_FALSE; - // statis->record_time = now; - // statis->block_time = 0; - // ctx->rate = 1; - // } - // } - // /* 如果还在一个统计周期内 */ - // else if (diff_second_record <= loc_conf->waf_cc_deny_cycle) { - // /* 如果访问频率超出限制 */ - // if (statis->count > limit) { - // ngx_http_waf_dp(r, "start blocking"); - // goto matched; - // } - // } else { - // ngx_http_waf_dp(r, "expired cache"); - // statis->count = 1; - // statis->is_blocked = NGX_HTTP_WAF_FALSE; - // statis->record_time = now; - // statis->block_time = 0; - // ctx->rate = 1; - // } - - - goto unlock; - - matched: - { - ngx_http_waf_dp(r, "flow: matched"); - goto block; - } - - block: - { - ngx_http_waf_dp(r, "flow: block"); - - ctx->gernal_logged = 1; - ctx->blocked = 1; - ngx_http_waf_set_rule_info(r, "CC-DENY", "", NGX_HTTP_WAF_TRUE, NGX_HTTP_WAF_TRUE); - ngx_http_waf_append_action_chain(r, action); - ret_value = NGX_HTTP_WAF_MATCHED; - time_t remain = duration - (now - statis->block_time); - - /* 如果不是 444 状态码则生成响应头 Retry-After。*/ - if (ngx_http_waf_check_flag(action->flag, ACTION_FLAG_RETURN) && action->extra.http_status != NGX_HTTP_CLOSE) { - ngx_http_waf_dp(r, "generating reponse header: Retry-After "); - ngx_table_elt_t* header = (ngx_table_elt_t*)ngx_list_push(&(r->headers_out.headers)); - if (header == NULL) { - ngx_http_waf_dp(r, "failed ... unlock"); - goto unlock; - } - - /* 如果 hash 字段为 0 则会在遍历 HTTP 头的时候被忽略 */ - header->hash = 1; - header->lowcase_key = (u_char*)"Retry-After"; - ngx_str_set(&header->key, "Retry-After"); - header->value.data = ngx_palloc(r->pool, NGX_TIME_T_LEN + 1); - if (header->value.data == NULL) { - ngx_http_waf_dp(r, "no memory ... unlock"); - goto unlock; - } - - #if (NGX_TIME_T_SIZE == 4) - header->value.len = sprintf((char*)header->value.data, "%d", (int)remain); - #elif (NGX_TIME_T_SIZE == 8) - header->value.len = sprintf((char*)header->value.data, "%lld", (long long)remain); - #else - #error The size of time_t is unexpected. - #endif - ngx_http_waf_dpf(r, "success(%V=%V)", &header->key, &header->value); - } - goto unlock; - } - - exception: - { - ngx_http_waf_dp(r, "flow expcetion"); - ngx_http_waf_append_action_return(r, NGX_HTTP_SERVICE_UNAVAILABLE, ACTION_FLAG_FROM_CC_DENY); - ret_value = NGX_HTTP_WAF_MATCHED; - goto unlock; - } - // no_memory: - // not_matched: - unlock: - ngx_http_waf_dp(r, "flow unlock"); - - ngx_http_waf_dp(r, "unlocking shared memory") - ngx_shmtx_unlock(&shpool->mutex); - ngx_http_waf_dp(r, "success"); - - - ngx_http_waf_dp_func_end(r); - return ret_value; + ngx_http_waf_dp_func_start(r); + + ngx_http_waf_ctx_t* ctx = NULL; + ngx_http_waf_loc_conf_t* loc_conf = NULL; + ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); + + ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; + time_t now = time(NULL); + action_t* action = NULL; + + ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_cc_deny); + + if (ngx_http_waf_is_unset_or_disable_value(loc_conf->waf_cc_deny)) { + ngx_http_waf_dp(r, "nothing to do ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + if (ngx_http_waf_is_unset_or_disable_value(loc_conf->waf_cc_deny_duration) + || ngx_http_waf_is_unset_or_disable_value(loc_conf->waf_cc_deny_limit) + || ngx_http_waf_is_unset_or_disable_value(loc_conf->waf_cc_deny_cycle) + || !ngx_http_waf_is_valid_ptr_value(loc_conf->shm_zone_cc_deny) + || !ngx_http_waf_is_valid_ptr_value(loc_conf->ip_access_statistics)) { + ngx_http_waf_dp(r, "invalid configuratiion ... return"); + ngx_http_waf_append_action_return(r, NGX_HTTP_INTERNAL_SERVER_ERROR, ACTION_FLAG_FROM_CC_DENY); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + ngx_http_waf_dp(r, "generating inx_addr_t"); + inx_addr_t inx_addr; + ngx_http_waf_make_inx_addr(r, &inx_addr); + ngx_http_waf_dp(r, "success"); + + ngx_int_t limit = loc_conf->waf_cc_deny_limit; + ngx_int_t duration = loc_conf->waf_cc_deny_duration; + ip_statis_t* statis = NULL; + ngx_http_waf_dpf(r, "limit: %i, duration: %i", limit, duration); + + + ngx_slab_pool_t *shpool = (ngx_slab_pool_t *)loc_conf->shm_zone_cc_deny->shm.addr; + ngx_http_waf_dp(r, "locking shared memory"); + ngx_shmtx_lock(&shpool->mutex); + ngx_http_waf_dp(r, "success"); + + ngx_http_waf_dp(r, "getting cache"); + lru_cache_find_result_t tmp0 = lru_cache_find(loc_conf->ip_access_statistics, &inx_addr, sizeof(inx_addr_t)); + if (tmp0.status == NGX_HTTP_WAF_KEY_EXISTS) { + ngx_http_waf_dp(r, "found"); + statis = *(tmp0).data; + } else { + ngx_http_waf_dp(r, "not found"); + + ngx_http_waf_dp(r, "adding cache"); + lru_cache_add_result_t tmp1 = lru_cache_add( + loc_conf->ip_access_statistics, + &inx_addr, + sizeof(inx_addr_t), + loc_conf->waf_cc_deny_cycle); + + if (tmp1.status == NGX_HTTP_WAF_SUCCESS) { + statis = mem_pool_calloc(loc_conf->ip_access_statistics->pool, sizeof(ip_statis_t)); + if (statis == NULL) { + ngx_http_waf_dp(r, "no memroy ... exception"); + goto exception; + } + statis->count = 0; + statis->is_blocked = NGX_HTTP_WAF_FALSE; + statis->record_time = now; + statis->block_time = 0; + ctx->rate = 0; + *(tmp1.data) = statis; + ngx_http_waf_dp(r, "success"); + + } else { + goto exception; + } + } + + // double diff_second_record = difftime(now, statis->record_time); + // double diff_second_block = difftime(now, statis->block_time); + + if (statis->count != NGX_MAX_INT_T_VALUE) { + statis->count++; + } + + ctx->rate = statis->count; + + if (statis->count > loc_conf->waf_cc_deny_limit) { + if (statis->count -1 <= loc_conf->waf_cc_deny_limit) { + lru_cache_set_expire(loc_conf->ip_access_statistics, &inx_addr, sizeof(inx_addr_t), loc_conf->waf_cc_deny_duration); + } + goto matched; + } + + // /* 如果已经被拦截 */ + // if (statis->is_blocked == NGX_HTTP_WAF_TRUE) { + // /* 如果还在拦截时间内 */ + // if (diff_second_block < duration) { + // ngx_http_waf_dp(r, "still blocked"); + // goto matched; + // } else { + // ngx_http_waf_dp(r, "reset record"); + // statis->count = 1; + // statis->is_blocked = NGX_HTTP_WAF_FALSE; + // statis->record_time = now; + // statis->block_time = 0; + // ctx->rate = 1; + // } + // } + // /* 如果还在一个统计周期内 */ + // else if (diff_second_record <= loc_conf->waf_cc_deny_cycle) { + // /* 如果访问频率超出限制 */ + // if (statis->count > limit) { + // ngx_http_waf_dp(r, "start blocking"); + // goto matched; + // } + // } else { + // ngx_http_waf_dp(r, "expired cache"); + // statis->count = 1; + // statis->is_blocked = NGX_HTTP_WAF_FALSE; + // statis->record_time = now; + // statis->block_time = 0; + // ctx->rate = 1; + // } + + + goto unlock; + + matched: + { + ngx_http_waf_dp(r, "flow: matched"); + goto block; + } + + block: + { + ngx_http_waf_dp(r, "flow: block"); + + ctx->gernal_logged = 1; + ctx->blocked = 1; + ngx_http_waf_set_rule_info(r, "CC-DENY", "", NGX_HTTP_WAF_TRUE, NGX_HTTP_WAF_TRUE); + ngx_http_waf_append_action_chain(r, action); + ret_value = NGX_HTTP_WAF_MATCHED; + time_t remain = duration - (now - statis->block_time); + + /* 如果不是 444 状态码则生成响应头 Retry-After。*/ + if (ngx_http_waf_check_flag(action->flag, ACTION_FLAG_RETURN) && action->extra.http_status != NGX_HTTP_CLOSE) { + ngx_http_waf_dp(r, "generating reponse header: Retry-After "); + ngx_table_elt_t* header = (ngx_table_elt_t*)ngx_list_push(&(r->headers_out.headers)); + if (header == NULL) { + ngx_http_waf_dp(r, "failed ... unlock"); + goto unlock; + } + + /* 如果 hash 字段为 0 则会在遍历 HTTP 头的时候被忽略 */ + header->hash = 1; + header->lowcase_key = (u_char*)"Retry-After"; + ngx_str_set(&header->key, "Retry-After"); + header->value.data = ngx_palloc(r->pool, NGX_TIME_T_LEN + 1); + if (header->value.data == NULL) { + ngx_http_waf_dp(r, "no memory ... unlock"); + goto unlock; + } + + #if (NGX_TIME_T_SIZE == 4) + header->value.len = sprintf((char*)header->value.data, "%d", (int)remain); + #elif (NGX_TIME_T_SIZE == 8) + header->value.len = sprintf((char*)header->value.data, "%lld", (long long)remain); + #else + #error The size of time_t is unexpected. + #endif + ngx_http_waf_dpf(r, "success(%V=%V)", &header->key, &header->value); + } + goto unlock; + } + + exception: + { + ngx_http_waf_dp(r, "flow expcetion"); + ngx_http_waf_append_action_return(r, NGX_HTTP_SERVICE_UNAVAILABLE, ACTION_FLAG_FROM_CC_DENY); + ret_value = NGX_HTTP_WAF_MATCHED; + goto unlock; + } + // no_memory: + // not_matched: + unlock: + ngx_http_waf_dp(r, "flow unlock"); + + ngx_http_waf_dp(r, "unlocking shared memory") + ngx_shmtx_unlock(&shpool->mutex); + ngx_http_waf_dp(r, "success"); + + + ngx_http_waf_dp_func_end(r); + return ret_value; } ngx_int_t ngx_http_waf_handler_check_white_url(ngx_http_request_t* r) { - ngx_http_waf_dp_func_start(r); - - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); - - ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; - action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); - - ngx_http_waf_set_action_decline(action, ACTION_FLAG_FROM_WHITE_LIST); - - if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_URL | r->method)) { - ngx_http_waf_dp(r, "nothing to do ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - ngx_str_t* p_uri = &r->uri; - ngx_array_t* regex_array = loc_conf->white_url; - lru_cache_t* cache = loc_conf->white_url_inspection_cache; - - ngx_http_waf_dpf(r, "matching uri(%V)", p_uri); - ret_value = ngx_http_waf_regex_exec_arrray(r, p_uri, regex_array, (u_char*)"WHITE-URL", cache); - - if (ret_value == NGX_HTTP_WAF_MATCHED) { - ngx_http_waf_dp(r, "matched"); - ctx->gernal_logged = 1; - ctx->blocked = 0; - ngx_http_waf_append_action(r, action); - } else { - ngx_http_waf_dp(r, "not matched"); - } - - ngx_http_waf_dp_func_end(r); - return ret_value; + ngx_http_waf_dp_func_start(r); + + ngx_http_waf_ctx_t* ctx = NULL; + ngx_http_waf_loc_conf_t* loc_conf = NULL; + ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); + + ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; + action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); + + ngx_http_waf_set_action_decline(action, ACTION_FLAG_FROM_WHITE_LIST); + + if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_URL | r->method)) { + ngx_http_waf_dp(r, "nothing to do ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + ngx_str_t* p_uri = &r->uri; + ngx_array_t* regex_array = loc_conf->white_url; + lru_cache_t* cache = loc_conf->white_url_inspection_cache; + + ngx_http_waf_dpf(r, "matching uri(%V)", p_uri); + ret_value = ngx_http_waf_regex_exec_arrray(r, p_uri, regex_array, (u_char*)"WHITE-URL", cache); + + if (ret_value == NGX_HTTP_WAF_MATCHED) { + ngx_http_waf_dp(r, "matched"); + ctx->gernal_logged = 1; + ctx->blocked = 0; + ngx_http_waf_append_action(r, action); + } else { + ngx_http_waf_dp(r, "not matched"); + } + + ngx_http_waf_dp_func_end(r); + return ret_value; } ngx_int_t ngx_http_waf_handler_check_black_url(ngx_http_request_t* r) { - ngx_http_waf_dp_func_start(r); + ngx_http_waf_dp_func_start(r); - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); + ngx_http_waf_ctx_t* ctx = NULL; + ngx_http_waf_loc_conf_t* loc_conf = NULL; + ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); - ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; - action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); + ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; + action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); - ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_blacklist); + ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_blacklist); - if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_URL | r->method)) { - ngx_http_waf_dp(r, "nothing to do ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } + if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_URL | r->method)) { + ngx_http_waf_dp(r, "nothing to do ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } - ngx_str_t* p_uri = &r->uri; - ngx_array_t* regex_array = loc_conf->black_url; - lru_cache_t* cache = loc_conf->black_url_inspection_cache; + ngx_str_t* p_uri = &r->uri; + ngx_array_t* regex_array = loc_conf->black_url; + lru_cache_t* cache = loc_conf->black_url_inspection_cache; - ngx_http_waf_dpf(r, "matching uri(%V)", p_uri); - ret_value = ngx_http_waf_regex_exec_arrray(r, p_uri, regex_array, (u_char*)"BLACK-URL", cache); + ngx_http_waf_dpf(r, "matching uri(%V)", p_uri); + ret_value = ngx_http_waf_regex_exec_arrray(r, p_uri, regex_array, (u_char*)"BLACK-URL", cache); - if (ret_value == NGX_HTTP_WAF_MATCHED) { - ngx_http_waf_dp(r, "matched"); - ctx->gernal_logged = 1; - ctx->blocked = 1; - ngx_http_waf_append_action_chain(r, action); - } else { - ngx_http_waf_dp(r, "not matched"); - } + if (ret_value == NGX_HTTP_WAF_MATCHED) { + ngx_http_waf_dp(r, "matched"); + ctx->gernal_logged = 1; + ctx->blocked = 1; + ngx_http_waf_append_action_chain(r, action); + } else { + ngx_http_waf_dp(r, "not matched"); + } - ngx_http_waf_dp_func_end(r); - return ret_value; + ngx_http_waf_dp_func_end(r); + return ret_value; } ngx_int_t ngx_http_waf_handler_check_black_args(ngx_http_request_t* r) { - ngx_http_waf_dp_func_start(r); + ngx_http_waf_dp_func_start(r); - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); + ngx_http_waf_ctx_t* ctx = NULL; + ngx_http_waf_loc_conf_t* loc_conf = NULL; + ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); - ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; - action_t* action = NULL; + ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; + action_t* action = NULL; - ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_blacklist); + ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_blacklist); - if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_ARGS | r->method)) { - ngx_http_waf_dp(r, "nothing to do ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } + if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_ARGS | r->method)) { + ngx_http_waf_dp(r, "nothing to do ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } - ngx_str_t* p_args = &r->args; - ngx_array_t* regex_array = loc_conf->black_args; - lru_cache_t* cache = loc_conf->black_args_inspection_cache; + ngx_str_t* p_args = &r->args; + ngx_array_t* regex_array = loc_conf->black_args; + lru_cache_t* cache = loc_conf->black_args_inspection_cache; - ngx_http_waf_dpf(r, "matching args(%V)", p_args); - ret_value = ngx_http_waf_regex_exec_arrray(r, p_args, regex_array, (u_char*)"BLACK-ARGS", cache); + ngx_http_waf_dpf(r, "matching args(%V)", p_args); + ret_value = ngx_http_waf_regex_exec_arrray(r, p_args, regex_array, (u_char*)"BLACK-ARGS", cache); - if (ret_value == NGX_HTTP_WAF_MATCHED) { - ngx_http_waf_dp(r, "matched"); - ctx->gernal_logged = 1; - ctx->blocked = 1; - ngx_http_waf_append_action_chain(r, action); - } else { - ngx_http_waf_dp(r, "not matched"); - } + if (ret_value == NGX_HTTP_WAF_MATCHED) { + ngx_http_waf_dp(r, "matched"); + ctx->gernal_logged = 1; + ctx->blocked = 1; + ngx_http_waf_append_action_chain(r, action); + } else { + ngx_http_waf_dp(r, "not matched"); + } - ngx_http_waf_dp_func_end(r); - return ret_value; + ngx_http_waf_dp_func_end(r); + return ret_value; } ngx_int_t ngx_http_waf_handler_check_black_user_agent(ngx_http_request_t* r) { - ngx_http_waf_dp_func_start(r); - - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); - - ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; - action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); - - ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_blacklist); - - if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_UA | r->method)) { - ngx_http_waf_dp(r, "nothing to do ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - if (r->headers_in.user_agent == NULL) { - ngx_http_waf_dp(r, "empty user-agent ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - ngx_str_t* p_ua = &r->headers_in.user_agent->value; - ngx_array_t* regex_array = loc_conf->black_ua; - lru_cache_t* cache = loc_conf->black_ua_inspection_cache; - - ngx_http_waf_dpf(r, "matching user-agent(%V)", p_ua); - ret_value = ngx_http_waf_regex_exec_arrray(r, p_ua, regex_array, (u_char*)"BLACK-UA", cache); - - if (ret_value == NGX_HTTP_WAF_MATCHED) { - ngx_http_waf_dp(r, "matched"); - ctx->gernal_logged = 1; - ctx->blocked = 1; - ngx_http_waf_append_action_chain(r, action); - } else { - ngx_http_waf_dp(r, "not matched"); - } - - ngx_http_waf_dp_func_end(r); - return ret_value; + ngx_http_waf_dp_func_start(r); + + ngx_http_waf_ctx_t* ctx = NULL; + ngx_http_waf_loc_conf_t* loc_conf = NULL; + ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); + + ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; + action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); + + ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_blacklist); + + if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_UA | r->method)) { + ngx_http_waf_dp(r, "nothing to do ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + if (r->headers_in.user_agent == NULL) { + ngx_http_waf_dp(r, "empty user-agent ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + ngx_str_t* p_ua = &r->headers_in.user_agent->value; + ngx_array_t* regex_array = loc_conf->black_ua; + lru_cache_t* cache = loc_conf->black_ua_inspection_cache; + + ngx_http_waf_dpf(r, "matching user-agent(%V)", p_ua); + ret_value = ngx_http_waf_regex_exec_arrray(r, p_ua, regex_array, (u_char*)"BLACK-UA", cache); + + if (ret_value == NGX_HTTP_WAF_MATCHED) { + ngx_http_waf_dp(r, "matched"); + ctx->gernal_logged = 1; + ctx->blocked = 1; + ngx_http_waf_append_action_chain(r, action); + } else { + ngx_http_waf_dp(r, "not matched"); + } + + ngx_http_waf_dp_func_end(r); + return ret_value; } ngx_int_t ngx_http_waf_handler_check_white_referer(ngx_http_request_t* r) { - ngx_http_waf_dp_func_start(r); - - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); - - ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; - action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); - - ngx_http_waf_set_action_decline(action, ACTION_FLAG_FROM_WHITE_LIST); - - if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_REFERER | r->method)) { - ngx_http_waf_dp(r, "nothing to do ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - if (r->headers_in.referer == NULL) { - ngx_http_waf_dp(r, "empty referer ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - - ngx_str_t* p_referer = &r->headers_in.referer->value; - ngx_array_t* regex_array = loc_conf->white_referer; - lru_cache_t* cache = loc_conf->white_referer_inspection_cache; - - ngx_http_waf_dpf(r, "matching referer(%V)", p_referer); - ret_value = ngx_http_waf_regex_exec_arrray(r, p_referer, regex_array, (u_char*)"WHITE-REFERER", cache); - - if (ret_value == NGX_HTTP_WAF_MATCHED) { - ngx_http_waf_dp(r, "matched"); - ctx->gernal_logged = 1; - ctx->blocked = 0; - ngx_http_waf_append_action(r, action); - } else { - ngx_http_waf_dp(r, "not matched"); - } - - ngx_http_waf_dp_func_end(r); - return ret_value; + ngx_http_waf_dp_func_start(r); + + ngx_http_waf_ctx_t* ctx = NULL; + ngx_http_waf_loc_conf_t* loc_conf = NULL; + ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); + + ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; + action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); + + ngx_http_waf_set_action_decline(action, ACTION_FLAG_FROM_WHITE_LIST); + + if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_REFERER | r->method)) { + ngx_http_waf_dp(r, "nothing to do ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + if (r->headers_in.referer == NULL) { + ngx_http_waf_dp(r, "empty referer ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + + ngx_str_t* p_referer = &r->headers_in.referer->value; + ngx_array_t* regex_array = loc_conf->white_referer; + lru_cache_t* cache = loc_conf->white_referer_inspection_cache; + + ngx_http_waf_dpf(r, "matching referer(%V)", p_referer); + ret_value = ngx_http_waf_regex_exec_arrray(r, p_referer, regex_array, (u_char*)"WHITE-REFERER", cache); + + if (ret_value == NGX_HTTP_WAF_MATCHED) { + ngx_http_waf_dp(r, "matched"); + ctx->gernal_logged = 1; + ctx->blocked = 0; + ngx_http_waf_append_action(r, action); + } else { + ngx_http_waf_dp(r, "not matched"); + } + + ngx_http_waf_dp_func_end(r); + return ret_value; } ngx_int_t ngx_http_waf_handler_check_black_referer(ngx_http_request_t* r) { - ngx_http_waf_dp_func_start(r); - - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); - - ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; - action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); - - ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_blacklist); - - if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_REFERER | r->method)) { - ngx_http_waf_dp(r, "nothing to do ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - if (r->headers_in.referer == NULL) { - ngx_http_waf_dp(r, "empty referer ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - ngx_str_t* p_referer = &r->headers_in.referer->value; - ngx_array_t* regex_array = loc_conf->black_referer; - lru_cache_t* cache = loc_conf->black_referer_inspection_cache; - - ngx_http_waf_dpf(r, "matching referer(%V)", p_referer); - ret_value = ngx_http_waf_regex_exec_arrray(r, p_referer, regex_array, (u_char*)"BLACK-REFERER", cache); - - if (ret_value == NGX_HTTP_WAF_MATCHED) { - ngx_http_waf_dp(r, "matched"); - ctx->gernal_logged = 1; - ctx->blocked = 1; - ngx_http_waf_append_action_chain(r, action); - } else { - ngx_http_waf_dp(r, "not matched"); - } - - ngx_http_waf_dp_func_end(r); - return ret_value; + ngx_http_waf_dp_func_start(r); + + ngx_http_waf_ctx_t* ctx = NULL; + ngx_http_waf_loc_conf_t* loc_conf = NULL; + ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); + + ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; + action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); + + ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_blacklist); + + if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_REFERER | r->method)) { + ngx_http_waf_dp(r, "nothing to do ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + if (r->headers_in.referer == NULL) { + ngx_http_waf_dp(r, "empty referer ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + ngx_str_t* p_referer = &r->headers_in.referer->value; + ngx_array_t* regex_array = loc_conf->black_referer; + lru_cache_t* cache = loc_conf->black_referer_inspection_cache; + + ngx_http_waf_dpf(r, "matching referer(%V)", p_referer); + ret_value = ngx_http_waf_regex_exec_arrray(r, p_referer, regex_array, (u_char*)"BLACK-REFERER", cache); + + if (ret_value == NGX_HTTP_WAF_MATCHED) { + ngx_http_waf_dp(r, "matched"); + ctx->gernal_logged = 1; + ctx->blocked = 1; + ngx_http_waf_append_action_chain(r, action); + } else { + ngx_http_waf_dp(r, "not matched"); + } + + ngx_http_waf_dp_func_end(r); + return ret_value; } +ngx_int_t ngx_http_waf_handler_check_white_cookie(ngx_http_request_t* r) { + ngx_http_waf_dp_func_start(r); + + ngx_http_waf_ctx_t* ctx = NULL; + ngx_http_waf_loc_conf_t* loc_conf = NULL; + ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); + + ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; + action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); + + ngx_http_waf_set_action_decline(action, ACTION_FLAG_FROM_WHITE_LIST); + + if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_COOKIE | r->method)) { + ngx_http_waf_dp(r, "nothing to do ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + #if (nginx_version >= 1023000) + if (r->headers_in.cookie == NULL) { + ngx_http_waf_dp(r, "empty cookies ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + ngx_table_elt_t* p = r->headers_in.cookie; + + for (p = r->headers_in.cookie; p != NULL; p = p->next) { + size_t len = p->key.len + p->value.len + 1; + u_char* buf = ngx_pcalloc(r->pool, sizeof(u_char) * (len + 1)); + + size_t offset = 0; + ngx_memcpy(buf + offset, p->key.data, sizeof(u_char) * p->key.len); + + offset += sizeof(u_char) * p->key.len; + buf[offset] = '='; + + ++offset; + ngx_memcpy(buf + offset, p->value.data, sizeof(u_char) * p->value.len); + + ngx_str_t cookie; + cookie.len = len; + cookie.data = buf; + + ngx_array_t* regex_array = loc_conf->white_cookie; + lru_cache_t* cache = loc_conf->white_cookie_inspection_cache; + ret_value = ngx_http_waf_regex_exec_arrray(r, &cookie, regex_array, (u_char*)"WHITE-COOKIE", cache); + + if (ret_value == NGX_HTTP_WAF_MATCHED) { + ngx_http_waf_dp(r, "matched"); + ctx->gernal_logged = 1; + ctx->blocked = 0; + ngx_http_waf_append_action(r, action); + break; + + } else { + ngx_http_waf_dp(r, "not matched"); + } + } + #else + if (r->headers_in.cookies.nelts == 0) { + ngx_http_waf_dp(r, "empty cookies ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + ngx_table_elt_t** ppcookie = r->headers_in.cookies.elts; + size_t i; + for (i = 0; i < r->headers_in.cookies.nelts; i++, ppcookie++) { + ngx_str_t* native_cookies = &((**ppcookie).value); + + ngx_http_waf_dpf(r, "matching cookie(%V)", native_cookies); + + ngx_array_t* regex_array = loc_conf->white_cookie; + lru_cache_t* cache = loc_conf->white_cookie_inspection_cache; + ret_value = ngx_http_waf_regex_exec_arrray(r, native_cookies, regex_array, (u_char*)"WHITE-COOKIE", cache); + + if (ret_value == NGX_HTTP_WAF_MATCHED) { + ngx_http_waf_dp(r, "matched"); + ctx->gernal_logged = 1; + ctx->blocked = 0; + ngx_http_waf_append_action(r, action); + break; + } else { + ngx_http_waf_dp(r, "not matched"); + } + } + #endif + + ngx_http_waf_dp_func_end(r); + return ret_value; +} + ngx_int_t ngx_http_waf_handler_check_black_cookie(ngx_http_request_t* r) { - ngx_http_waf_dp_func_start(r); - - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); - - ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; - action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); - - ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_blacklist); - - if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_COOKIE | r->method)) { - ngx_http_waf_dp(r, "nothing to do ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } - -#if (nginx_version >= 1023000) - if (r->headers_in.cookie == NULL) { - ngx_http_waf_dp(r, "empty cookies ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - ngx_table_elt_t* p = r->headers_in.cookie; - - for (p = r->headers_in.cookie; p != NULL; p = p->next) { - size_t len = p->key.len + p->value.len + 1; - u_char* buf = ngx_pcalloc(r->pool, sizeof(u_char) * (len + 1)); - - size_t offset = 0; - ngx_memcpy(buf + offset, p->key.data, sizeof(u_char) * p->key.len); - - offset += sizeof(u_char) * p->key.len; - buf[offset] = '='; - - ++offset; - ngx_memcpy(buf + offset, p->value.data, sizeof(u_char) * p->value.len); - - ngx_str_t cookie; - cookie.len = len; - cookie.data = buf; - - ngx_array_t* regex_array = loc_conf->black_cookie; - lru_cache_t* cache = loc_conf->black_cookie_inspection_cache; - ret_value = ngx_http_waf_regex_exec_arrray(r, &cookie, regex_array, (u_char*)"BLACK-COOKIE", cache); - - if (ret_value == NGX_HTTP_WAF_MATCHED) { - ngx_http_waf_dp(r, "matched"); - ctx->gernal_logged = 1; - ctx->blocked = 1; - ngx_http_waf_append_action_chain(r, action); - - } else { - ngx_http_waf_dp(r, "not matched"); - } - - if (ctx->blocked) { - ngx_http_waf_dp(r, "blocked ... break"); - break; - } - } -#else - if (r->headers_in.cookies.nelts == 0) { - ngx_http_waf_dp(r, "empty cookies ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - ngx_table_elt_t** ppcookie = r->headers_in.cookies.elts; - size_t i; - for (i = 0; i < r->headers_in.cookies.nelts; i++, ppcookie++) { - ngx_str_t* native_cookies = &((**ppcookie).value); - - ngx_http_waf_dpf(r, "matching cookie(%V)", native_cookies); - - ngx_array_t* regex_array = loc_conf->black_cookie; - lru_cache_t* cache = loc_conf->black_cookie_inspection_cache; - ret_value = ngx_http_waf_regex_exec_arrray(r, native_cookies, regex_array, (u_char*)"BLACK-COOKIE", cache); - - if (ret_value == NGX_HTTP_WAF_MATCHED) { - ngx_http_waf_dp(r, "matched"); - ctx->gernal_logged = 1; - ctx->blocked = 1; - ngx_http_waf_append_action_chain(r, action); - - } else { - ngx_http_waf_dp(r, "not matched"); - } - - if (ctx->blocked) { - ngx_http_waf_dp(r, "blocked ... break"); - break; - } - } -#endif - - ngx_http_waf_dp_func_end(r); - return ret_value; + ngx_http_waf_dp_func_start(r); + + ngx_http_waf_ctx_t* ctx = NULL; + ngx_http_waf_loc_conf_t* loc_conf = NULL; + ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); + + ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; + action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); + + ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_blacklist); + + if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_COOKIE | r->method)) { + ngx_http_waf_dp(r, "nothing to do ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + #if (nginx_version >= 1023000) + if (r->headers_in.cookie == NULL) { + ngx_http_waf_dp(r, "empty cookies ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + ngx_table_elt_t* p = r->headers_in.cookie; + + for (p = r->headers_in.cookie; p != NULL; p = p->next) { + size_t len = p->key.len + p->value.len + 1; + u_char* buf = ngx_pcalloc(r->pool, sizeof(u_char) * (len + 1)); + + size_t offset = 0; + ngx_memcpy(buf + offset, p->key.data, sizeof(u_char) * p->key.len); + + offset += sizeof(u_char) * p->key.len; + buf[offset] = '='; + + ++offset; + ngx_memcpy(buf + offset, p->value.data, sizeof(u_char) * p->value.len); + + ngx_str_t cookie; + cookie.len = len; + cookie.data = buf; + + ngx_array_t* regex_array = loc_conf->black_cookie; + lru_cache_t* cache = loc_conf->black_cookie_inspection_cache; + ret_value = ngx_http_waf_regex_exec_arrray(r, &cookie, regex_array, (u_char*)"BLACK-COOKIE", cache); + + if (ret_value == NGX_HTTP_WAF_MATCHED) { + ngx_http_waf_dp(r, "matched"); + ctx->gernal_logged = 1; + ctx->blocked = 1; + ngx_http_waf_append_action_chain(r, action); + + } else { + ngx_http_waf_dp(r, "not matched"); + } + + if (ctx->blocked) { + ngx_http_waf_dp(r, "blocked ... break"); + break; + } + } + #else + if (r->headers_in.cookies.nelts == 0) { + ngx_http_waf_dp(r, "empty cookies ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + ngx_table_elt_t** ppcookie = r->headers_in.cookies.elts; + size_t i; + for (i = 0; i < r->headers_in.cookies.nelts; i++, ppcookie++) { + ngx_str_t* native_cookies = &((**ppcookie).value); + + ngx_http_waf_dpf(r, "matching cookie(%V)", native_cookies); + + ngx_array_t* regex_array = loc_conf->black_cookie; + lru_cache_t* cache = loc_conf->black_cookie_inspection_cache; + ret_value = ngx_http_waf_regex_exec_arrray(r, native_cookies, regex_array, (u_char*)"BLACK-COOKIE", cache); + + if (ret_value == NGX_HTTP_WAF_MATCHED) { + ngx_http_waf_dp(r, "matched"); + ctx->gernal_logged = 1; + ctx->blocked = 1; + ngx_http_waf_append_action_chain(r, action); + + } else { + ngx_http_waf_dp(r, "not matched"); + } + + if (ctx->blocked) { + ngx_http_waf_dp(r, "blocked ... break"); + break; + } + } + #endif + + ngx_http_waf_dp_func_end(r); + return ret_value; } ngx_int_t ngx_http_waf_handler_check_black_post(ngx_http_request_t* r) { - ngx_http_waf_dp_func_start(r); - - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); - - action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); - - ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_blacklist); - - if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_RB)) { - ngx_http_waf_dp(r, "nothing to do ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - if (ctx->has_req_body == NGX_HTTP_WAF_FALSE) { - ngx_http_waf_dp(r, "empty request body ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - ngx_str_t body_str; - body_str.data = ctx->req_body.pos; - body_str.len = ctx->req_body.last - ctx->req_body.pos; - - ngx_http_waf_dpf(r, "matching request body %V", &body_str); - ngx_int_t rc = ngx_http_waf_regex_exec_arrray(r, &body_str, loc_conf->black_post, (u_char*)"BLACK-POST", NULL); - if (rc == NGX_HTTP_WAF_MATCHED) { - ngx_http_waf_dp(r, "matched"); - ctx->gernal_logged = 1; - ctx->blocked = 1; - ngx_http_waf_append_action_chain(r, action); - return NGX_HTTP_WAF_MATCHED; - } else { - ngx_http_waf_dp(r, "not matched"); - ngx_http_waf_dp_func_end(r); - return NGX_HTTP_WAF_NOT_MATCHED; - } + ngx_http_waf_dp_func_start(r); + + ngx_http_waf_ctx_t* ctx = NULL; + ngx_http_waf_loc_conf_t* loc_conf = NULL; + ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); + + action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); + + ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_blacklist); + + if (!ngx_http_waf_check_flag(loc_conf->waf_mode, NGX_HTTP_WAF_MODE_INSPECT_RB)) { + ngx_http_waf_dp(r, "nothing to do ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + if (ctx->has_req_body == NGX_HTTP_WAF_FALSE) { + ngx_http_waf_dp(r, "empty request body ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + ngx_str_t body_str; + body_str.data = ctx->req_body.pos; + body_str.len = ctx->req_body.last - ctx->req_body.pos; + + ngx_http_waf_dpf(r, "matching request body %V", &body_str); + ngx_int_t rc = ngx_http_waf_regex_exec_arrray(r, &body_str, loc_conf->black_post, (u_char*)"BLACK-POST", NULL); + if (rc == NGX_HTTP_WAF_MATCHED) { + ngx_http_waf_dp(r, "matched"); + ctx->gernal_logged = 1; + ctx->blocked = 1; + ngx_http_waf_append_action_chain(r, action); + return NGX_HTTP_WAF_MATCHED; + } else { + ngx_http_waf_dp(r, "not matched"); + ngx_http_waf_dp_func_end(r); + return NGX_HTTP_WAF_NOT_MATCHED; + } } -ngx_int_t ngx_http_waf_regex_exec_arrray(ngx_http_request_t* r, - ngx_str_t* str, - ngx_array_t* array, - const u_char* rule_type, - lru_cache_t* cache) { - ngx_http_waf_dp_func_start(r); - - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); - ngx_int_t cache_hit = NGX_HTTP_WAF_FAIL; - check_result_t result; - result.is_matched = NGX_HTTP_WAF_NOT_MATCHED; - result.detail = NULL; - - if (ngx_http_waf_is_empty_str_value(str) || !ngx_http_waf_is_valid_ptr_value(array)) { - ngx_http_waf_dp(r, "nothing to do ... return"); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - if ( loc_conf->waf_cache == 1 - && loc_conf->waf_cache_capacity != NGX_CONF_UNSET - && cache != NULL) { - ngx_http_waf_dp(r, "getting cache"); - lru_cache_find_result_t tmp = lru_cache_find(cache, str->data, sizeof(u_char) * str->len); - if (tmp.status == NGX_HTTP_WAF_KEY_EXISTS) { - ngx_http_waf_dp(r, "found"); - cache_hit = NGX_HTTP_WAF_SUCCESS; - ngx_memcpy(&result, *(tmp.data), sizeof(check_result_t)); - - } else { - ngx_http_waf_dp(r, "not found"); - } - } - - if (cache_hit != NGX_HTTP_WAF_SUCCESS) { - ngx_http_waf_dpf(r, "matching str(%V)", str); - ngx_regex_elt_t* p = (ngx_regex_elt_t*)(array->elts); - for (size_t i = 0; i < array->nelts; i++, p++) { - ngx_http_waf_dpf(r, "testing %s", p->name); - ngx_int_t rc = ngx_regex_exec(p->regex, str, NULL, 0); - if (rc >= 0) { - ngx_http_waf_dp(r, "matched"); - result.is_matched = NGX_HTTP_WAF_MATCHED; - result.detail = p->name; - break; - } - } - } - - if ( loc_conf->waf_cache == 1 - && loc_conf->waf_cache_capacity != NGX_CONF_UNSET - && cache != NULL) { - ngx_http_waf_dp(r, "adding cache"); - - /* 过期时间为 [5, 10] 分钟 */ - time_t expire = (time_t)randombytes_uniform(60 * 5) + 60 * 5; - lru_cache_add_result_t tmp = lru_cache_add(cache, str->data, str->len * sizeof(u_char), expire); - if (tmp.status == NGX_HTTP_WAF_SUCCESS) { - *(tmp.data) = lru_cache_calloc(cache, sizeof(check_result_t)); - if (*(tmp.data) == NULL) { - ngx_http_waf_dp(r, "no memory"); - - } else { - ngx_memcpy(*(tmp.data), &result, sizeof(check_result_t)); - ngx_http_waf_dp(r, "success"); - } - - } else { - ngx_http_waf_dp(r, "failed"); - } - } - - if (result.is_matched == NGX_HTTP_WAF_MATCHED) { - ngx_http_waf_dp(r, "matched"); - - /* 这里不设置 ctx->gernal_logged 和 ctx->blocked,参数只是凑数的。 */ - ngx_http_waf_set_rule_info(r, (char*)rule_type, (char*)result.detail, 0, 0); - - } else { - ngx_http_waf_dp(r, "not matched"); - } - - ngx_http_waf_dp_func_end(r); - return result.is_matched; +ngx_int_t ngx_http_waf_regex_exec_arrray(ngx_http_request_t* r, + ngx_str_t* str, + ngx_array_t* array, + const u_char* rule_type, + lru_cache_t* cache) { + ngx_http_waf_dp_func_start(r); + + ngx_http_waf_loc_conf_t* loc_conf = NULL; + ngx_http_waf_ctx_t* ctx = NULL; + ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); + ngx_int_t cache_hit = NGX_HTTP_WAF_FAIL; + check_result_t result; + result.is_matched = NGX_HTTP_WAF_NOT_MATCHED; + result.detail = NULL; + + if (ngx_http_waf_is_empty_str_value(str) || !ngx_http_waf_is_valid_ptr_value(array)) { + ngx_http_waf_dp(r, "nothing to do ... return"); + return NGX_HTTP_WAF_NOT_MATCHED; + } + + if ( loc_conf->waf_cache == 1 + && loc_conf->waf_cache_capacity != NGX_CONF_UNSET + && cache != NULL) { + + ngx_http_waf_dp(r, "getting cache"); + lru_cache_find_result_t tmp = lru_cache_find(cache, str->data, sizeof(u_char) * str->len); + if (tmp.status == NGX_HTTP_WAF_KEY_EXISTS) { + ngx_http_waf_dp(r, "found"); + cache_hit = NGX_HTTP_WAF_SUCCESS; + ngx_memcpy(&result, *(tmp.data), sizeof(check_result_t)); + + } else { + ngx_http_waf_dp(r, "not found"); + } + } + + if (cache_hit != NGX_HTTP_WAF_SUCCESS) { + ngx_http_waf_dpf(r, "matching str(%V)", str); + ngx_regex_elt_t* p = (ngx_regex_elt_t*)(array->elts); + for (size_t i = 0; i < array->nelts; i++, p++) { + ngx_http_waf_dpf(r, "testing %s", p->name); + ngx_int_t rc = ngx_regex_exec(p->regex, str, NULL, 0); + if (rc >= 0) { + ngx_http_waf_dp(r, "matched"); + result.is_matched = NGX_HTTP_WAF_MATCHED; + result.detail = p->name; + break; + } + } + } + + if ( loc_conf->waf_cache == 1 + && loc_conf->waf_cache_capacity != NGX_CONF_UNSET + && cache != NULL) { + ngx_http_waf_dp(r, "adding cache"); + + /* 过期时间为 [5, 10] 分钟 */ + time_t expire = (time_t)randombytes_uniform(60 * 5) + 60 * 5; + lru_cache_add_result_t tmp = lru_cache_add(cache, str->data, str->len * sizeof(u_char), expire); + if (tmp.status == NGX_HTTP_WAF_SUCCESS) { + *(tmp.data) = lru_cache_calloc(cache, sizeof(check_result_t)); + if (*(tmp.data) == NULL) { + ngx_http_waf_dp(r, "no memory"); + + } else { + ngx_memcpy(*(tmp.data), &result, sizeof(check_result_t)); + ngx_http_waf_dp(r, "success"); + } + + } else { + ngx_http_waf_dp(r, "failed"); + } + } + + if (result.is_matched == NGX_HTTP_WAF_MATCHED) { + ngx_http_waf_dp(r, "matched"); + + /* 这里不设置 ctx->gernal_logged 和 ctx->blocked,参数只是凑数的。 */ + ngx_http_waf_set_rule_info(r, (char*)rule_type, (char*)result.detail, 0, 0); + + } else { + ngx_http_waf_dp(r, "not matched"); + } + + ngx_http_waf_dp_func_end(r); + return result.is_matched; } diff --git a/src/ngx_http_waf_module_config.c b/src/ngx_http_waf_module_config.c index 27698fb8..1e89e85a 100644 --- a/src/ngx_http_waf_module_config.c +++ b/src/ngx_http_waf_module_config.c @@ -926,7 +926,7 @@ char* ngx_http_waf_priority_conf(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) } - if (utarray_len(array) != 15) { + if (utarray_len(array) != 16) { ngx_conf_log_error(NGX_LOG_EMERG, cf, NGX_EINVAL, "ngx_waf: you must specify the priority of all inspections"); return NGX_CONF_ERROR; @@ -952,6 +952,7 @@ char* ngx_http_waf_priority_conf(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) _parse_priority("UA", ngx_http_waf_handler_check_black_user_agent); _parse_priority("W-REFERER", ngx_http_waf_handler_check_white_referer); _parse_priority("REFERER", ngx_http_waf_handler_check_black_referer); + _parse_priority("W-COOKIE", ngx_http_waf_handler_check_white_cookie); _parse_priority("COOKIE", ngx_http_waf_handler_check_black_cookie); _parse_priority("UNDER-ATTACK", ngx_http_waf_handler_under_attack); _parse_priority("POST", ngx_http_waf_handler_check_black_post); @@ -1188,7 +1189,6 @@ char* ngx_http_waf_action_conf(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) { NGX_HTTP_FORBIDDEN, ACTION_FLAG_FROM_VERIFY_BOT | ACTION_FLAG_UNSET); - for (size_t i = 1; i < cf->args->nelts; i++) { UT_array* array = NULL; if (ngx_http_waf_str_split(p_str + i, '=', 256, &array) != NGX_HTTP_WAF_SUCCESS) { @@ -1705,6 +1705,7 @@ void* ngx_http_waf_create_loc_conf(ngx_conf_t* cf) { conf->black_args = NGX_CONF_UNSET_PTR; conf->black_ua = NGX_CONF_UNSET_PTR; conf->black_referer = NGX_CONF_UNSET_PTR; + conf->white_cookie = NGX_CONF_UNSET_PTR; conf->black_cookie = NGX_CONF_UNSET_PTR; conf->black_post = NGX_CONF_UNSET_PTR; conf->white_url = NGX_CONF_UNSET_PTR; @@ -1718,6 +1719,7 @@ void* ngx_http_waf_create_loc_conf(ngx_conf_t* cf) { conf->black_url_inspection_cache = NGX_CONF_UNSET_PTR; conf->black_args_inspection_cache = NGX_CONF_UNSET_PTR; + conf->white_cookie_inspection_cache = NGX_CONF_UNSET_PTR; conf->black_cookie_inspection_cache = NGX_CONF_UNSET_PTR; conf->black_referer_inspection_cache = NGX_CONF_UNSET_PTR; conf->black_ua_inspection_cache = NGX_CONF_UNSET_PTR; @@ -1735,12 +1737,13 @@ void* ngx_http_waf_create_loc_conf(ngx_conf_t* cf) { conf->check_proc[7] = ngx_http_waf_handler_check_white_url; conf->check_proc[8] = ngx_http_waf_handler_check_black_url; conf->check_proc[9] = ngx_http_waf_handler_check_black_args; - conf->check_proc[10] = ngx_http_waf_handler_check_black_user_agent; - conf->check_proc[11] = ngx_http_waf_handler_check_white_referer; - conf->check_proc[12] = ngx_http_waf_handler_check_black_referer; - conf->check_proc[13] = ngx_http_waf_handler_check_black_cookie; - conf->check_proc[14] = ngx_http_waf_handler_check_black_post; - conf->check_proc[15] = ngx_http_waf_handler_modsecurity; + conf->check_proc[10] = ngx_http_waf_handler_check_white_cookie; + conf->check_proc[11] = ngx_http_waf_handler_check_black_cookie; + conf->check_proc[12] = ngx_http_waf_handler_check_black_user_agent; + conf->check_proc[13] = ngx_http_waf_handler_check_white_referer; + conf->check_proc[14] = ngx_http_waf_handler_check_black_referer; + conf->check_proc[15] = ngx_http_waf_handler_check_black_post; + conf->check_proc[16] = ngx_http_waf_handler_modsecurity; return conf; } @@ -1770,6 +1773,7 @@ char* ngx_http_waf_merge_loc_conf(ngx_conf_t *cf, void *prev, void *conf) { ngx_conf_merge_ptr_value(child->black_args, parent->black_args, NULL); ngx_conf_merge_ptr_value(child->black_ua, parent->black_ua, NULL); ngx_conf_merge_ptr_value(child->black_post, parent->black_post, NULL); + ngx_conf_merge_ptr_value(child->white_cookie, parent->white_cookie, NULL); ngx_conf_merge_ptr_value(child->black_cookie, parent->black_cookie, NULL); ngx_conf_merge_ptr_value(child->black_referer, parent->black_referer, NULL); @@ -1847,6 +1851,7 @@ char* ngx_http_waf_merge_loc_conf(ngx_conf_t *cf, void *prev, void *conf) { ngx_conf_merge_ptr_value(child->black_args_inspection_cache, parent->black_args_inspection_cache, NULL); ngx_conf_merge_ptr_value(child->black_ua_inspection_cache, parent->black_ua_inspection_cache, NULL); ngx_conf_merge_ptr_value(child->black_referer_inspection_cache, parent->black_referer_inspection_cache, NULL); + ngx_conf_merge_ptr_value(child->white_cookie_inspection_cache, parent->white_cookie_inspection_cache, NULL); ngx_conf_merge_ptr_value(child->black_cookie_inspection_cache, parent->black_cookie_inspection_cache, NULL); ngx_conf_merge_ptr_value(child->white_url_inspection_cache, parent->white_url_inspection_cache, NULL); ngx_conf_merge_ptr_value(child->white_referer_inspection_cache, parent->white_referer_inspection_cache, NULL); @@ -2238,6 +2243,7 @@ static ngx_int_t _init_lru_cache(ngx_conf_t* cf, ngx_http_waf_loc_conf_t* conf) conf->black_args_inspection_cache = ngx_pcalloc(cf->pool, sizeof(lru_cache_t)); conf->black_ua_inspection_cache = ngx_pcalloc(cf->pool, sizeof(lru_cache_t)); conf->black_referer_inspection_cache = ngx_pcalloc(cf->pool, sizeof(lru_cache_t)); + conf->white_cookie_inspection_cache = ngx_pcalloc(cf->pool, sizeof(lru_cache_t)); conf->black_cookie_inspection_cache = ngx_pcalloc(cf->pool, sizeof(lru_cache_t)); conf->white_url_inspection_cache = ngx_pcalloc(cf->pool, sizeof(lru_cache_t)); conf->white_referer_inspection_cache = ngx_pcalloc(cf->pool, sizeof(lru_cache_t)); @@ -2269,6 +2275,12 @@ static ngx_int_t _init_lru_cache(ngx_conf_t* cf, ngx_http_waf_loc_conf_t* conf) p = ngx_array_push(main_conf->local_caches); *p = conf->black_referer_inspection_cache; + lru_cache_init(&conf->white_cookie_inspection_cache, + conf->waf_cache_capacity, pool); + + p = ngx_array_push(main_conf->local_caches); + *p = conf->white_cookie_inspection_cache; + lru_cache_init(&conf->black_cookie_inspection_cache, conf->waf_cache_capacity, pool); @@ -2326,6 +2338,7 @@ static ngx_int_t _load_all_rule(ngx_conf_t* cf, ngx_http_waf_loc_conf_t* conf) { ngx_http_waf_check_and_load_conf(cf, full_path, end, NGX_HTTP_WAF_ARGS_FILE, conf->black_args, 0); ngx_http_waf_check_and_load_conf(cf, full_path, end, NGX_HTTP_WAF_UA_FILE, conf->black_ua, 0); ngx_http_waf_check_and_load_conf(cf, full_path, end, NGX_HTTP_WAF_REFERER_FILE, conf->black_referer, 0); + ngx_http_waf_check_and_load_conf(cf, full_path, end, NGX_HTTP_WAF_WHITE_COOKIE_FILE, conf->white_cookie, 0); ngx_http_waf_check_and_load_conf(cf, full_path, end, NGX_HTTP_WAF_COOKIE_FILE, conf->black_cookie, 0); ngx_http_waf_check_and_load_conf(cf, full_path, end, NGX_HTTP_WAF_POST_FILE, conf->black_post, 0); ngx_http_waf_check_and_load_conf(cf, full_path, end, NGX_HTTP_WAF_WHITE_IPV4_FILE, conf->white_ipv4, 1); @@ -2352,6 +2365,7 @@ static ngx_int_t _init_rule_containers(ngx_conf_t* cf, ngx_http_waf_loc_conf_t* conf->black_args = ngx_array_create(cf->pool, 1, sizeof(ngx_regex_elt_t)); conf->black_ua = ngx_array_create(cf->pool, 1, sizeof(ngx_regex_elt_t)); conf->black_referer = ngx_array_create(cf->pool, 1, sizeof(ngx_regex_elt_t)); + conf->white_cookie = ngx_array_create(cf->pool, 1, sizeof(ngx_regex_elt_t)); conf->black_cookie = ngx_array_create(cf->pool, 1, sizeof(ngx_regex_elt_t)); conf->black_post = ngx_array_create(cf->pool, 1, sizeof(ngx_regex_elt_t)); conf->white_url = ngx_array_create(cf->pool, 1, sizeof(ngx_regex_elt_t)); @@ -2367,6 +2381,7 @@ static ngx_int_t _init_rule_containers(ngx_conf_t* cf, ngx_http_waf_loc_conf_t* || conf->black_args == NULL || conf->black_ua == NULL || conf->black_referer == NULL + || conf->white_cookie == NULL || conf->black_cookie == NULL || conf->black_post == NULL || conf->white_url == NULL @@ -2516,4 +2531,4 @@ static void _modsecurity_pcre_free(void* ptr) { #undef _strcaseeq -#undef _strncaseeq \ No newline at end of file +#undef _strncaseeq diff --git a/src/ngx_http_waf_module_core.c b/src/ngx_http_waf_module_core.c index 715b23d7..721004d0 100644 --- a/src/ngx_http_waf_module_core.c +++ b/src/ngx_http_waf_module_core.c @@ -123,30 +123,30 @@ static ngx_command_t ngx_http_waf_commands[] = { static ngx_http_module_t ngx_http_waf_module_ctx = { - ngx_http_waf_preconfiguration, - ngx_http_waf_postconfiguration, - ngx_http_waf_create_main_conf, - NULL, - NULL, - NULL, - ngx_http_waf_create_loc_conf, - ngx_http_waf_merge_loc_conf + ngx_http_waf_preconfiguration, + ngx_http_waf_postconfiguration, + ngx_http_waf_create_main_conf, + NULL, + NULL, + NULL, + ngx_http_waf_create_loc_conf, + ngx_http_waf_merge_loc_conf }; ngx_module_t ngx_http_waf_module = { - NGX_MODULE_V1, - &ngx_http_waf_module_ctx, /* module context */ - ngx_http_waf_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init master */ - NULL, /* init module */ - ngx_http_waf_init_process, /* init process */ - NULL, /* init thread */ - NULL, /* exit thread */ - NULL, /* exit process */ - NULL, /* exit master */ - NGX_MODULE_V1_PADDING + NGX_MODULE_V1, + &ngx_http_waf_module_ctx, /* module context */ + ngx_http_waf_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + ngx_http_waf_init_process, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING }; @@ -556,4 +556,4 @@ static ngx_int_t _gc(ngx_http_request_t* r) { ngx_http_waf_dp_func_end(r); return NGX_HTTP_WAF_SUCCESS; -} \ No newline at end of file +} diff --git a/src/ngx_http_waf_module_var.c b/src/ngx_http_waf_module_var.c index 1eb38b85..6a1b4d26 100644 --- a/src/ngx_http_waf_module_var.c +++ b/src/ngx_http_waf_module_var.c @@ -9,8 +9,23 @@ ngx_http_waf_dp(r, "no ctx ... return"); \ v->not_found = 1; \ return NGX_OK; \ - } +} + + +/** + * @brief 当读取 waf_log 变量时的回调函数,这个变量当启动检查时不为空,反之为空字符串。 +*/ +ngx_int_t _waf_ssl_greased(ngx_http_request_t* r, ngx_http_variable_value_t* v, uintptr_t data); +/** + * @brief 当读取 waf_log 变量时的回调函数,这个变量当启动检查时不为空,反之为空字符串。 +*/ +ngx_int_t _waf_ssl_fingerprint(ngx_http_request_t* r, ngx_http_variable_value_t* v, uintptr_t data); + +/** + * @brief 当读取 waf_log 变量时的回调函数,这个变量当启动检查时不为空,反之为空字符串。 +*/ +ngx_int_t _waf_ssl_fingerprint_hash(ngx_http_request_t* r, ngx_http_variable_value_t* v, uintptr_t data); /** * @brief 当读取 waf_log 变量时的回调函数,这个变量当启动检查时不为空,反之为空字符串。 @@ -72,12 +87,129 @@ ngx_int_t ngx_http_waf_install_add_var(ngx_conf_t* cf) { _install_var("waf_rule_details", _waf_rule_deatils_handler); _install_var("waf_spend", _waf_spend_handler); _install_var("waf_rate", _waf_rate_handler); + _install_var("waf_ssl_greased", _waf_ssl_greased); + _install_var("waf_ssl_ja3", _waf_ssl_fingerprint); + _install_var("waf_ssl_ja3_hash", _waf_ssl_fingerprint_hash); #undef _install_var return NGX_HTTP_WAF_SUCCESS; } +ngx_int_t _waf_ssl_greased(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_waf_dp_func_start(r); + + _init(r, v); + + if (!ctx->checked) { + ngx_http_waf_dp(r, "not checked ... return"); + v->not_found = 1; + return NGX_OK; + } + if (r->connection == NULL) + { + ngx_http_waf_dp(r, "not checked ... return"); + return NGX_OK; + } + + if (r->connection->ssl == NULL) + { + ngx_http_waf_dp(r, "not checked ... return"); + return NGX_OK; + } + + ngx_http_waf_dp(r, "checked ... return"); + v->len = 1; + v->data = (u_char*)(r->connection->ssl->fp_tls_greased ? "1" : "0"); + + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + + ngx_http_waf_dp_func_end(r); + return NGX_OK; +} + +ngx_int_t _waf_ssl_fingerprint(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_waf_dp_func_start(r); + + _init(r, v); + + if (!ctx->checked) { + ngx_http_waf_dp(r, "not checked ... return"); + v->not_found = 1; + return NGX_OK; + } + if (r->connection == NULL) + { + ngx_http_waf_dp(r, "not checked ... return"); + return NGX_OK; + } + + if (r->connection->ssl == NULL) + { + ngx_http_waf_dp(r, "not checked ... return"); + return NGX_OK; + } + + if (r->connection->ssl->fp_ja3_str.data == NULL) { + ngx_http_waf_dp(r, "not checked ... return"); + return NGX_OK; + } + + ngx_http_waf_dp(r, "checked ... return"); + v->data = r->connection->ssl->fp_ja3_str.data; + v->len = r->connection->ssl->fp_ja3_str.len; + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + + ngx_http_waf_dp_func_end(r); + return NGX_OK; +} + +ngx_int_t _waf_ssl_fingerprint_hash(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_waf_dp_func_start(r); + + _init(r, v); + + if (!ctx->checked) { + ngx_http_waf_dp(r, "not checked ... return"); + v->not_found = 1; + return NGX_OK; + } + + if (r->connection == NULL) + { + ngx_http_waf_dp(r, "not checked ... return"); + return NGX_OK; + } + + if (r->connection->ssl == NULL) + { + ngx_http_waf_dp(r, "not checked ... return"); + return NGX_OK; + } + + if (r->connection->ssl->fp_ja3_md5.data == NULL) { + ngx_http_waf_dp(r, "not checked ... return"); + return NGX_OK; + } + + ngx_http_waf_dp(r, "checked ... return"); + v->data = r->connection->ssl->fp_ja3_md5.data; + v->len = r->connection->ssl->fp_ja3_md5.len; + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + + ngx_http_waf_dp_func_end(r); + return NGX_OK; +} + ngx_int_t _waf_log_get_handler(ngx_http_request_t* r, ngx_http_variable_value_t* v, uintptr_t data) { ngx_http_waf_dp_func_start(r); @@ -204,4 +336,4 @@ ngx_int_t _waf_rate_handler(ngx_http_request_t* r, ngx_http_variable_value_t* v, } -#undef _init \ No newline at end of file +#undef _init diff --git a/test/test-nginx/template/bad_config.t b/test/test-nginx/template/bad_config.t index 4ce07ddc..65bd971b 100644 --- a/test/test-nginx/template/bad_config.t +++ b/test/test-nginx/template/bad_config.t @@ -223,7 +223,7 @@ waf_http_status bad; === TEST: Bad directive waf_priority --- config -waf_priority "W-IP IP VERIFY-BOT CC CAPTCHA UNDER-ATTACK W-URL URL ARGS UA W-REFERER REFERER COOKIE POST" +waf_priority "W-IP IP VERIFY-BOT CC CAPTCHA UNDER-ATTACK W-URL URL ARGS UA W-REFERER REFERER W-COOKIE COOKIE POST" --- must_die