news 2026/9/28 2:49:53

Cap 有效性剖析:工作量证明 + Instrumentation 如何让自动化滥用变得昂贵

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Cap 有效性剖析:工作量证明 + Instrumentation 如何让自动化滥用变得昂贵
  • 网络安全
  • 应用安全
  • 后端

【免费下载链接】cap

Free, open-source and self-hosted CAPTCHA alternative to reCAPTCHA. Privacy-first and powered by proof-of-work and instrumentation challenges.

项目地址:https://gitcode.com/gh_mirrors/cap13/cap
点击查看免费下载

Cap 是一个免费、开源、可自托管的 CAPTCHA 替代方案。本文围绕其官方文档 docs/zh/guide/effectiveness.md 的核心论断展开:Cap 不靠猜测"谁是人类"来拦截机器人,而是通过**工作量证明(Proof of Work, PoW)与Instrumentation(浏览器环境检测)**两套独立机制,把自动化滥用的成本抬到经济上无利可图,同时让真实用户的体验保持快速且几乎无感。读完本文,你将理解 PoW 的攻防经济学、为什么 Cap 默认采用抗 GPU 的 HashWX 协议、这两层验证在源码中如何实现,以及如何在 cap-core 与 Standalone 中实际配置难度与协议。

隐私与安全:默认不追踪、默认防重放

Cap 在隐私层面的设计是"少即是多",这一点直接写进了有效性文档:

  • 默认不使用 Cookie,也没有任何形式的遥测:质询的签发与验证不依赖任何客户端状态存储;
  • 完全自托管:质询生成、验证、令牌签发全部发生在你自己的服务器上,没有任何数据被收集或存储到中心化服务器;
  • 默认内置重放防护和基于签名的质询令牌:质询令牌是使用 HMAC 主密钥签名的 JWT,客户端无法伪造或篡改参数(难度、盐、过期时间),详见 core/src/index.js 中generateChallenge的jwtSign调用。

从源码结构看,"无状态"是这套设计的根基:capjs-core库本身不持有任何会话,generateChallenge(secret, opts)每次调用都用crypto.randomBytes生成随机盐并把质询配置签进 JWT,validateChallenge(secret, body, opts)则先用jwtVerify还原并校验载荷(core/src/index.js)。重放防护以可插拔回调consumeNonce(sigHex, ttlMs)的形式提供——库不绑定具体存储,你可以把它接到 Redis 的SET NX EX、Cloudflare KV 或 PostgreSQL 唯一约束上,实现真正的按需开启(参见 docs/zh/guide/capjs-core.md 的"重放防护"一节)。

为什么选择工作量证明:把"猜谁是人"换成"让滥用变贵"

有效性文档开门见山承认一个事实:任何 CAPTCHA 最终都能被破解——无论是通过 AI 识别图片、算法逆向与伪造指纹,还是直接雇 CAPTCHA 打码平台人工解题。攻防双方因此陷入无休止的猫鼠游戏。Cap 的立场是:真正的区别不在于"能不能破",而在于攻击者要付出多少成本。

文档给出了一个很直观的经济学模型:

设想发送 10,000 条垃圾消息的成本是 1 美元,潜在收益 10 美元,这样有利可图。如果 Cap 抬高计算成本,把发送这批消息的成本变成 100 美元,垃圾消息发送者就要亏损 90 美元,经济动机就此消失。

这就是 PoW 的定位:通过要求付出计算量来阻止滥用,而不是依赖机器人不断学会模仿的人工验证手段。Cap 的工作量证明深受 Hashcash 启发;其 instrumentation 质询则借鉴了 Twitter 和 YouTube 各自的自定义质询。

从实现角度看,这套"成本论"对应的是 core/src/index.js 里validateChallenge对解的校验:每个提交的解必须满足powMatchesPrefix(sha256Bytes(salt + nonce), target),任何错误解都会以invalid_solution失败,攻击者无法靠"猜"通过。机器人要规模化地通过,就只能规模化地消耗 CPU 去求解——这正是成本的来源。

让 GPU 无用武之地:从 SHA-256 到 HashWX

作为通用 PoW 算法,SHA-256 是合理的选择,但它有一个致命弱点:GPU 每秒能清掉的数量大约是 CPU 的 150 倍。GPU 用成千上万条通道同步运行同一个固定函数,而机器人防护真正在意的指标恰恰是吞吐量——攻击者不关心单个质询要花多久,只关心每小时能清掉多少个。

因此,新建的密钥默认使用 HashWX,一个由 tevador(RandomX 与 HashX 的作者)设计的抗 GPU 哈希算法。Cap 在 wasm/src 中内置了其官方 WebAssembly 参考实现,并在 core/src/hashwx.js 中通过hashwxReady()懒加载编译。文档给出的吞吐量对比(来自 tevador 的未公开 CUDA 实现,RSW 行由 Cap 独立复现验证):

算法CPU(Ryzen 3700X,16 线程)GPU(RTX 5060 Ti)GPU 优势
SHA-25641 MH/s6150 MH/s~150x
RSW26 H/s4400 H/s~170x
HashWX2.8 MH/s5.8 MH/s~2x

注意 RSW(时间锁谜题)也在表中:它在延迟维度上很出色(单个谜题内部的顺序平方无法并行),但在吞吐量维度上输得很惨,GPU 可以同时跑几千个互不相关的谜题,优势反而高达 ~170 倍。RSW 已被弃用:它仍然可以按密钥选用,现有密钥也继续可用,但不应再用于新的部署。

HashWX 协议如何工作

在 core/src/hashwx.js 中可以看到协议的完整实现脉络:

  1. 铸造:服务端取 32 个随机字节作为质询C(crypto.randomBytes(HASHWX_CHALLENGE_SIZE)),再定一个难度d。没有密钥材料、没有预计算,铸造就是一次随机读取加一次 JWT 签名——这也解释了文档所说"HashWX 不需要密钥材料,启动时也不用做任何准备"。
  2. 客户端求解:客户端要找到一个 64 位 nonceN,使得H(N) <= (2^64 - 1) / d,其中H = hashwx_make(sha256(C || u64le(N / n)))。每一块n个连续 nonce 共用一个生成出来的哈希函数。hashwxTarget()在源码中即U64_MAX / d的实现。
  3. 块大小n:Cap 使用n = 65536(DEFAULT_HASHWX_NONCES_PER_HASH)。参考协议给原生客户端用的是 463;在浏览器里,每一块都要通过WebAssembly.Module把函数重新 JIT 编译一遍,更大的块能摊薄这部分开销。tevador 明确指出这个取舍:每个函数覆盖的 nonce 越多,协议就越容易被 JIT 编译的 GPU 内核追上,在此取值下撑住抗 GPU 能力的是分支发散。
  4. 服务端验证:服务端根据C和提交的 nonce 对应的块索引重新算出种子(hashwxSeed即sha256(C || u64le(block))),生成那一个哈希函数,运行一次,再与目标比较。程序生成的开销大约只有 HashX 的 1/5,这正是验证能保持在几十微秒的原因。核心实现在 core/src/hashwx.js 的verifyHashwxSolution。

为什么 GPU 快不起来

HashWX 的四个抗 GPU 特性(均出自 tevador 的设计文档)值得展开:

  • 分支发散:每个实例是 32 个程序,每个程序都是一个循环,以 1/2 的概率跳回自己的开头,算下来每次哈希正好 256 次分支。CPU 上这只是几次分支预测失败;GPU 上它会把一个 warp 拆成若干发散路径,只能一条接一条地执行。
  • 刻意不对齐的 16 KB 暂存区:CPU 把它放进 L1,用乱序执行掩盖 3~4 个周期的延迟;GPU 只能放在由 L2 支撑的本地内存里,延迟约 100 个周期,且大多数 GPU 架构还得把两次相邻读取拼起来才能模拟不对齐读取。
  • 深/浅源寄存器列表:源寄存器取自交错排列的"浅"列表和"深"列表,CPU 平均要处理 2.75 次相互依赖的读取;GPU 解释器只能按深列表特化,因为约 95% 的情况下一个 warp 里至少有一个线程在跑深程序,于是每次都吃下完整的 6 次依赖读取链。
  • 受限指令集:指令集被限制在 WebAssembly 1.0 范围内(64 位乘、加、减、XOR、OR、循环移位和移位,6 位立即数),正是这一点让同一套算法能在浏览器里跑起来。

成本:服务端与客户端

文档给出了 Apple M3 单核心上validateChallenge实测的服务端成本(200 次铸造 + 40 次验证取中位数):

协议铸造验证合计
HashWX,1 个质询14 µs40 µs54 µs
HashWX,4 个子质询(默认)20 µs129 µs149 µs
SHA-256(50 个质询,难度 4)4 µs83 µs87 µs
RSW(t = 75,000)1522 µs14 µs1536 µs

单个 HashWX 质询是三者中往返开销最低的;默认的四个子质询约 150 µs,只有 RSW 的十分之一(RSW 每次签发都要做四次真正的模幂运算)。难度不影响服务端成本:无论找到解有多难,验证每个子质询都只需算一次哈希——这一点与 core/src/hashwx.js 中verifyHashwxSolution只执行单次hashwx_exec的实现完全吻合。

为什么默认拆成 4 个子质询?单个质询的求解时间服从指数分布,让它像抽奖:同样的难度,一位访客 30 毫秒解完,下一位要三秒。拆分把总难度d均摊到 4 个独立子质询上(源码见mintHashwxChallenges中的each = Math.max(1, Math.round(difficulty / count))),让求解时间更均匀。文档在 8 核 M3 上用正式版 Chrome 实测(每组 72 次求解,两种难度调到相同中位数):

1 个质询,d = 1,330,0004 个子质询,d = 1,000,000
中位数536 ms490 ms
p901447 ms778 ms
72 次中最慢2378 ms1490 ms

对给定的难度,拆分并不改变攻击者要付出的代价(预期工作量都是d次哈希),改变的是分布形状:单个质询的中位数只有均值的 0.69,四个子质询把中位数推到均值的 0.92 左右,长尾也随之缩短。验证组件自身的开销很小——worker 每 16 毫秒检查一次是否该停止(HASHWX_YIELD_MS = 16,见 widget/src/src/worker.js),这决定了子质询之间交接的最长时间。

浏览器引擎与移动端表现

HashWX 的 wasm 构建速度约为原生的 60%。三大引擎在单个 worker 上相差无几,所有核心跑满时 Safari 会落后(同一台 M3、同一次测试、各浏览器处于无头或前台):

引擎1 个 worker8 个 worker解释执行回退
Chrome 153440 KH/s2050 KH/s94 KH/s
Firefox 156420 KH/s1850 KH/s105 KH/s
Safari 27.2410 KH/s1480 KH/s105 KH/s

调难度时要以 Safari 为准:d = 1,000,000 时 Chrome 上平均约 0.5 秒,Safari 上约 0.7 秒。自行测量时务必使用各浏览器的正式发布版并让标签页保持在前台——Playwright 自带的 Firefox 跑任何 WebAssembly 负载都比正式版慢 3~6 倍,后台标签页则可能被调度到能效核心上让数字直接减半。

移动端(BrowserStack 真机,默认配置,每台 15 次求解,Vivo 30 次,每轮从刚加载的页面开始):

设备系统全部核心中位数最慢
Galaxy S24Android 141238 KH/s1.1 秒1.8 秒
Pixel 9Android 15837 KH/s1.4 秒2.0 秒
Pixel 6Android 12746 KH/s1.9 秒2.4 秒
iPhone 15iOS 17未测1.9 秒4.3 秒
Redmi Note 11Android 11456 KH/s2.4 秒4.8 秒
Vivo Y21Android 11316 KH/s5.9 秒11.0 秒

每次求解都包含两次到测试服务器的往返(各设备中位数 80~190 ms)。入门级 Android 手机的耗时约为 M3 台式机的十倍——如果你的流量以移动端为主,请调低难度;求解时间与难度成正比,500,000大约能让表中每个数字的求解部分减半。此外,没有 WebAssembly 的客户端根本解不了 HashWX(会直接拿到错误),需要支持它们时应改用有纯 JS 回退方案的 SHA-256 PoW(回退求解器实现见 widget/src/src/worker.js 的solveFallback);iPhone 上验证组件需要 iOS 15 或更高版本。

与 Instrumentation 质询协同:付出 + 环境

工作量证明证明的是付出(客户端必须消耗 CPU 周期寻找哈希),但它无法证明计算发生在真实浏览器里——攻击者可以用脚本直接跑求解器。这正是 Instrumentation 质询的用武之地:每次请求时服务端生成一段独一无二的 JavaScript 程序(core/src/instrumentation.js 的generateInstrumentation),在访问者浏览器中执行后把答案发回,由服务端对照预先并行跟踪的期望值校验,在接受令牌前确认对方处于真实浏览器环境。

它的核心机制值得展开:

  • 主计算链:多个整数变量以随机种子值初始化,经过约 20 轮随机化操作不断变换,包括按位 AND/OR/XOR/NAND、原型链技巧(fnHelper中的构造函数原型篡改),以及基于 DOM 的运算(domHelper向页面追加一棵元素树,沿树回溯累加数值,最后移除)。
  • 为什么用 DOM 操作:纯算术运算在非浏览器环境里直接运行这段 JS 就能复现;DOM 操作做不到,至少无法低成本地做到——构建真实元素树、通过排版引擎读取数值、再拆除它们,触及的是非浏览器运行时常常只做桩实现、实现得不正确或出于性能跳过的那部分。质询因此很难在真实渲染引擎之外被重放。
  • 自动化浏览器检测:可选开启blockAutomatedBrowsers,脚本会运行 realm 逃逸检测与行为检测(headless Chromium 标记、webdriver 属性、window/document上的自动化框架注入标记等),识别 Playwright/Puppeteer/Selenium 等。不过文档如实说明:这些检查并非万无一失,即使是 Turnstile 这样的商业闭源 CAPTCHA,攻击者也能用打过补丁的隐身浏览器绕过。
  • 执行环境:所有检查都在 iframe 内运行,通过postMessage把答案发回父页面。服务端通过verifyInstrumentationResult校验返回的state是否与expectedVals完全一致(core/src/instrumentation.js)。

两者互补而非冗余:PoW 抬高"付出"维度的成本,Instrumentation 验证"环境"维度的真实性,在两个独立维度上抬高滥用成本。面对有决心的攻击者,单独任何一个都不够,但同时攻破两者就难得多。同样重要的是文档的告诫:Instrumentation 并非万无一失,不建议用它替代工作量证明——在没有 PoW 的情况下,攻击者用真实浏览器就能低成本地批量通过这类质询。

局限与边界:HashWX 防不住什么

与 RSW 防不住的是同一件事:定制芯片。专门为 HashWX 打造的 FPGA 或 ASIC 仍然会赢过 CPU。对刷 CAPTCHA 来说这笔账通常算不过来(ASIC 的一次性工程费用高达数百万美元),但这终究不是密码学层面的保证。

它同样拦不住人工打码农场,而且永远拦不住——工作量证明抬高的是每个请求的成本,不是人工的劳动。正确姿势是把 HashWX 与 instrumentation 质询搭配使用,让攻击者还必须提供真实的浏览器环境。

实战:在哪里配置难度与协议

cap-core:format-2 API 手动启用 HashWX

在 docs/zh/guide/capjs-core.md 中,cap-core 的默认仍是 SHA-256 PoW,HashWX 需要通过 format-2 API 手动启用:

import { generateChallenge, validateChallenge } from "capjs-core"; const SECRET = process.env.CAP_SECRET; app.post("/api/challenge", async () => { return await generateChallenge(SECRET, { format: 2, protocols: ["hashwx", "instrumentation"], hashwxDifficulty: 1_000_000, // 可选,这就是默认值 }); }); app.post("/api/redeem", async (req) => { return await validateChallenge(SECRET, req.body, { consumeNonce }); });

关键参数(默认值与边界均来自 core/src/hashwx.js):

  • hashwxDifficulty:客户端预期计算的哈希次数,默认1_000_000,合法范围[1, 1_000_000_000];
  • hashwxChallengeCount:拆分的子质询数,默认4,范围[1, 64];每多一个子质询,验证开销约增加 20 µs;
  • hashwxNoncesPerHash:每个生成函数覆盖的 nonce 数,默认65_536,范围[1, 1_048_576]。

HashWX 不需要密钥材料,启动时也无任何准备;第一次验证会编译内置的 WebAssembly 模块(耗时几毫秒),可在启动阶段调用hashwxReady()把这份开销从首个请求挪走。验证组件会自动检测 format-2 响应,只需升级服务端即可。

Cap Standalone:按站点密钥切换协议

在 docs/zh/guide/standalone/options.md 中,HashWX 是新建密钥的默认协议,且按站点密钥配置:个别密钥可以用 SHA-256,其余继续留在 HashWX 上;在 HashWX 成为默认之前创建的密钥会保持原有设置直到手动更改。打开某个密钥的Configuration标签页,在Challenge protocol下选择协议即可,无需任何准备工作(没有密钥对要生成,也没有东西要持久化)。

难度由HashWX difficulty滑块控制(客户端预期计算的哈希次数),默认1_000_000,有效范围50_000–5_000_000,拆分为四个子质询。调高之前请先参考上文移动端测量结果。Instrumentation 质询在新建站点密钥时默认开启,可在密钥配置中开关;"Attempt to block headless browsers" 可阻止无头浏览器求解。较高的 instrumentation 混淆级别会显著降低生成吞吐量,除非需要更强混淆,建议保持在级别 3(obfuscationLevel默认值,1–10 可选,参见 docs/zh/guide/capjs-core.md 的 Instrumentation 一节)。

延伸阅读

  • CAPTCHA 与转化率:质询摩擦对注册量的代价,以及低摩擦机制为何在转化率上更优
  • 2026 年最佳 CAPTCHA 替代方案:与其他机制(Turnstile、hCaptcha、FriendlyCaptcha、ALTCHA 等)的横向对比
  • HashWX 工作量证明:抗 GPU 协议的完整设计与测量细节
  • Instrumentation 质询:第二层验证的机制与局限
  • Core 无状态服务端库:generateChallenge/validateChallenge的完整 API 与无状态部署模式(Cloudflare Workers、Bun)
  • Standalone 配置选项:环境变量、速率限制、Redis/Valkey、健康检查与 HashWX 滑块
  • 网络安全
  • 应用安全
  • 后端

【免费下载链接】cap

Free, open-source and self-hosted CAPTCHA alternative to reCAPTCHA. Privacy-first and powered by proof-of-work and instrumentation challenges.

项目地址:https://gitcode.com/gh_mirrors/cap13/cap
点击查看免费下载

相关推荐

上一篇:GEMMA全基因组关联分析工具:免费高效的遗传数据分析终极指南
下一篇:Nuclide工作集模板库:框架特定配置快速应用

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 2:49:43

2026最新百度推广电话避坑指南:3步搞清备案与转化

2026最新百度推广电话避坑指南:3步搞清备案与转化 备案流程一头雾水?别急,这是90%独立站长在2026年遇到的第一道坎。很多人以为拿到【百度推广电话】就能躺赢流量,结果卡在ICP备案上,网站上线慢了一周,客户全跑了。今天不聊虚的,直接拆解2026年建站与推广的实操细节。…

作者头像 李华
网站建设 2026/9/28 2:49:26

宁波的网络营销服务公司新手入门

宁波网络营销服务公司选错坑?5款免费工具保命指南 网站半夜突然挂满赌博广告,后台密码改了也进不去,域名被劫持指向奇怪页面。这时候你慌不慌?别急着哭,也别盲目找宁波的网络营销服务公司挨宰。我是干了十年SEO和运维的老鸟,见过太多老板花几万块请“专家”,结果连基础的安全扫描都没做。今天不聊虚的,直接上干…

作者头像 李华
网站建设 2026/9/28 2:49:13

石家庄做网站优化详细步骤

石家庄做网站优化哪家好,别只看报价单看细节 找石家庄做网站优化的朋友,最怕的不是技术不懂,而是怕被坑高价。很多老板花几万块做个站,结果打开速度慢得像蜗牛,百度收录还没个影。这时候你问“哪家好”,销售只会给你看案例图,但图好看不代表体验好,更不代表能带流量。…

作者头像 李华
网站建设 2026/9/28 2:48:33

wordpress如何安裝保姆级建站教程避坑指南

wordpress如何安裝保姆级建站教程避坑指南 找过建站公司的朋友,心里大概都打过鼓。报价单上写着“企业级定制”,交钱后发来的却是套壳模板,改个颜色还得加钱,这种高价低质的坑,太多人踩过。其实,对于很多中小企业和个人开发者来说,掌握 wordpress如何安裝…

作者头像 李华
网站建设 2026/9/28 2:48:32

3步搞定seo页面代码优化,小白也能看懂怎么选

3步搞定seo页面代码优化,小白也能看懂怎么选 域名服务器搞不懂,后台代码像天书,这是很多做市场推广的朋友在接手网站优化时最头疼的事。你明明知道SEO能带来流量,但看着满屏的HTML标签和CSS样式,完全不知道 怎么选 对的方向下手。 别急,今天咱们不聊那些虚头巴脑的理论,直接拆解…

作者头像 李华
网站建设 2026/9/28 2:48:23

wordpress还原网站源码实操避坑指南

wordpress还原网站源码实操避坑指南 改个需求建站公司拖一周,改个颜色还要加钱,这种憋屈感做过网站的人都懂。手里攥着源码却不敢动,怕一碰就崩,或者根本不知道从哪下刀。今天这篇不是讲大道理,而是直接拆解【wordpress还原网站源码】的底层逻辑,给你一份实打实的【避坑指南】。咱们不整虚的,直接…

作者头像 李华