Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions assets/hCaptcha.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
</style>
<script>
function onSubmit(token) {
let reqBody = "h-captcha-response=" + token;
let httpRequest = new XMLHttpRequest();
httpRequest.open("POST", "/captcha");
httpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
httpRequest.send(reqBody);
httpRequest.setRequestHeader("h-captcha-response", token);
httpRequest.send(null);
httpRequest.onreadystatechange = () => {
if (httpRequest.readyState == 4 && httpRequest.status == 200) {
let text = httpRequest.responseText;
Expand All @@ -43,7 +43,7 @@
<body>
<h1>Please complete the captcha.</h1>
<h1>请完成验证码</h1>
<div class="h-captcha" data-sitekey="********your_site_key********" data-callback="onSubmit"></div>
<div class="h-captcha" data-sitekey="%V" data-callback="onSubmit"></div>
</body>

</html>
2 changes: 1 addition & 1 deletion inc/ngx_http_waf_module_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
extern unsigned char ngx_http_waf_data_html_under_attack[555];


extern unsigned char ngx_http_waf_data_html_template_hCaptcha[1548];
extern unsigned char ngx_http_waf_data_html_template_hCaptcha[1635];


extern unsigned char ngx_http_waf_data_html_template_reCAPTCHAv2_checkbox[1550];
Expand Down
97 changes: 60 additions & 37 deletions src/ngx_http_waf_module_captcha.c
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,44 @@ static ngx_int_t _verify_cookies(ngx_http_request_t* r) {
return NGX_HTTP_WAF_SUCCESS;
}

static char* ngx_waf_get_captcha_response_token(ngx_http_request_t* r, ngx_str_t header_str) {

ngx_int_t need_to_continue = NGX_HTTP_WAF_TRUE;

ngx_list_part_t *part;
ngx_table_elt_t *header;
ngx_uint_t i;
char * response_token = NULL;

part = &r->headers_in.headers.part;
header = part->elts;

for (i = 0; /* void */; i++) {
if (need_to_continue == NGX_HTTP_WAF_FALSE)
break;
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
part = part->next;
header = part->elts;
i = 0;
}
if (ngx_strcmp(header[i].key.data, header_str.data) == 0) {
if (header[i].value.len > 0 ) {
char * buf = ngx_pnalloc (r->pool, header[i].value.len + 1);
if (buf != NULL) {
ngx_memcpy(buf, header[i].value.data, header[i].value.len);
buf[header[i].value.len] = '\0';
response_token = buf;
}
}
need_to_continue = NGX_HTTP_WAF_FALSE;
}
}

return response_token;
}

static ngx_int_t _verify_captcha_dispatcher(ngx_http_request_t* r) {
ngx_http_waf_dp_func_end(r);
Expand Down Expand Up @@ -591,9 +629,9 @@ static ngx_int_t _verify_hCaptcha(ngx_http_request_t* r) {
ngx_http_waf_loc_conf_t* loc_conf = NULL;
ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx);

ngx_str_t response_key = ngx_string("h-captcha-response");
ngx_str_t response_header = ngx_string("h-captcha-response");
ngx_int_t ret = _verfiy_reCAPTCHA_compatible(r,
response_key,
response_header,
loc_conf->waf_captcha_hCaptcha_secret,
loc_conf->waf_captcha_api,
NGX_HTTP_WAF_FALSE,
Expand All @@ -611,9 +649,9 @@ static ngx_int_t _verify_reCAPTCHAv2(ngx_http_request_t* r) {
ngx_http_waf_loc_conf_t* loc_conf = NULL;
ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx);

ngx_str_t response_key = ngx_string("g-recaptcha-response");
ngx_str_t response_header = ngx_string("g-recaptcha-response");
ngx_int_t ret = _verfiy_reCAPTCHA_compatible(r,
response_key,
response_header,
loc_conf->waf_captcha_reCAPTCHAv2_secret,
loc_conf->waf_captcha_api,
NGX_HTTP_WAF_FALSE,
Expand All @@ -631,9 +669,9 @@ static ngx_int_t _verify_reCAPTCHAv3(ngx_http_request_t* r) {
ngx_http_waf_loc_conf_t* loc_conf = NULL;
ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx);

ngx_str_t response_key = ngx_string("g-recaptcha-response");
ngx_str_t response_header = ngx_string("g-recaptcha-response");
ngx_int_t ret = _verfiy_reCAPTCHA_compatible(r,
response_key,
response_header,
loc_conf->waf_captcha_reCAPTCHAv3_secret,
loc_conf->waf_captcha_api,
NGX_HTTP_WAF_TRUE,
Expand All @@ -645,7 +683,7 @@ static ngx_int_t _verify_reCAPTCHAv3(ngx_http_request_t* r) {


static ngx_int_t _verfiy_reCAPTCHA_compatible(ngx_http_request_t* r,
ngx_str_t response_key,
ngx_str_t response_header,
ngx_str_t secret,
ngx_str_t url,
ngx_int_t is_reCAPTCHA_v3,
Expand All @@ -655,36 +693,30 @@ static ngx_int_t _verfiy_reCAPTCHA_compatible(ngx_http_request_t* 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 = NGX_HTTP_WAF_SUCCESS;

ngx_str_t body = { ctx->req_body.last - ctx->req_body.pos, ctx->req_body.pos };
key_value_t* kvs = NULL;
ngx_http_waf_dpf(r, "parsing form %V", &body);
ngx_int_t ret = ngx_http_waf_parse_form_string(&body, &kvs);
if (ret != NGX_HTTP_WAF_SUCCESS) {
goto hash_map_free;
}
ngx_http_waf_dp(r, "success");

ngx_http_waf_dpf(r, "getting %V", &response_key);
key_value_t* captcha_response = NULL;
HASH_FIND(hh, kvs, response_key.data, response_key.len, captcha_response);
if (captcha_response == NULL) {
char * captcha_token = NULL;
captcha_token = ngx_waf_get_captcha_response_token(r, response_header);
if (captcha_token == NULL) {
ngx_http_waf_dp(r, "failed ... releasing resources");
ret = NGX_HTTP_WAF_FAIL;
goto hash_map_free;
goto _verify_recaptcha_compatible_error;
}
ngx_http_waf_dpf(r, "success(%V)", &captcha_response->value);

ngx_str_t captcha_response = ngx_null_string;
captcha_response.data = (u_char*)captcha_token;
captcha_response.len = strlen(captcha_token);

char* json_str = NULL;
ngx_http_waf_dpf(r, "using serect %V", &secret);

ngx_http_waf_dp(r, "gererating request body for verification");
char* in = ngx_pnalloc(r->pool, captcha_response->value.len + secret.len + 64);
char* in = ngx_pnalloc(r->pool, captcha_response.len + secret.len + 64);
if (in == NULL) {
ngx_http_waf_dp(r, "no memory ... releasing resources");
goto hash_map_free;
goto _verify_recaptcha_compatible_error;
}
sprintf(in, "response=%s&secret=%s", (char*)(captcha_response->value.data), (char*)(secret.data));
sprintf(in, "response=%s&secret=%s", (char*)(captcha_response.data), (char*)(secret.data));
ngx_http_waf_dpf(r, "success(%s)", in);

ngx_http_waf_dpf(r, "sending a request to %V", &url);
Expand All @@ -699,7 +731,7 @@ static ngx_int_t _verfiy_reCAPTCHA_compatible(ngx_http_request_t* r,
}

ngx_http_waf_dp(r, "releasing resources");
goto hash_map_free;
goto _verify_recaptcha_compatible_error;
}
ngx_http_waf_dpf(r, "success(%s)", json_str);

Expand All @@ -709,7 +741,7 @@ static ngx_int_t _verfiy_reCAPTCHA_compatible(ngx_http_request_t* r,
if (json_obj == NULL) {
ngx_http_waf_dp(r, "failed ... releasing resources");
ret = NGX_HTTP_WAF_FAIL;
goto hash_map_free;
goto _verify_recaptcha_compatible_error;
}
ngx_http_waf_dp(r, "success");

Expand Down Expand Up @@ -756,16 +788,7 @@ static ngx_int_t _verfiy_reCAPTCHA_compatible(ngx_http_request_t* r,
// json_free:
cJSON_Delete(json_obj);

hash_map_free:
{
key_value_t *temp0 = NULL, *temp1 = NULL;
HASH_ITER(hh, kvs, temp0, temp1) {
HASH_DEL(kvs, temp0);
free(temp0->key.data);
free(temp0->value.data);
free(temp0);
}
}
_verify_recaptcha_compatible_error:

ngx_http_waf_dp_func_end(r);
return ret;
Expand Down
Loading