前天中午莫名其妙收到一条评论:内容是英文的,昵称是印尼语(翻译过来是“混凝土板”),链接是拼凑的(一个东南亚中医诊所)。更诡异的是,评论发布在一篇已经被我隐藏的文章里。而昨天中午又在相近的时间、相同的文章收到了类似的评论。可惜两条评论脑子一热全给删了,没留着对IP做点“有意思”的分析,而是直接打为人机,也因此开始着手做评论区的反人机系统。

硬要说Typecho这框架还有什么优点,我个人认为是其完善的插件生态。尽管牺牲了一部分的自定义能力,这种“抄作业”模式确实让功能的添加与分离更便利了些。

从2000年 CAPTCHA (Completely Automated Public Turing test to tell Computer and Human Apart, 全自动区分人类与计算机的图灵测试)(又臭又长)以其经典的“识别扭曲字符串/图形分类”模式出现,到Google reCAPTCHA v1,v2 的“人工OCR”和 臭名昭著的“人工数据标注”,再到如今逐渐无操作化的reCAPTCHA v3(代价是跨站追踪构建你的用户画像)以及转而“拷打浏览器”的Cap,Turnstile等——人类在网络世界同自动机器的斗争从未停歇,当然这期间也收割了盟友无数免费的劳动力。

在2026年,想要让各位在发表评论前“标记下面图片中的红绿灯👇”无异于化身全民公敌,因此思路一定是要往无感化的方向靠拢的。找来找去,最终敲定了Cap。原因嘛……当然是因为其有 诸多优点 现成插件啦!

Cap,是啥?

首先简要介绍一下这种验证模式。Cap不仅如前所述选择“拷打浏览器”,还玩了招阴的——成本。两层的验证模式中,

  • 第一层:工作量证明(PoW) 在这里,服务器会向发起请求的Cap组件生成一个“挑战”,要求请求端暴力算出一个与答案(通常是一个特定的模式,例如要求哈希值以0000开头)匹配的SHA-256值。由于SHA-256用16进制表示,这意味着浏览器平均要做16^4=65536次尝试。对于只想发一条评论的你而言,这点功夫不值一提,而对于广告灌水的自动程序,这可是一笔相当不划算的算力开销。从成本考虑,这类CAPTCHA实在不值得大量“硬刚”——不得不说,这一招确实高明!
  • 第二层:浏览器验证 已经不算新鲜了。Cap服务器会向请求端发送一段随机的、只有浏览器端才能正确实现的JS程序,来确定请求来源。

Cap服务器会在两层验证均通过后,向客户端返回一个JWT redeem token。最后还有一步,客户端服务器(注意不是浏览器)需要将这个token和自己的SiteSecret字段再次发送给Cap服务器做一次检验,确保token有效,避免伪造/复用。

这是一个成功的Cap请求的时序图:

CAP请求流程图.pngCAP请求流程图.png

那么,它的优势在哪?可以归结为以下几点:

  • 轻(客户端组件12-20KB),加载快。
  • 注重隐私。不收集用户数据。
  • 开源,可自托管(事实上自托管是最好的选择!)

只说优势不说劣势是不对的。其缺点主要是:

  • 只防懒汉,不防行家。PoW只能让低成本自动化变得极不划算。如果有人铁了心要刷你的博客,甚至不惜买GPU集群,那么Cap也没办法。
  • 如果攻击者用了无头浏览器,两层验证即可轻松通过。

插件:Cap for Typecho

项目地址:https://github.com/hzl0931/Cap_for_Typecho
基于 cc2562/Cap_for_Typecho 的插件再开发。原作者的老版插件在Typecho 1.3.0启动时会出Bug,已经做了修复。同时增加了使用 Cloudflare Access Service Token 保护 Cap /api/validate/的服务的功能(见下节)。

注意,在使用前,需要手动把前端逻辑业务逻辑写进你的评论表单文件(参见项目readme)。

对于不想使用国外客户端脚本(默认的https://captcha.gurl.eu.org/cap.min.js)的用户,可以选择国内CDN:https://cdn.jsdelivr.net/npm/@cap.js/[email protected]/cap.min.js。

托管你自己的Cap服务并保护

Cap默认的API服务由提供由开发者个人https://captcha.gurl.eu.org/api/提供,国内可能不太稳定。你可以在Cap原项目地址找到自托管的方法。但是最方便的当然是使用Cloudflare!xyTom/cap-worker项目已经构建好了生产/开发环境,可以一键部署到Cloudflare。服务启动后,你会得到一个链接,类似于这样:

服务链接-Cloudflare Worker界面.png服务链接-Cloudflare Worker界面.png

接下来只需将你的链接/api/填入插件设置中的“Cap API 端点”字段就可以使用了。如果你希望将域名整合到自己的固有域名中,可以点下方的“添加域名”或“添加路由”,但你需要把自己域名的DNS解析全部迁移到Cloudflare下。(Cf免费的域名解析还是很香的!)

保护你的/api/validate/

自己有一点一直没绕清楚。因为Cap服务的验证依赖SHA-256计算,因此如果你的服务地址(/api/challenge/ & /api/redeem/)暴露在公网,很有可能就会被别人拿去白嫖——但,这是没有办法的。Cap本身就要求对/api/challenge/的请求匿名,因此,用服务令牌一类的token机制保护/api/challenge/毫无意义。

唯一能保护的是/api/validate/接口。这个接口的目的是完成两层验证后对JWT redeem token的鉴定。为此,开通免费的Cloudflare Zero Trust基础版,在访问控制-服务凭据里新建服务令牌,再在访问控制-应用程序中新建“自托管/私有”程序,在目标-公共主机名中填自己的url(your-cap-server-url/api/validate/),在“Access 策略”中选择“Service Token”,“操作”选择“服务身份验证”,然后保存;回到插件设置,填入新建服务令牌时提供的Cloudflare Access Client ID和Client Secret,搞定!

千万不要试着也对/api/challenge/ & /api/redeem/添加同样的保护策略。牢记对/api/challenge/ & /api/redeem/的请求是匿名的,永远不会也不应该受到服务令牌保护。