- 网络安全
- 应用安全
- 后端
【免费下载链接】cap
Free, open-source and self-hosted CAPTCHA alternative to reCAPTCHA. Privacy-first and powered by proof-of-work and instrumentation challenges.
本指南讲解 Cap 开源验证码项目中@cap.js/solver的完整用法:这是一个零依赖、单文件的服务端求解库,专为机器对机器(M2M)流程设计,只能运行在 Bun 上。读完本文,你将掌握如何在服务端从种子(seed)或质询列表直接求解 Cap 的工作量证明(proof-of-work)质询、理解其底层求解算法,以及如何把求解结果提交给 Cap 服务端完成验证与换取通行令牌。
什么是 @cap.js/solver
@cap.js/solver是 Cap 提供的一个独立(standalone)库,用于在服务端求解 Cap 质询(challenge)。与面向浏览器的 widget 相比,它同样快速高效,但实现上"极度简单"——零依赖、单文件,且有一个硬性前提:只能在 Bun 运行时下使用。
需要特别强调两点边界:
- 它不会绕过任何实际的工作量证明。solver 老老实实地完成质询所要求的计算,只是把原本在浏览器 widget 里完成的求解过程搬到了服务端,因此它产出的是真实、可被服务端验证的合法解。
- 它不支持 instrumentation 质询。Cap 有两种质询类型:proof-of-work(工作量证明)和 instrumentation(浏览器行为探针)。instrumentation 质询依赖浏览器环境的运行特征(详见 instrumentation 指南),服务端没有浏览器环境,因此
@cap.js/solver只覆盖 proof-of-work 类质询。
从仓库源码看,Cap 的 proof-of-work 质询共包含三种协议,均可在服务端被求解:
| 协议 | 原理 | 相关实现 |
|---|---|---|
sha256-pow | 寻找 noncen,使SHA-256(salt + n)的十六进制结果以target前缀开头 | core/src/crypto.js、core/test/helpers.js |
hashwx | 基于 WASM 的专用哈希函数,寻找满足hash <= U64_MAX / difficulty的 nonce | core/src/hashwx.js、widget/src/src/worker.js |
rsw | 基于 RSA 的重复平方(repeated squaring),计算y = x^(2^t) mod N | core/src/rsw.js |
安装
solver以 npm 包形式发布,通过 Bun 的包管理器安装:
bun add @cap.js/solver由于库只在 Bun 上运行,请确保你的服务端环境已经安装 Bun。安装完成后即可在 Bun 脚本中直接import使用。
用法一:从种子(seeded)质询求解
服务端最典型的场景是:你已经通过 Cap 的generateChallenge拿到了一个 JWT 形式的质询令牌(token),其中携带了质询数量c、盐长度s与难度d等参数。此时可以把 token 直接交给 solver,并显式传入这些参数:
import solver from "@cap.js/solver"; console.log( await solver("challenge token", { c: 50, // 质询数量 s: 32, // 盐的长度(字节/十六进制字符数) d: 4, // 难度 }), );solver会基于该 token 派生出c组 salt/target,并逐一求出满足条件的 nonce,最终返回一个数组:
[67302, 64511, 40440, 27959, 71259 /* ... */]种子派生逻辑的源码依据:token 的种子派生在仓库中有明确实现。capjs-core通过 FNV-1a 哈希与自实现 PRNG 从 token 派生 salt 与 target——prng(token + i, s)生成第 i 个质询的盐,prng(token + i + "d", d)生成其目标前缀,然后循环递增 nonce,直到SHA-256(salt + nonce)以 target 开头(见 core/src/prng.js 与 core/test/helpers.js)。服务端求解器执行的正是这套算法,因此其结果与服务端验证逻辑完全一致。
参数的默认值与取值范围
solver 的种子参数与服务端generateChallenge的默认值一一对应。仓库中 core/src/index.js 定义:
c(质询数量):默认50,合法范围1 ~ 1000;s(盐长度):默认32,合法范围1 ~ 256;d(难度,即 target 前缀的十六进制位数):默认4,合法范围1 ~ 16。
难度d每增加 1,平均需要多计算约 16 倍哈希,因此在实际 M2M 场景中,应结合自身服务端 CPU 能力与对延迟的容忍度选择合适的难度。
用法二:从质询列表求解
如果服务端不希望维护"种子派生"这层间接关系,也可以直接传入显式的质询列表。列表中每一项是一个二元组:第一项为盐(salt),第二项为难度前缀(target):
import solver from "@cap.js/solver"; const challenges = [ ["a5b6fda4aaed97cf61d7dd9259f733b5", "d455"], ["286bcc39249f9ee698314b600c32e40f", "f0ff"], ["501350aa7c46573cb604284554045703", "4971"], ["a55c02f3b9b4cd088a5a7ee3d4941c14", "eab7"], ["5f3362c12e2779f56f4ef75b4494f5e6", "999f"], /* ... */ ]; console.log(await solver(challenges));输出同样是一个与输入顺序对应的 nonce 数组:
[67302, 64511, 40440, 27959, 71259 /* ... */]这种形式对应 Cap format-2 质询中的sha256-pow协议:服务端生成的每个质询载荷都包含{ salt, target },客户端只需寻找 nonce 使SHA-256(salt + nonce)以target开头(生成与验证逻辑见 core/src/index.js 与 core/src/index.js)。
提示:
hashwx与rsw协议同样属于 proof-of-work。从 core/src/index.js 的实现看,rsw质询的载荷为{ N, x, t }(模数、基值与迭代次数),hashwx质询的载荷为{ c, d, n }(挑战、难度、每哈希 nonce 数)。这些质询同样可以在服务端被求解,只是求解方式与参数形态不同。
第二个参数:选项详解
await solver(challenges, options)的第二个参数是可选的,且始终是一个对象。无论传不传、传多少,workerCount与onProgress对所有质询类型都生效;c/s/d仅对基于种子的质询有意义。
workerCount
- 作用范围:所有质询类型。
- 含义:求解时使用的 worker 数量。
- 默认值:CPU 核心数(即
navigator.hardwareConcurrency)。
worker 划分逻辑在仓库的 widget worker 中可以看到同样模式:每个 worker 从自己的起始区块开始,按步长workerCount推进搜索空间(见 widget/src/src/worker.js)。在服务端,更高的workerCount可以更充分地利用多核 CPU,但也会占用更多内存与 CPU 时间,需要根据机器的核心数与同时处理的请求量做权衡。
onProgress
- 作用范围:所有质询类型。
- 含义:进度更新回调。
进度回调的典型形态可以参考 widget 端的实现:worker 每完成一定量哈希就上报一次进度(widget 中为每约 150ms 上报一次,见 widget/src/src/worker.js)。在 M2M 场景中,onProgress常用于日志记录、超时判断或给调用方返回阶段性状态:
await solver(challenges, { workerCount: 4, onProgress: (progress) => { console.log(`solving... ${progress}`); }, });c/s/d(仅限种子质询)
- 作用范围:仅基于种子的质询。
- 含义:指定要生成的解的数量(
c)、质询(盐)的大小(s)与难度(d)。
当第一个参数是字符串 token 时,solver 需要这三个参数才能确定要生成多少组 salt/target、以多大强度求解;当第一个参数是显式质询列表时,这些信息已经包含在列表中,无需(也不应)再传。
完整的 M2M 集成流程
把上面的知识串起来,一个典型的服务端 M2M 流程如下:
- 获取质询:调用 Cap 实例的
POST /<site-key>/challenge接口(或通过capjs-core的generateChallenge在本地生成),拿到携带质询参数、带有过期时间的 JWT token(生成逻辑见 standalone/src/cap.js)。 - 服务端求解:把 token 或显式质询列表交给
@cap.js/solver,得到 nonce 数组。 - 提交验证:将
{ token, solutions: [nonce, ...] }POST 到 Cap 实例的POST /<site-key>/redeem接口。服务端会校验每个 nonce 对应的哈希是否满足 target 前缀条件、token 是否过期、是否已被兑换(nonce 一次性消费),验证通过后返回一个带 TTL 的兑换令牌(见 standalone/src/cap.js 与 core/src/index.js)。
这套流程让没有浏览器环境的服务端程序(如批量数据抓取、自动化测试、CI 流水线、服务间调用)也能正常通过 Cap 的验证,同时保持与浏览器 widget 相同的求解效率。
边界与注意事项
- 仅限 Bun:
@cap.js/solver依赖 Bun 的运行时能力,不能在 Node.js 或 Deno 下使用。 - 只覆盖 proof-of-work:如果目标站点配置了 instrumentation 质询,solver 无法求解,需配合真实浏览器环境(如 Cap 的前端 widget 或 programmatic 模式,见 programmatic 模式指南)。
- 不绕过工作量证明:求解计算是真实的、可验证的,不要指望通过它"跳过"验证——服务端会逐一校验解的正确性。
- 注意默认参数:种子模式下
c=50, s=32, d=4是常见默认组合,难度越高单次求解耗 CPU 越多,请为服务端预留足够的计算资源(仓库中的 core/test/benchmark.js 展示了不同参数组合下generateChallenge/validateChallenge的基准测试方式,可用于评估容量)。
延伸阅读
- Cap 核心库说明:
capjs-core的质询生成与验证 API。 - hashwx 协议指南:hashwx 质询的难度、nonce 与验证细节。
- instrumentation 指南:solver 不支持的另一种质询类型。
- Standalone 部署指南:如何自托管 Cap 实例并提供
/challenge与/redeem接口。 - 编程式集成指南:在客户端 JS 中通过
new Cap()编程式求解(适用于浏览器环境)。
- 网络安全
- 应用安全
- 后端
【免费下载链接】cap
Free, open-source and self-hosted CAPTCHA alternative to reCAPTCHA. Privacy-first and powered by proof-of-work and instrumentation challenges.
相关推荐
使用 @cap.js/solver 在 Bun 服务端求解 Cap 的 Proof-of-Work Challenge(M2M 场景指南)
使用 @cap.js/solver 在 Bun 服务端求解 Cap 的 Proof of Work Challenge(M2M 场景指南) @cap.js/so
网络安全应用安全后端Cap 服务端 M2M 集成指南:用 @cap.js/solver 在 Bun 中离线求解 Proof-of-Work 挑战
Cap 服务端 M2M 集成指南:用 @cap.js/solver 在 Bun 中离线求解 Proof of Work 挑战 @cap.js/solver 是
网络安全应用安全后端在 Bun 服务端用 @cap.js/solver 求解 Cap PoW 挑战:M2M 机器对机器集成指南
在 Bun 服务端用 @cap.js/solver 求解 Cap PoW 挑战:M2M 机器对机器集成指南 本篇指南以 docs/de/guide/solver
网络安全应用安全后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考