[GH-ISSUE #153] 尝试使用 Turnstile 作为验证码,但是目前用不了 #110

Open
opened 2026-03-04 12:18:59 +03:00 by kerem · 0 comments
Owner

Originally created by @benzBrake on GitHub (Jan 16, 2026).
Original GitHub issue: https://github.com/ADD-SP/ngx_waf/issues/153

这是vhost配置文件

#WAF ZONE--START
waf_zone name=rust size=20m;
#WAF_ZONE--END
server
{
    listen 80;
    listen 443 ssl;
    http2 on;
    server_name rust.localhost;
    index index.php index.html index.htm default.php default.htm default.html;
    root /www/wwwroot/rust.localhost/rust;
    #WAF--START
    waf on;
    waf_rule_path /www/server/nginx/src/ngx_waf/assets/rules/;
    waf_mode DYNAMIC;
    waf_cache on capacity=100;
    waf_cc_deny on rate=10r/m zone=rust:cc duration=10m;
    waf_captcha off prov=reCAPTCHAv3 file=/www/wwwroot/captcha-v3-turnstile.html sitekey=0xYyyyyyyyyyyy secret=0xUuuuuuuuuuuuuuuuuuuu api=https://challenges.cloudflare.com/turnstile/v0/siteverify;
    waf_action cc_deny=CAPTCHA zone=rust:action;
    #WAF--END
   
    #CERT-APPLY-CHECK--START
    # 用于SSL证书申请时的文件验证相关配置 -- 请勿删除
    include /www/server/panel/vhost/nginx/well-known/rust.localhost.conf;
    #CERT-APPLY-CHECK--END
    include /www/server/panel/vhost/nginx/extension/rust.localhost/*.conf;
   
    #SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则
    #error_page 404/404.html;
    #HTTP_TO_HTTPS_START
    set $isRedcert 1;
    if ($server_port != 443) {
        set $isRedcert 2;
    }
    if ( $uri ~ /\.well-known/ ) {
        set $isRedcert 1;
    }
    if ($isRedcert != 1) {
        rewrite ^(/.*)$ https://$host$1 permanent;
    }
    #HTTP_TO_HTTPS_END
    ssl_certificate /www/server/panel/vhost/cert/rust.localhost/fullchain.pem;
    ssl_certificate_key /www/server/panel/vhost/cert/rust.localhost/privkey.pem;
    ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_tickets on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    add_header Strict-Transport-Security "max-age=31536000";
    error_page 497 https://$host$request_uri;
    #SSL-END
    #ERROR-PAGE-START 错误页配置,可以注释、删除或修改
    error_page 404 /404.html;
    #error_page 502 /502.html;
    #ERROR-PAGE-END

    location = /captcha {

    }
    #PHP-INFO-START PHP引用配置,可以注释或修改
    include enable-php-00.conf;
    #PHP-INFO-END
    #REWRITE-START URL重写规则引用,修改后将导致面板设置的伪静态规则失效
    include /www/server/panel/vhost/rewrite/rust.localhost.conf;
    #REWRITE-END
    #禁止访问的文件或目录
    location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md)
    {
        return 404;
    }
    #一键申请SSL证书验证目录相关设置
    location ~ \.well-known{
        allow all;
    }
    #禁止在证书验证目录放入敏感文件
    if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {
        return 403;
    }
    
    # 2. 如果路径中包含 "." 且不是 .html 结尾 -> 当作静态资源处理
    location ~ \.(?!html$)[^/]*$ {
        # 匹配任何包含 . 但不是以 .html 结尾的路径段(如 app.js, style.css, image.png)
        try_files $uri @redirect_to_index;
        expires 1y;
    }
    
    # 3. 处理带尾部斜杠的页面路径: /guide/why -> /guide/why.html
    location ~ ^/(.+)/$ {
        try_files /$1.html /$1/index.html @redirect_to_index;
    }
    
    location ~ \.html$ {
        try_files $uri @redirect_to_index;
    }
    
    # 4. 主路由处理 - 修改 try_files 规则
    location / {
        # 优先尝试作为文件或目录访问
        # 如果是 SPA 路由,回退到 index.html
        try_files $uri $uri/ /index.html;
    }
    
    location = / {
        try_files /index.html =404;
    }
    
    # 5. 原有的 @redirect_to_index 位置
    location @redirect_to_index {
        # 这里只处理找不到的文件,跳转到 SPA 首页
        rewrite ^.*$ /index.html last;
    }
    
    access_log /www/wwwlogs/rust.localhost.log;
    error_log /www/wwwlogs/rust.localhost.error.log;
}

然后这是/www/wwwroot/captcha-v3-turnstile.html

<!DOCTYPE html>
<html lang="en">
<html>

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Please complete the captcha</title>
  <script src="https://challenges.cloudflare.com/turnstile/v0/api.js?compat=recaptcha" async defer></script>
  <style type="text/css">
    div {
      text-align: center;
    }
  </style>
  <script>
    function onSubmit(token) {
      let reqBody = "g-recaptcha-response=" + token;
      let httpRequest = new XMLHttpRequest();
      httpRequest.open("POST", "/captcha");
      httpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      httpRequest.send(reqBody);
      httpRequest.onreadystatechange = () => {
        if (httpRequest.readyState == 4 && httpRequest.status == 200) {
          let text = httpRequest.responseText;
          switch (text) {
            case "good":
              window.location.reload();
              break;
            case "bad":
              alert("Bad CAPTCHA, please refresh the page and try again.\n"
                  + "您未能通过人机验证,请刷新页面后重试。");
              break;
            default:
              alert("Unexpected error occurred, please refresh the page and try again.\n"
                  + "发生了意料之外的错误,请刷新页面后重试。");
          }
        }
      }
    }
  </script>
</head>

<body>
  <h1>Please complete the captcha.</h1>
  <h1>请完成验证码</h1>
  <div>
    <button class="g-recaptcha" data-sitekey="0xYyyyyyyyyyyy"
    data-callback='onSubmit' style="font-size:25px" data-action='submit'>CLICK ME (点击此处)</button>
  </div>
</body>

</html>

vhost的错误日志

2026/01/16 23:50:44 [alert] 2066138#0: *272 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "POST /captcha HTTP/2.0", host: "rust.localhost", referrer: "https://rust.localhost/"
2026/01/16 23:53:16 [alert] 2067644#0: *292 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET / HTTP/2.0", host: "rust.localhost"
2026/01/16 23:53:17 [alert] 2067644#0: *292 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET /favicon.ico HTTP/2.0", host: "rust.localhost", referrer: "https://rust.localhost/"
2026/01/16 23:54:13 [alert] 2077783#0: *304 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET /captcha HTTP/1.1", host: "rust.localhost"
2026/01/16 23:54:25 [alert] 2077783#0: *305 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET / HTTP/2.0", host: "rust.localhost"
2026/01/16 23:54:27 [alert] 2077783#0: *305 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET /favicon.ico HTTP/2.0", host: "rust.localhost", referrer: "https://rust.localhost/"
2026/01/17 00:01:16 [alert] 2071516#0: *316 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET / HTTP/2.0", host: "rust.localhost"
2026/01/17 00:01:17 [alert] 2071516#0: *316 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET /favicon.ico HTTP/2.0", host: "rust.localhost", referrer: "https://rust.localhost/"
2026/01/17 00:03:38 [alert] 2072668#0: *323 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET / HTTP/2.0", host: "rust.localhost"
2026/01/17 00:03:39 [alert] 2072668#0: *323 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET /favicon.ico HTTP/2.0", host: "rust.localhost", referrer: "https://rust.localhost/"
2026/01/17 00:05:29 [alert] 2073464#0: *329 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET / HTTP/2.0", host: "rust.localhost"
2026/01/17 00:05:30 [alert] 2073464#0: *329 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET /favicon.ico HTTP/2.0", host: "rust.localhost", referrer: "https://rust.localhost/"
2026/01/17 00:09:43 [alert] 2073627#0: *337 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET / HTTP/2.0", host: "rust.localhost"
2026/01/17 00:09:44 [alert] 2073627#0: *337 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET /favicon.ico HTTP/2.0", host: "rust.localhost", referrer: "https://rust.localhost/"

然后验证码页面一直卡着

Image

devtools 里看 /captcha 没有返回数据

Image
Originally created by @benzBrake on GitHub (Jan 16, 2026). Original GitHub issue: https://github.com/ADD-SP/ngx_waf/issues/153 这是vhost配置文件 ``` #WAF ZONE--START waf_zone name=rust size=20m; #WAF_ZONE--END server { listen 80; listen 443 ssl; http2 on; server_name rust.localhost; index index.php index.html index.htm default.php default.htm default.html; root /www/wwwroot/rust.localhost/rust; #WAF--START waf on; waf_rule_path /www/server/nginx/src/ngx_waf/assets/rules/; waf_mode DYNAMIC; waf_cache on capacity=100; waf_cc_deny on rate=10r/m zone=rust:cc duration=10m; waf_captcha off prov=reCAPTCHAv3 file=/www/wwwroot/captcha-v3-turnstile.html sitekey=0xYyyyyyyyyyyy secret=0xUuuuuuuuuuuuuuuuuuuu api=https://challenges.cloudflare.com/turnstile/v0/siteverify; waf_action cc_deny=CAPTCHA zone=rust:action; #WAF--END #CERT-APPLY-CHECK--START # 用于SSL证书申请时的文件验证相关配置 -- 请勿删除 include /www/server/panel/vhost/nginx/well-known/rust.localhost.conf; #CERT-APPLY-CHECK--END include /www/server/panel/vhost/nginx/extension/rust.localhost/*.conf; #SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则 #error_page 404/404.html; #HTTP_TO_HTTPS_START set $isRedcert 1; if ($server_port != 443) { set $isRedcert 2; } if ( $uri ~ /\.well-known/ ) { set $isRedcert 1; } if ($isRedcert != 1) { rewrite ^(/.*)$ https://$host$1 permanent; } #HTTP_TO_HTTPS_END ssl_certificate /www/server/panel/vhost/cert/rust.localhost/fullchain.pem; ssl_certificate_key /www/server/panel/vhost/cert/rust.localhost/privkey.pem; ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; ssl_prefer_server_ciphers on; ssl_session_tickets on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; add_header Strict-Transport-Security "max-age=31536000"; error_page 497 https://$host$request_uri; #SSL-END #ERROR-PAGE-START 错误页配置,可以注释、删除或修改 error_page 404 /404.html; #error_page 502 /502.html; #ERROR-PAGE-END location = /captcha { } #PHP-INFO-START PHP引用配置,可以注释或修改 include enable-php-00.conf; #PHP-INFO-END #REWRITE-START URL重写规则引用,修改后将导致面板设置的伪静态规则失效 include /www/server/panel/vhost/rewrite/rust.localhost.conf; #REWRITE-END #禁止访问的文件或目录 location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md) { return 404; } #一键申请SSL证书验证目录相关设置 location ~ \.well-known{ allow all; } #禁止在证书验证目录放入敏感文件 if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) { return 403; } # 2. 如果路径中包含 "." 且不是 .html 结尾 -> 当作静态资源处理 location ~ \.(?!html$)[^/]*$ { # 匹配任何包含 . 但不是以 .html 结尾的路径段(如 app.js, style.css, image.png) try_files $uri @redirect_to_index; expires 1y; } # 3. 处理带尾部斜杠的页面路径: /guide/why -> /guide/why.html location ~ ^/(.+)/$ { try_files /$1.html /$1/index.html @redirect_to_index; } location ~ \.html$ { try_files $uri @redirect_to_index; } # 4. 主路由处理 - 修改 try_files 规则 location / { # 优先尝试作为文件或目录访问 # 如果是 SPA 路由,回退到 index.html try_files $uri $uri/ /index.html; } location = / { try_files /index.html =404; } # 5. 原有的 @redirect_to_index 位置 location @redirect_to_index { # 这里只处理找不到的文件,跳转到 SPA 首页 rewrite ^.*$ /index.html last; } access_log /www/wwwlogs/rust.localhost.log; error_log /www/wwwlogs/rust.localhost.error.log; } ``` 然后这是`/www/wwwroot/captcha-v3-turnstile.html` ``` <!DOCTYPE html> <html lang="en"> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Please complete the captcha</title> <script src="https://challenges.cloudflare.com/turnstile/v0/api.js?compat=recaptcha" async defer></script> <style type="text/css"> div { text-align: center; } </style> <script> function onSubmit(token) { let reqBody = "g-recaptcha-response=" + token; let httpRequest = new XMLHttpRequest(); httpRequest.open("POST", "/captcha"); httpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); httpRequest.send(reqBody); httpRequest.onreadystatechange = () => { if (httpRequest.readyState == 4 && httpRequest.status == 200) { let text = httpRequest.responseText; switch (text) { case "good": window.location.reload(); break; case "bad": alert("Bad CAPTCHA, please refresh the page and try again.\n" + "您未能通过人机验证,请刷新页面后重试。"); break; default: alert("Unexpected error occurred, please refresh the page and try again.\n" + "发生了意料之外的错误,请刷新页面后重试。"); } } } } </script> </head> <body> <h1>Please complete the captcha.</h1> <h1>请完成验证码</h1> <div> <button class="g-recaptcha" data-sitekey="0xYyyyyyyyyyyy" data-callback='onSubmit' style="font-size:25px" data-action='submit'>CLICK ME (点击此处)</button> </div> </body> </html> ``` vhost的错误日志 ``` 2026/01/16 23:50:44 [alert] 2066138#0: *272 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "POST /captcha HTTP/2.0", host: "rust.localhost", referrer: "https://rust.localhost/" 2026/01/16 23:53:16 [alert] 2067644#0: *292 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET / HTTP/2.0", host: "rust.localhost" 2026/01/16 23:53:17 [alert] 2067644#0: *292 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET /favicon.ico HTTP/2.0", host: "rust.localhost", referrer: "https://rust.localhost/" 2026/01/16 23:54:13 [alert] 2077783#0: *304 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET /captcha HTTP/1.1", host: "rust.localhost" 2026/01/16 23:54:25 [alert] 2077783#0: *305 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET / HTTP/2.0", host: "rust.localhost" 2026/01/16 23:54:27 [alert] 2077783#0: *305 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET /favicon.ico HTTP/2.0", host: "rust.localhost", referrer: "https://rust.localhost/" 2026/01/17 00:01:16 [alert] 2071516#0: *316 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET / HTTP/2.0", host: "rust.localhost" 2026/01/17 00:01:17 [alert] 2071516#0: *316 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET /favicon.ico HTTP/2.0", host: "rust.localhost", referrer: "https://rust.localhost/" 2026/01/17 00:03:38 [alert] 2072668#0: *323 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET / HTTP/2.0", host: "rust.localhost" 2026/01/17 00:03:39 [alert] 2072668#0: *323 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET /favicon.ico HTTP/2.0", host: "rust.localhost", referrer: "https://rust.localhost/" 2026/01/17 00:05:29 [alert] 2073464#0: *329 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET / HTTP/2.0", host: "rust.localhost" 2026/01/17 00:05:30 [alert] 2073464#0: *329 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET /favicon.ico HTTP/2.0", host: "rust.localhost", referrer: "https://rust.localhost/" 2026/01/17 00:09:43 [alert] 2073627#0: *337 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET / HTTP/2.0", host: "rust.localhost" 2026/01/17 00:09:44 [alert] 2073627#0: *337 ngx_waf: [CAPTCHA][CHALLENGE] while logging request, client: [REDACTED_IP], server: rust.localhost, request: "GET /favicon.ico HTTP/2.0", host: "rust.localhost", referrer: "https://rust.localhost/" ``` 然后验证码页面一直卡着 <img width="906" height="692" alt="Image" src="https://github.com/user-attachments/assets/06c90882-59e9-4d88-b147-9432b25fa38f" /> devtools 里看 /captcha 没有返回数据 <img width="752" height="745" alt="Image" src="https://github.com/user-attachments/assets/3c9ac5ea-46bd-4940-a60f-08cb35b00899" />
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/ngx_waf#110
No description provided.