恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Cap 内部工作原理:自托管 CAPTCHA 的 SHA-256 工作量证明与埋点挑战全流程解析

  • 首页
  • 资讯中心
  • /
  • Cap 内部工作原理:自托管 CAPTCHA 的 SHA-256 工作量证明与埋点挑战全流程解析

相关资讯

别被建站公司坑了3000块,这3个免费工具搞定wordpress订单提醒功能 2026/9/27 23:35:17
PyTorch全连接网络实现垃圾邮件分类:从文本清洗到模型训练 2026/9/27 23:35:17
PyTorch全连接神经网络垃圾邮件分类实战:从文本清洗到模型训练 2026/9/27 23:35:16

最新资讯

知识产权网站开发避坑指南:性能优化决定咨询转化
选对早教网站源码才不挂马,这套最佳实践救过我
新手入门外贸网站服务器推荐:3个坑避开,省钱又稳定
WordPress页面模板目录文件下载:5大注意事项避坑指南
南宁网站建设公司利润真相:新手怎么选避坑指南
0代码做网站工作避坑指南:2024最新速查手册

今日推荐

婚恋网站实战案例:避开3个高价坑,省钱50%还能跑赢流量
制作网页比较方便的软件怎么选?一文搞懂避坑指南
BootCamp6.1.7071驱动包手动安装与回滚全攻略

本周热门

从像素到笔画:srt-whiteboard-animation骨架笔迹追踪实现(Zhang-Suen细化+8邻接追踪)
网站建设的英语怎么说?别只背单词,看完这套安全完整流程才敢上线
新手入门看这篇:建设网站加盟避坑指南与SEO实操

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

Cap 内部工作原理:自托管 CAPTCHA 的 SHA-256 工作量证明与埋点挑战全流程解析

发布时间:2026/9/27 23:35:17
Cap 内部工作原理:自托管 CAPTCHA 的 SHA-256 工作量证明与埋点挑战全流程解析 网络安全应用安全后端【免费下载链接】capFree, 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 替代方案在浏览器与服务端之间的完整工作链路从 widget 的注册与 shadow DOM 构建到挑战请求、基于 Rust WASM 与 Web Worker 的并行求解、沙箱 iframe 中的埋点instrumentation挑战再到服务端基于同一种子重放挑战、验证并兑换一次性令牌。读完本文你将能准确理解 Cap 的种子化挑战 双重验证 一次性令牌设计并能在部署、集成与排查时定位到每一环节对应的源码实现。说明本文仅覆盖 SHA-256 PoW 与 instrumentation 挑战链路不包含 HashWX相关内容见 HashWX 说明。希望获得更宏观的对抗效果概述可阅读 效果评估。1. 总体流程一次人类验证的九步生命周期原文档将 Cap 的完整流程归纳为三个阶段九个步骤我们可以把一次验证的生命周期整理如下阶段步骤发生位置核心动作初始化1–2浏览器注册自定义元素cap-widget构建 shadow DOM 与全部 UI 元素请求挑战3–4浏览器 ↔ 服务端请求challenge接口获得 token、挑战配置与可选的压缩埋点数据由固定种子派生多个挑战计算解5–6浏览器WASM Web Workers 并行求解 SHA-256 PoW在沙箱 iframe 中解压并执行埋点挑战兑换令牌7–9浏览器 ↔ 服务端提交解至redeem接口服务端独立重放挑战并校验消费解并签发一次性令牌核心设计思想挑战与验证都是**确定性deterministic**的——双方使用同一个 token 作为种子依据同样的参数推导出相同的 salt 与 target因此服务端可以脱离任何会话状态仅凭提交的 token 与解就能完成校验而消耗即作废的一次性令牌设计nonce 消费则保证同一份解不能被重复兑换。2. 初始化自定义元素与 shadow DOM2.1 自定义元素的注册Cap 的 widget 是一个继承自HTMLElement的CapWidget类。脚本加载后会在页面全局注册名为cap-widget的自定义元素if (!customElements.get(cap-widget) !window?.CAP_DONT_SKIP_REDEFINE) { customElements.define(cap-widget, CapWidget); }若页面中已存在同名自定义元素Cap 会跳过注册并打印警告同时提供了window.CAP_DONT_SKIP_REDEFINE true用于强制覆盖见 widget/src/src/cap.js。widget 同时以window.Cap暴露构造器并兼容 CommonJS / AMD / ESM 导出。2.2 shadow DOM 的构建在connectedCallback()元素被插入文档时触发中Cap 完成以下初始化this.#shadow this.attachShadow({ mode: open }); // 创建 open 模式的 shadow DOM this.createUI(); // 构建 widget 全部 UI 元素 this.addEventListeners(); // 绑定事件 this.initialize(); // 预创建 Worker、AbortController 等 this.#host.innerHTML input typehidden name${this.#fieldName}; // 隐藏表单字段其中隐藏表单字段cap-token默认data-cap-hidden-field-name用于在表单提交时携带验证令牌见 widget/src/src/cap.js 与 widget/src/src/cap.js。Worker 数量默认取navigator.hardwareConcurrency也可通过data-cap-worker-count属性指定。3. 请求挑战challenge 接口与种子化派生3.1 请求的发起用户点击验证或页面预加载触发后widget 向data-cap-api-endpoint指定的服务端地址发起POST {endpoint}/challenge请求。Cap 支持通过window.CAP_CUSTOM_FETCH注入自定义 fetch 实现以适配非标准网络环境见 widget/src/src/cap.js。在自托管 standalone 部署中对应的路由为/:siteKey/challenge见 standalone/src/cap.js。服务端在签发挑战前会执行一系列前置检查校验 site key 是否存在及其jwtSecret配置按 IP 进行封禁规则匹配支持精确 IP、cidr:前缀、asn:、country:等规则可选地拦截非浏览器 UAblockNonBrowserUA与缺失必需请求头requiredHeaders的请求执行基于 Valkey/Redis 的限流默认 30 次 / 5 秒可被 site key 级配置覆盖。3.2 服务端如何生成挑战服务端核心调用capjs-core的generateChallenge(secret, opts)。以 SHA-256 PoWformat 1默认协议为例挑战的默认参数与约束如下参数默认值合法范围含义challengeCountc501–1000需要求解的挑战个数challengeSizes321–256salt 的十六进制长度即字节数×2challengeDifficultyd41–16目标哈希前缀长度十六进制位expiresMs10 分钟—挑战令牌的过期时间tokenTtlMs20 分钟—兑换出的令牌的有效期以上默认值与范围定义可见 core/src/index.js 与 core/src/index.js。若同时启用了 instrumentation服务端还会生成埋点脚本并将期望值以 AES-256-GCM 加密encryptGcm后写入令牌载荷payload.ei字段见 core/src/index.js。随后挑战配置、随机 noncen: randomHex(25)、过期时间等被封装为 HS256 签名的 JWT 令牌见 core/src/crypto.js。这个令牌同时充当派生挑战的种子——它的签名与载荷共同保证了挑战只能由签发它的服务端验证。3.3 浏览器端从种子派生 salt 与 target响应格式为{ challenge: { c: 50, s: 32, d: 4 }, token: JWT, expires: 1730000000000, instrumentation: 压缩后的 base64 数据可选 }浏览器端利用 PRNG 从 token 种子逐个派生 salt 与 targetchallenges Array.from({ length: challenge.c }, () { i; return [ prng(${token}${i}, challenge.s), // salt以 token序号 为种子的确定性随机串 prng(${token}${i}d, challenge.d), // target以 token序号d 为种子派生前缀 ]; });对应实现见 widget/src/src/cap.js。prng采用 FNV-1a 哈希播种 xorshift 生成器见 core/src/prng.js并保证两次相同输入得到完全一致的输出——这正是服务端可以独立重放的前提。若提供了 instrumentation 数据widget 会先将其解压再放入沙箱 iframe 执行见 widget/src/src/cap.js。3.4 服务端验证侧的派生公式在验证时服务端并不依赖记忆任何状态而是从令牌出发复算 salt 与 targetconst tokenFnv fnv1a(token); // 令牌 FNV-1a 哈希作为种子 for (let i 0; i c; i) { const saltSeed fnv1aResume(tokenFnv, String(i 1)); const targetSeed fnv1aResume(saltSeed, d); const salt prngFromHash(saltSeed, size); const target prngFromHash(targetSeed, difficulty); // 校验 sha256(salt nonce) 是否以 target 为前缀 }对应实现见 core/src/index.js。parseHexPrefix支持奇数长度的十六进制前缀并保留半字节掩码powMatchesPrefix逐字节比较哈希前缀见 core/src/crypto.js。4. 计算解Rust WASM Web Worker 并行求解4.1 Worker 池与并行策略widget 内部维护了一个WorkerPool任务进入队列后被派发给空闲 Workerdata-cap-worker-count控制池大小默认navigator.hardwareConcurrency || 8。Worker 通过 Blob URL 从内联脚本创建支持失败后自动替换最多重试 3 次与stop消息优雅终止见 widget/src/src/cap.js。每个 Worker 的求解逻辑伪代码循环: 将 salt 与递增的 nonce 组合 计算 SHA-256(salt nonce) 若哈希以 target 前缀开头 → 返回该 nonce 否则 nonce4.2 WASM 求解器与 JS 回退WASM 模块通过window.CAP_CUSTOM_WASM_URL可自定义地址默认从cap.js/wasm包加载见 widget/src/src/cap.js。Rust 侧的求解器针对 WebAssembly SIMD 做了 4 路并行4-way multiway ARXSHA-256 优化每条消息4 个不同 nonce 的 salt 组合同时处理并一次性提取每个哈希的前 64 位进行目标匹配见 wasm/src/rust/src/lib.rs 与 wasm/src/rust/src/lib.rs。从源码结构看Rust 侧parse_target断言目标不超过 64 位bits 64因为超过 64 位的前缀在实际求解中已不现实——这也解释了challengeDifficulty上限被约束在 16即 64 位十六进制的原因见 wasm/src/rust/src/lib.rs。当 WebAssembly 不可用时如极旧浏览器Worker 会回退到纯 JS 求解器使用crypto.subtle.digest(SHA-256)按 50000 次一批计算并逐字节/半字节比对目标前缀见 widget/src/src/worker.js。回退模式会显著变慢属于降级兼容路径。4.3 投机式求解speculative solving为进一步优化用户体验Cap 实现了隐形预求解widget 在用户首次交互mousemove/touchstart/keydown后若可见则延迟 2500ms 提前拉取挑战并仅用 1 个 Worker 后台求解用户真正点击验证时若预求解尚未完成则立即将 Worker 池扩容至全量并接力继续见 widget/src/src/cap.js 与 widget/src/src/cap.js。已获得的令牌会被缓存使用直到过期后自动reset()。5. 计算解沙箱 iframe 中的埋点挑战5.1 解压与执行当服务端启用了 instrumentation 时挑战响应会附带一段压缩数据。widget 优先使用浏览器原生的DecompressionStream(deflate-raw)解压若不可用则动态加载 pako 作为回退也可通过window.CAP_PAKO_URL指定 CDN 地址见 widget/src/src/cap.js。解压出的脚本被注入一个sandbox 隔离的 iframe中执行iframe.setAttribute(sandbox, allow-scripts); // 仅允许脚本无同源能力 iframe.style.cssText position:absolute;width:1px;height:1px;top:-9999px;...; // 完全不可见脚本通过window.postMessage与主页面通信超时上限为 20 秒若检测到自动化浏览器iframe 会回传blocked标记见 widget/src/src/cap.js。这一设计使得埋点挑战与主页面环境相互隔离既防止脚本被页面脚本干扰也避免其影响页面自身。5.2 埋点检测什么服务端生成 instrumentation 脚本的核心是generateInstrumentation见 core/src/instrumentation.js脚本会在 iframe 内探测一系列环境特征并在生成阶段就为每个探针字段注入随机变量名与期望值服务端已知答案客户端无法预判。检测维度包括自动化框架标记window/document/navigator上残留的 Selenium、WebDriver、PhantomJS、Playwright 等特征属性与前缀见 core/src/instrumentation.js引擎一致性Gecko 引擎却带有 Chromium 特征如deviceMemory、userAgentData的矛盾判断无头浏览器User-Agent 与 brand 列表中的HeadlessChrome等 token字体指纹几何特征通过一组字体栈探测量化后的字体宽度分布是否过于整数化geometry_quantized视图窗口异常单显示器下 outerHeight 超过屏幕高度、viewport 被强制覆盖为全屏等自动化痕迹原生方法篡改被 JS 覆写的navigator属性tamper 检测。上述检测规则完整实现于 core/src/detect.jsdetectAutomation返回pass、checks、blockedBy与riskFlags。其中 gating门禁类检查不通过即拦截非门禁类如 tamper仅作为风险标记可由上层策略决定。5.3 服务端如何验证埋点结果widget 将埋点执行结果随兑换请求提交instr字段。服务端在验证时先解密令牌中的ei载荷取出服务端期望值expectedVals、vars等再调用verifyInstrumentationResult对提交结果逐项比对若启用了blockAutomatedBrowsers且检测到自动化标记则直接拒绝返回instr_automated_browser。失败原因包括instr_corrupted数据损坏、instr_expired过期、instr_timeout超时、instr_missing未提交等见 core/src/index.js。standalone 服务端将上述失败映射为对应的 HTTP 状态码与错误信息见 standalone/src/cap.js便于前端据此展示不同的错误 UI。6. 兑换令牌服务端独立验证与一次性消费6.1 redeem 请求求解完成后widget 向POST {endpoint}/redeem提交{ token: 挑战令牌, solutions: [12345, 67890, ...], instr: { 字段1: 值1, 字段2: 值2 } // 启用 instrumentation 时 }6.2 服务端验证流程standalone 的/:siteKey/redeem路由调用validateChallenge(secret, body, opts)见 standalone/src/cap.js核心校验步骤依次为令牌校验JWT 签名与载荷验证jwtVerify比对scopesite key检查exp是否过期参数合法性c/s/d必须在约束范围内solutions必须是长度为c的数字数组逐条重放校验对每个挑战重新执行 FNV-1a PRNG 派生 salt 与 target计算sha256Bytes(salt solutions[i])并比对powMatchesPrefix任一失败即返回invalid_solution埋点校验若启用解密ei载荷、比对 instrumentation 结果一次性消费nonce 防重放调用consumeNonce(sigHex, ttlMs)在 standalone 中即对令牌签名哈希执行 RedisSET key 1 NX EX ttl原子操作成功才表示未被兑换过失败返回already_redeemed见 standalone/src/cap.js。针对上述校验路径core/test/core.test.js 覆盖了错误 secret、篡改 JWT、解数量不匹配、非数字解、过期挑战、scope 不匹配、解重放already_redeemed等全部失败分支是理解验证语义的绝佳参考。6.3 签发最终令牌验证通过后服务端消费本次挑战解并签发可证明人类的一次性令牌若提供了signToken回调standalone 即采用此方式则生成{siteKey}:{redeemId}:{redeemSecret}格式令牌并写入 RedisTTL 2 小时见 standalone/src/cap.js 与 standalone/src/cap.js否则由capjs-core生成{id}:{verToken}形式令牌并返回tokenKeySHA-256 后的密钥供服务端存储比对。响应形如{ success: true, token: 一次性令牌, expires: 1730007600000 }widget 收到后将其写入隐藏表单字段cap-token触发solve事件并派发 100% 进度同时根据expires设置自动reset()定时器令牌过期后自动进入下一轮验证见 widget/src/src/cap.js。表单提交时应用服务端即可依据该令牌放行请求。7. 安全特性总结与排查指引7.1 关键安全设计特性机制源码位置挑战不可伪造挑战令牌为 HS256 JWTsalt/target 由令牌确定性派生core/src/index.js、core/src/index.js解不可复用consumeNonce一次性消费RedisNX EX原子占位standalone/src/cap.js埋点不可造假期望值加密进令牌随机变量名服务端比对core/src/index.js、core/src/index.js挑战不可转移scope绑定 site keycore/src/index.js过期兜底挑战 10 分钟、令牌 20 分钟standalone 为 15 分钟 / 2 小时core/src/index.js、standalone/src/cap.js自动化识别沙箱 iframe 探针 服务端规则引擎core/src/detect.js7.2 常见问题定位提示 Invalid solution多为解被篡改或服务端 secret 与签发时不一致可对照 core/test/core.test.js 的重放逻辑检查提示 Challenge already redeemed同一 token 被重复兑换说明一次性消费机制生效属预期行为见 core/test/core.test.js提示 Challenge expiredtoken 超过expiresMs前端应在过期后重新请求挑战埋点相关 403对应instr_automated_browser、instr_timeout、instr_missing等分支可结合 standalone/src/cap.js 的错误映射确认具体原因性能调优通过data-cap-worker-count控制并行 Worker 数对高配置服务器可适当提升challengeDifficulty低端设备则相应调低以缩短求解时间。8. 延伸阅读capjs-core 核心库说明generateChallenge/validateChallenge的完整 API 与集成方式服务端部署指南自托管 standalone 服务的安装与配置Widget 使用指南自定义元素属性、事件与表单集成埋点配置与疑难排查instrumentation 启停与误报处理HashWX 协议本文未覆盖的替代 PoW 协议相关实现位于 core/src/hashwx.js赞分享网络安全应用安全后端【免费下载链接】capFree, 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点击查看免费下载相关推荐res-downloader 网络资源嗅探完整教程从克隆仓库到保存第一条无水印视频res downloader 网络资源嗅探完整教程从克隆仓库到保存第一条无水印视频 res downloader 是一款基于 Go 与 Wails 的跨平台网网络安全应用安全后端Myrtille终极指南原生HTML远程桌面协议与SSH客户端的完整解析Myrtille终极指南原生HTML远程桌面协议与SSH客户端的完整解析 Myrtille是一款强大的原生HTML4/HTML5远程桌面协议RDP和SSHCap 的 HashWX 工作量证明GPU 抗性挑战协议的原理、成本与配置实战Cap 的 HashWX 工作量证明GPU 抗性挑战协议的原理、成本与配置实战 HashWX 是开源项目 Cap 的默认挑战协议也是其对抗 GPU 算力碾压网络安全应用安全后端上一篇如何快速掌握cel-go深入理解表达式语言的核心实现原理下一篇5分钟打造专业音乐播放器foobox-cn美化配置终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号