Proof of Work Verification

轻量、安静的
人机验证

让浏览器完成一小段工作量证明,以此拦截自动化滥用。无需图片识别、无需追踪用户,也不依赖第三方验证码服务。

隐私友好零客户端依赖一次性 Token

完整接入教程

下面以登录表单为例。核心流程是:浏览器获得验证 token,把它随业务表单提交;你的服务端消费 token 后,再处理登录或评论。

引入组件资源

把样式放在页面的 <head> 中,并在 </body> 前引入脚本。脚本会自动向它所在的域名请求验证接口。

HTML
<link rel="stylesheet" href="https://cap-pow.wuw.li/cap-pow.css">
<script src="https://cap-pow.wuw.li/cap-pow.js" defer></script>

在表单中加入验证组件

复制完整结构,不要删改 cap-* 类名。隐藏字段用于把最终 token 和你的业务表单一起提交。

HTML
<form id="login-form" method="post" action="/login">
  <input name="email" type="email" required>
  <input name="password" type="password" required>
  <input id="cap-token" name="cap_token" type="hidden">

  <div class="cap-wrap">
    <div class="captcha">
      <div class="cap-ct" id="cap-ct" role="button" tabindex="0"
           onclick="CapPow.go()" aria-label="点击进行人机验证">
        <div class="cap-cb">
          <div class="cap-check">
            <svg viewBox="0 0 24 24">
              <polyline points="4,12 9,17 20,6"></polyline>
            </svg>
          </div>
          <svg class="cap-ring" viewBox="0 0 32 32">
            <circle class="cap-ring-bg" cx="16" cy="16" r="14"></circle>
            <circle class="cap-ring-fg" cx="16" cy="16" r="14"></circle>
          </svg>
        </div>
        <div class="cap-lw">
          <span class="cap-label active">验证你是人类</span>
        </div>
      </div>
      <a class="cap-credits" href="https://github.com/tiagorangel1/cap">Cap</a>
    </div>
  </div>

  <button type="submit">登录</button>
</form>

接收 token 并控制提交

验证完成后写入隐藏字段。提交表单前再次检查,避免用户尚未完成验证就发起业务请求。

JavaScript
const form = document.querySelector('#login-form');
const tokenInput = document.querySelector('#cap-token');

CapPow.onDone = function (token) {
  tokenInput.value = token;
};

CapPow.onFail = function (message) {
  tokenInput.value = '';
  console.error('Cap-Pow 验证失败:', message);
};

form.addEventListener('submit', function (event) {
  if (!tokenInput.value) {
    event.preventDefault();
    alert('请先完成人机验证');
  }
});
前端检查只改善交互,不能代替服务端验证。攻击者可以绕过页面直接调用你的登录或提交接口。

在业务服务端核验 token

业务后端收到 cap_token 后,向 Cap-Pow 的 /api/validate 发起 POST。只有返回 success: true 才继续业务逻辑。

Node.js / Express
app.post('/login', async (req, res) => {
  const response = await fetch('https://cap-pow.wuw.li/api/validate', {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify({ token: req.body.cap_token })
  });
  const result = await response.json();

  if (!result.success) {
    return res.status(403).json({ error: '人机验证失败' });
  }

  // Token 已验证并消费,现在执行登录逻辑。
  return handleLogin(req, res);
});

处理有效期、重放和失败

Challenge 约 5 分钟有效;验证 token 约 20 分钟有效,而且只能成功核验一次。业务请求失败后不要复用旧 token,应让用户重新验证。

验证接口返回
// 成功
{ "success": true, "message": "Token validated successfully" }

// 已使用、过期或不存在
{ "success": false, "message": "Token not found" }
建议为业务接口本身继续配置速率限制。PoW 能提高批量请求成本,但不替代账号锁定、风控和权限校验。

接口速查

组件通常会自动完成前两个接口;你的业务后端只需要调用验证接口。

POST

/challenge

创建一组 PoW 题目和短期 challenge token。

浏览器调用 · 不缓存
POST

/redeem

提交浏览器计算结果,换取一次性验证 token。

浏览器调用 · 不缓存
POST

/api/validate

消费并核验验证 token,返回是否允许继续业务。

仅业务后端调用 · 不缓存

CDN 回源配置

使用 CDN 绑定域名时,源站 Host 和缓存规则必须明确配置,否则接口可能命中错误缓存或无法回源。

源站参数

源站地址
cap-pow-worker.qiailmy.workers.dev
回源协议
HTTPS
回源端口
443
回源 Host
cap-pow-worker.qiailmy.workers.dev

缓存策略

必须不缓存
/challenge、/redeem、/validate、/api/*
可以缓存
/、/cap-pow.js、/cap-pow.css
切换验收
先关闭全站缓存,验证通过后再缓存静态文件