Files
SproutGate/docs/cloudflare-turnstile.md
2026-05-13 12:19:36 +08:00

8.8 KiB
Raw Blame History

Cloudflare Turnstile 网站接入指南

本文说明如何在任意网站中集成 Cloudflare Turnstile 人机验证:从控制台拿密钥、前端展示控件、把一次性 token 交给后端、由服务端向 Cloudflare 校验。内容适用于自建站点与 API不限定具体技术栈文末可对照本仓库中的实现。


1. 概念与流程

说明
Site Key 公钥,可出现在前端代码或 HTML 中。
Secret Key 私钥,能用于你的服务端调用校验接口。
Tokenresponse 用户通过验证后Turnstile 在浏览器中生成的一串临时字符串,需在你自己的业务请求里随表单/JSON 提交到你的后端
二次校验 前端 token 不能单独作为“已通过人机验证”的依据;必须由服务器使用 Secret Key 调用 Cloudflare 的 siteverify 接口确认。

典型流程:

  1. 页面加载 Cloudflare 提供的 JS在指定 DOM 中渲染小组件。
  2. 用户通过挑战后,前端拿到 token,写入状态或随登录/注册请求提交。
  3. 你的后端在执行业务逻辑之前用 Secret Key + token(及可选的客户端 IP请求 siteverifysuccess: true 才继续。
  4. 每个 token 仅应用一次、且有时效;提交失败后应重置控件以获取新 token见第 3 节)。

2. 在 Cloudflare 控制台创建站点

  1. 登录 Cloudflare Dashboard,进入 Turnstile
  2. 选择 Add widget / 添加站点。
  3. 填写网站域名、选择 Managed(或按需选择可见性/交互方式)。
  4. 创建后得到 Site KeySecret Key;为生产环境可单独为生产域名建 widget勿把 Secret Key 写进仓库或静态资源。

本地开发:在 Turnstile 站点里把 localhost 及测试域名加入允许的主机名(与 Cloudflare 当前 UI 中「主机名」/域名列表一致),否则可能无法加载或校验失败。


3. 前端:加载脚本与渲染控件

3.1 官方脚本

推荐按文档使用官方脚本,例如显式渲染render=explicit)便于在单页应用里把控件挂在指定容器上:

  • 脚本地址:
    https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit

在页面中插入一次即可(注意避免重复注入同一脚本多份,除非你有意为之)。

<script
  src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"
  defer
></script>

全局会暴露 window.turnstile,主要方法包括:

  • turnstile.render(container, options):在 containerDOM 元素或选择器)内渲染,返回 widgetId
  • turnstile.reset(widgetId):同一会话内换发新 token失败重试、重复提交时很有用
  • turnstile.remove(widgetId):销毁实例。

3.2 常用 render 参数

参数 含义
sitekey 必填,即 Site Key。
callback 验证通过时回调,参数为 token 字符串。
expired-callback token 过期时。
error-callback 发生错误时。
theme 可选 light / dark / auto 等。

建议在 expired-callbackerror-callback 里把本地产出的 token 清空,避免用失效 token 提交。

3.3 把 token 交给你的后端

验证通过后,在 callback 中保存 token(如 React 的 state、Vue 的 ref。用户点击「登录/提交」时,将 同一请求 中的其它字段与 turnstileToken(或你命名的字段名)一起发给你自己的 API。字段名仅前后端一致即可例如 JSON

{
  "username": "user",
  "password": "…",
  "turnstileToken": "0.xxx…"
}

注意

  • 未启用 Turnstile 的页面或测试环境,前后端要约定好是否“可不传 token”避免生产误关校验。
  • 提交后若失败,应调用 reset 并清空本地 token避免复用。

3.4 与 Content Security Policy (CSP) 的兼容

若站点启用了严格 CSP需允许 Cloudflare 相关源,例如(按实际策略合并):

  • script-srchttps://challenges.cloudflare.com
  • frame-srcchild-src:同上(部分实现会以 iframe 呈现挑战)
  • 有时还需 https://challenges.cloudflare.com/cdn-cgi/... 等,以浏览器控制台与官方文档为准。

4. 后端siteverify 校验

执行业务逻辑之前用服务器端向 Cloudflare 验证 token。不应信任客户端声称的“已验证”。

4.1 端点

POST https://challenges.cloudflare.com/turnstile/v0/siteverify

使用 application/x-www-form-urlencoded 或等价的表单编码提交。

4.2 参数

参数 必填 说明
secret Secret Key。
response 前端传来的 token。
remoteip 发起请求的用户 IP可与 Cloudflare 侧风控一致,建议有则传。

4.3 响应

JSON 中至少包含 success(布尔值)。successtrue 才应继续登录、注册、发帖等业务。

失败时 JSON 中常带有 error-codes 数组,便于排障,例如 invalid-input-responsetimeout-or-duplicate 等(以官方说明为准)。

实践建议

  • 为 HTTP 客户端设置合理超时(如 815 秒),失败时对用户显示通用错误,不要在错误信息中泄露 Secret Key 或内部堆栈。
  • siteverify 应仅在服务端调用;不要从浏览器直接带 Secret 请求。

4.4 伪代码示例

if secret_key is empty: return 500  # 未配置
if user_token is empty: return 400  # 请完成人机验证
POST form: secret, response, (optional) remoteip
if JSON.success != true: return 400  # 验证失败
# 再执行登录/注册等逻辑

语言无关Go 可用 http.PostFormNode 可用 fetch + URLSearchParamsPython 可用 httpx/requestsdata= 等。


5. 安全与产品注意点

  • Site Key 可公开Secret Key 绝不可进前端、公开仓库、日志。 使用环境变量或密钥管理。
  • 每次敏感操作若需要防护,可要求新的 token而不是长缓存同一条 token。
  • 速率限制、账户锁定、异常 IP 检测等组合,而不是只依赖 Turnstile。
  • 若使用反向代理remoteip 应取真实客户端 IP与 Turnstile 可见一致),与信任代理头配置统一。
  • 多环境dev/staging/prod使用不同 widget 与密钥,避免误用。

6. 排障简表

现象 可能原因
前端不显示控件 域名未在 Turnstile 站点中、脚本被 CSP/广告拦截、脚本未加载完就 render
总是 error-callback Site Key 错误、域名校验失败、网络问题
siteverify 失败 token 已用过/过期、Secret Key 错误、时间偏差过大、请求不是 POST 表单
生产正常、本地失败 未把 localhost 加入允许主机名、混用不同环境的 Key

更完整的错误码与行为以 Cloudflare 官方文档为准:
https://developers.cloudflare.com/turnstile/


7. 与本项目SproutGate的对应关系参考

本仓库中可作为对照的实现位置(不保证与上文逐字相同,以代码为准):

  • 前端组件:sproutgate-frontend/src/components/oauth/TurnstileWidget.jsx(显式 render、token 回调、reset)。
  • 前端在登录/注册中附带 turnstileTokenUserPortal.jsxUserPortalAuthSection.jsx
  • 后端校验:sproutgate-backend/internal/handlers/turnstile.goverifyTurnstileTokenturnstileVerifyURL
  • 管理端配置 Site/Secret 与开关:/api/admin/turnstile、存储层 TurnstileConfig

第三方站点只需遵守本文第 15 节的通用步骤即可;具体路由与配置项以各自系统为准。