顶呱呱的快乐
顶呱呱的快乐
发布于 2026-07-18 / 26 阅读
0
0

Cap-Pow 部署与使用教程:搭建 PoW 人机验证并接入网站

2026-07-18T10-resdk.webp

本文记录如何部署并使用一个基于工作量证明(Proof of Work,PoW)的人机验证服务。与传统的图片点选验证码相比,Cap-Pow 不要求访客识别图片,而是在浏览器中完成少量 SHA-256 计算,再由服务端核验结果。

在线服务:https://cap-pow.wuw.li/

完整示例页面:https://cap-pow.wuw.li/demo.html

如果只想在自己的网站中使用,可以直接跳到“接入现有网站”;如果希望独立运行自己的服务,请继续阅读“自行部署”。

一、工作原理

2026-07-18T10-3ayli.webp
  1. 前端向 /challenge 请求挑战参数和一次性挑战 token。

  2. 浏览器使用 Web Crypto 的 SHA-256 完成少量 PoW 计算。

  3. 前端把计算结果提交到 /redeem,成功后取得验证 token。

  4. 业务后端把验证 token 提交到 /api/validate,确认有效后才继续处理表单。

关键点:不能只在前端显示“验证通过”。最终 token 必须由业务后端调用验证接口核验,否则攻击者可以绕过前端 JavaScript。

二、在线体验

先打开下面的示例页面,点击居中的“验证你是人类”按钮:

打开 Cap-Pow 完整示例页面

验证成功后按钮会变成绿色,并在页面下方显示 token 的前一部分。正式接入时不需要把 token 展示给用户,而是把它写入隐藏表单字段并随业务表单一起提交。

三、接入现有网站

2026-07-18T10-ymcdh.webp

1. 引入 CSS 和 JavaScript

把下面代码放进网页中。CSS 负责原版按钮外观,JavaScript 负责挑战计算与 token 获取。

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

<div class="cap-wrap">
  <div class="captcha">
    <div class="cap-ct" id="cap-ct" role="button" tabindex="0"
         onclick="CapPow.go('cap-ct')">
      <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>
  </div>
</div>

<input type="hidden" name="cap_token" id="cap_token">
<script>
CapPow.onDone = function (token) {
  document.getElementById('cap_token').value = token;
  // 验证完成后再允许提交表单
};
CapPow.onFail = function (message) {
  console.error('Cap-Pow 验证失败:', message);
};
</script>

2. 把 token 随表单提交

上面的 CapPow.onDone 会把 token 写入隐藏字段 cap_token。之后正常提交登录、注册、留言或联系表单即可。

3. 在 PHP 后端验证 token

把下面代码放在业务处理代码之前。只有 success=true 才能继续执行后续逻辑。

<?php
$token = $_POST['cap_token'] ?? '';

$context = stream_context_create([
    'http' => [
        'method'  => 'POST',
        'header'  => "Content-Type: application/json\r\n",
        'content' => json_encode(['token' => $token]),
        'timeout' => 5,
    ],
]);

$response = @file_get_contents(
    'https://cap-pow.wuw.li/api/validate',
    false,
    $context
);
$result = $response ? json_decode($response, true) : null;

if (!$result || empty($result['success'])) {
    http_response_code(400);
    exit('人机验证未通过,请刷新后重试');
}

// 验证通过,继续登录、注册、留言或表单提交等业务逻辑。

验证 token 建议仅使用一次。不要把接口返回成功缓存到 Cookie、LocalStorage 或 CDN 中。

四、自行部署 PHP 服务端

1. 环境要求

  • Linux 服务器

  • Nginx 或 OpenResty

  • PHP 8.0 或更高版本

  • PHP-FPM、PDO SQLite、OpenSSL 扩展

  • HTTPS 域名

2. 下载源码

git clone https://github.com/onexru/cap-pow-php-server.git /var/www/cap-pow
cd /var/www/cap-pow
mkdir -p .data
chown -R www-data:www-data /var/www/cap-pow

SQLite 数据库存放在 .data/cap.db。PHP-FPM 用户必须对 .data 目录拥有写权限,否则挑战和 token 无法持久化。

3. 配置 Nginx / OpenResty

challenge、redeem 和 validate 都是 POST 接口,推荐直接映射到对应 PHP 文件,不要使用可能改变请求方法的跳转。

server {
    listen 443 ssl http2;
    server_name cap.example.com;
    root /var/www/cap-pow;
    index index.php;

    location = /challenge {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root/challenge.php;
    }
    location = /redeem {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root/redeem.php;
    }
    location = /validate {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root/validate.php;
    }
    location = /api/challenge {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root/challenge.php;
    }
    location = /api/redeem {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root/redeem.php;
    }
    location = /api/validate {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root/validate.php;
    }
}

补充证书路径后执行:

nginx -t && systemctl reload nginx

4. 调整验证难度

c 是挑战轮数,d 是哈希前缀难度。难度过高会导致手机 CPU 占用较高、页面长时间显示“验证中”。建议先使用较轻参数,再结合真实设备测试。

// challenge.php 中可按设备性能调整
$challenge = [
    'c' => 8,   // 挑战轮数
    's' => 64,  // 盐长度
    'd' => 3,   // 难度;数值越大越耗算力
];
$expires = 300;
$pow_data = $cap->createChallenge($challenge, $expires);

五、API 说明

接口

方法

用途

/challenge

POST

获取 PoW 挑战

/redeem

POST

提交计算结果并兑换验证 token

/validate

POST

服务端验证 token

/api/challenge

POST

challenge 的兼容路径

/api/redeem

POST

redeem 的兼容路径

/api/validate

POST

推荐给业务后端使用的验证路径

六、常见问题

一直显示“验证中”怎么办?

  • 先查看浏览器控制台以及 /challenge/redeem 的响应。

  • 确认前端 PRNG、SHA-256 计算规则与 PHP 后端完全一致。

  • 降低 cd,避免移动设备长时间满负载计算。

  • 确认 CDN 没有缓存 challenge、redeem、validate 等动态接口。

为什么必须后端验证?

前端代码运行在访问者设备上,任何人都可以修改或绕过。只有你的业务服务器向 /api/validate 提交 token 并得到成功结果,才能证明本次请求通过验证。

跨域接入需要什么?

如果组件页面和 Cap-Pow 服务不在同一个域名,需要在服务端允许前端域名访问 challenge 和 redeem 接口。生产环境可将 Access-Control-Allow-Origin 从通配符改为自己的站点域名。

至此,一个可独立部署、可嵌入现有表单、并能在后端完成最终核验的 Cap-Pow 服务就配置完成了。


评论