- 网络安全
- 应用安全
- 后端
【免费下载链接】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是 Cap 开源 CAPTCHA 项目提供的一个独立服务端库,用于在机器对机器(M2M)场景下直接求解 Cap 的工作量证明质询,而无需经过浏览器验证组件。它零依赖、单文件、体积小巧,求解速度与验证组件相当,但只能在 Bun 运行时下使用。读完本文,你将掌握该库的安装方式、两种质询输入形式(基于种子与基于质询列表)、全部可选参数(workerCount、onProgress、c/s/d)的语义,并从源码层面理解其求解与验证背后的 SHA-256 工作量证明原理。
什么是@cap.js/solver:M2M 场景的定位
在 Cap 的常规流程中,工作量证明质询由浏览器里的验证组件负责求解:服务端签发质询,客户端用 WASM 和 Web Worker 并行计算解,再把解回传兑换令牌(详见 Cap 是如何工作的?)。
@cap.js/solver把"求解"这一步搬到服务端执行,服务于**机器对机器(M2M)**场景——例如你的后端服务需要自己先通过一次 Cap 质询,才能继续调用受 CAPTCHA 保护的下游接口。与浏览器求解不同,它没有 WASM 编译、Web Worker 调度、shadow DOM 等浏览器上下文依赖,因此实现极度精简:零依赖、单文件,但求解吞吐与验证组件一样高效。
需要明确的是:这个包不会绕过任何实际的工作量证明。它按照与浏览器验证组件相同的算法老老实实计算 nonce,所以服务端同样要付出对应的计算成本;同时它不支持 instrumentation 质询(instrumentation 是浏览器环境检测类质询,需要真实浏览器环境才能通过,服务端无法模拟),详见下文"边界与限制"。
安装
该库只在 Bun 生态中分发,使用 Bun 的包管理器安装即可:
bun add @cap.js/solver安装后通过默认导出引入:
import solver from "@cap.js/solver";@cap.js/solver与服务端签发/验证库是解耦的。如果你需要在自己后端签发质询,可配合 Cap 的无状态服务端库capjs-core(文档)或开箱即用的 Cap Standalone 使用。
用法一:基于种子的质询(seeded challenges)
最常用的形式是传入种子令牌(challenge token)与配置对象,让求解器按种子生成并求解一组质询:
import solver from "@cap.js/solver"; console.log( await solver("challenge token", { c: 50, // 质询数量 s: 32, // 盐的长度(十六进制字符数) d: 4, // 难度(目标前缀长度) }), );配置对象中的三个参数与验证组件/服务端库的生成参数一一对应:
c(challenge count):要生成的质询数量。服务端默认签发50个质询,因此通常传50。s(salt size):每个质询的盐长度,单位是十六进制字符数,默认32。盐是工作量证明输入的一部分,由种子确定性派生。d(difficulty):难度,即哈希结果需要匹配的目标前缀长度(十六进制字符数),默认4。d越大,找到有效 nonce 的期望哈希次数越多。
这三个参数与capjs-core中generateChallenge的challengeCount、challengeSize、challengeDifficulty默认值(50、32、4)完全对齐(见 core/src/index.js 的参数校验逻辑)。
用法二:基于质询列表(challenge list)
第二种形式是直接传入质询列表,列表中每个元素是[盐, 目标前缀]二元组。这种形式通常用于:你已经从服务端拿到了具体的质询对,只想针对它们逐一求解:
import solver from "@cap.js/solver"; const challenges = [ ["a5b6fda4aaed97cf61d7dd9259f733b5", "d455"], ["286bcc39249f9ee698314b600c32e40f", "f0ff"], ["501350aa7c46573cb604284554045703", "4971"], ["a55c02f3b9b4cd088a5a7ee3d4941c14", "eab7"], ["5f3362c12e2779f56f4ef75b4494f5e6", "999f"], /* ... */ ]; console.log(await solver(challenges));列表形式下求解器不再自行生成质询,而是对每个[salt, target]对直接暴力搜索有效 nonce,因此不需要(也不接受)c/s/d这三个种子派生参数。
输出示例:
[67302, 64511, 40440, 27959, 71259 /* ... */]输出的每个数字对应一个质询的有效 nonce,顺序与输入质询列表(或种子派生出的质询)一一对应。拿到这些 nonce 后,即可按验证组件同样的格式把它们作为solutions提交给服务端兑换令牌。
第二个参数:通用选项与种子专属选项
第二个参数可选,但任何时候都可以传入,且始终是一个对象。它包含两类选项:
所有质询类型通用
workerCount:指定使用的 worker 数量,默认值为 CPU 核心数。这与浏览器验证组件的并行策略一致——验证组件把质询分发给多个 Web Worker 并行计算(见 widget/src/src/worker.js 中 worker 按workerIndex/workerCount分块递增 nonce 的逻辑)。在服务端,workerCount决定了求解器并行搜索的通道数;调大可降低单次求解延迟,但会占用更多 CPU 资源。onProgress:进度更新回调。当求解器在处理大量质询时,可通过该回调获取当前进度,用于日志记录、进度条展示或任务管理。
仅基于种子的质询专属
c:要生成的解(质询)数量;s:质询大小(盐长度);d:难度。
也就是说,{ c, s, d }只对字符串种子形式的调用有效;传入质询列表时这些键会被忽略。
底层原理:求解器在算什么
要正确使用求解器,有必要理解它计算的对象。Cap 的 SHA-256 工作量证明遵循如下流程(详见 Cap 是如何工作的?):
- 服务端基于种子令牌与质询索引确定性派生每个质询的盐(salt)与目标前缀(target);
- 客户端将盐与递增的nonce拼接,计算 SHA-256 哈希;
- 检查哈希是否以目标前缀开头;若不是,nonce 递增后重试。
在浏览器端,这一循环由 Rust 编写的 WASM 与 Web Worker 并行执行(见 widget/src/src/worker.js 中的solveFallback与 WASMsolve_pow分支);@cap.js/solver在服务端执行的是同样的算法——所以它绝不绕过工作量证明,只是把计算位置从浏览器挪到了 Bun 进程里。
服务端验证侧的对应逻辑可在capjs-core源码中印证(core/src/index.js):
const salt = prngFromHash(saltSeed, size); const target = prngFromHash(targetSeed, difficulty); const hash = sha256Bytes(salt + solutions[i]); if (!powMatchesPrefix(hash, parseHexPrefix(target))) { return fail("invalid_solution"); }验证方会用同样的种子派生方式重建每个质询的盐和目标,再对提交的 nonce 重算一次 SHA-256 并与前缀比对。这也解释了为什么基于列表形式要求[盐, 目标]与种子派生结果完全一致:服务端校验的是"提交的 nonce 是否满足该盐/目标对应的哈希前缀条件",而非 nonce 的来源。
边界与限制
- 仅支持 Bun:库依赖 Bun 运行时特性,不能直接在 Node.js 或浏览器中运行。
- 不支持 instrumentation 质询:instrumentation 质询是需要在真实浏览器沙箱中执行并回报指纹的检测型质询(配置方式见 capjs-core 的 instrumentation 选项 与 Standalone 选项)。服务端求解器无法伪造浏览器环境,因此
@cap.js/solver对此类质询无能为力——如果你面对的密钥/路由开启了 instrumentation,请走正常的浏览器验证组件流程。 - 不绕过 PoW:求解依然要消耗真实算力,难度
d越高,期望哈希次数越多。若要降低服务端求解成本,应与服务端协商更低的难度或更少的质询数量。 - 注意协议:Cap 的默认质询协议是抗 GPU 的 HashWX(Standalone 新建密钥的默认协议)。HashWX 与经典 SHA-256 PoW 的求解接口不同,使用求解器前请确认目标服务签发的质询属于 SHA-256 PoW 格式;对 HashWX 格式质询的求解,验证组件使用独立的 WASM 运行时(
hashwx.wasm),@cap.js/solver的经典[salt, target]接口并不适用。
完整实战示例
综合以上内容,一个典型的 M2M 集成流程如下:
import solver from "@cap.js/solver"; // 从受保护服务获取质询令牌(此处为示意,实际由你的后端路由返回) const token = await fetchChallengeToken(); // 1) 基于种子求解 50 个难度 4 的质询,开满全部 CPU 核心 const solutions = await solver(token, { c: 50, s: 32, d: 4, workerCount: 8, onProgress: (p) => console.log(`progress: ${p}`), }); // 2) 把 nonce 数组作为 solutions 回传兑换 const { success, token: redeemToken } = await fetch("/cap/redeem", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ token, solutions }), }).then((r) => r.json()); if (success) { // 3) 用兑换令牌继续访问受保护的业务接口 }在调度大量求解任务、需要在主流程之外异步处理时,请把求解逻辑放入 worker 池或独立进程,避免阻塞 Bun 的事件循环——这一点与浏览器端把求解卸载到 Web Worker 的思路(widget/src/src/worker.js)是相通的。
- 网络安全
- 应用安全
- 后端
【免费下载链接】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
网络安全应用安全后端在 Bun 服务端用 @cap.js/solver 求解 Cap PoW 挑战:M2M 机器对机器集成指南
在 Bun 服务端用 @cap.js/solver 求解 Cap PoW 挑战:M2M 机器对机器集成指南 本篇指南以 docs/de/guide/solver
网络安全应用安全后端Cap 服务端 M2M 集成指南:用 @cap.js/solver 在 Bun 中离线求解 Proof-of-Work 挑战
Cap 服务端 M2M 集成指南:用 @cap.js/solver 在 Bun 中离线求解 Proof of Work 挑战 @cap.js/solver 是
网络安全应用安全后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考