CrawlForge MCP
政策

验证 CrawlForge 抓取器

日志里有一个请求自称是 CrawlForge。本页说明如何核实它确实是我们、如果你不希望被抓取该如何屏蔽,以及可以写信给谁。

匹配令牌,而不是整个字符串 产品令牌 CrawlForge 是稳定的。它后面的版本号每次发版都会变化,两个运行面上的值也不相同,因此针对完整 User-Agent 字符串写的规则迟早会失效。请匹配令牌;如果你想要的是证据而不是声明,请验证签名。

CrawlForge 如何标识自己

CrawlForge 抓取的每个页面都携带同一个诚实的 User-Agent:产品令牌 CrawlForge、一个版本号和一个联系 URL。没有第二个身份,不做轮换,也不会默认伪装成浏览器——抓取器运行规则解释了为什么这是一条规则而不是一种偏好。

CrawlForge 有两个运行面,两者都发送这个令牌:托管的 REST API,以及由客户自行运行的 crawlforge-mcp-server 包。两者各自发送自己包的版本号,因此版本号部分会随运行面和发版而变化,令牌则不会。

User-Agent 模式

这才是我们支持你去匹配的内容。只有版本号部分会变化。

User-Agent patternBash
CrawlForge/<version> (+https://crawlforge.dev)

托管 API 当前发送的内容

它由抓取器实际发送的同一个常量生成,所以本页不会与请求头脱节。它只是示例,不是用来匹配的字符串:下一次发版就会变。MCP 服务器发送同样的形式,只是带上它自己包的版本号。

request headersBash
User-Agent: CrawlForge/1.0.0 (+https://crawlforge.dev)

在日志中识别我们

对令牌做前缀匹配,可以在我们每一次发版之后继续有效。

matching us in your logsBash
# Match the product token. Anchored, and stopping at the slash, so the
# version cannot break the match on our next release.
^CrawlForge/

已停用的 CrawlForge-Bot 令牌

我们的部分工具过去标识为 CrawlForge-Bot。现在已经没有任何东西发送该令牌,全部发送 CrawlForge。

不过它仍然被当作 disallow 的来源继续遵守。否则统一令牌会悄悄解除对我们所有已在 robots.txt 中写下旧名称的站点所有者的屏蔽,而那是他们针对我们做出的决定,改名不该把它一笔勾销。两个令牌都会被查询,任意一个的 disallow 都优先生效。

如果你的 robots.txt 已经写了这个停用令牌,不需要做任何改动。

robots.txtBash
# Already in your file? Leave it — it still blocks us.
User-agent: CrawlForge-Bot
Disallow: /

密码学验证(Web Bot Auth)

User-Agent 只是一种声明,任何人都可以发送我们的那一串。因此 CrawlForge 使用 Web Bot Auth 对外发请求签名:基于 HTTP 消息签名(RFC 9421)和一把 Ed25519 密钥,其公钥部分由我们公开发布。你无需联系我们、也无需任何白名单,就可以验证一个请求。

两个运行面都会签名。每个签名请求都携带 Signature-Input(被覆盖的组件与签名参数)、Signature(base64 编码的 Ed25519 签名)和 Signature-Agent(发布我们密钥的目录 URL)。

签名覆盖请求发往的 authority,以及在公布时的 Signature-Agent 值。它证明该请求来自持有我们私钥的一方。它不覆盖路径、请求体或 User-Agent,所以请把它当作*谁发的*的证明,而不是*请求了什么*的证明。

我们的签名目录

一个 JSON 密钥集,以 application/http-message-signatures-directory+json 提供,可缓存一天。注意 signatures 是复数。

the signature directoryBash
curl -sS https://www.crawlforge.dev/.well-known/http-message-signatures-directory

我们发送的请求头

参数列表由为我们的请求签名的同一个函数序列化生成。尖括号中的值每次请求都不同。请到目录中解析 `keyid`,不要把它写死:它是密钥的指纹,轮换密钥时会变。

request headersBash
Signature-Input: sig1=("@authority" "signature-agent");created=1787788800;keyid="<keyid — look it up in the directory>";alg="ed25519";expires=1787789100;nonce="<64 random bytes, base64>";tag="web-bot-auth"
Signature: sig1=:<base64 Ed25519 signature>:
Signature-Agent: "https://www.crawlforge.dev"

验证一个请求

用你收到的请求重建签名基串,再用已发布的公钥核验。Node 内置的 crypto 就够了;任何 RFC 9421 验证器做的都是同一件事。

verify.mjsJavascript
import { createPublicKey, verify } from 'node:crypto';

// `request` is the request you received; `signatureInput` and `signature`
// are its Signature-Input and Signature header values.

// 1. Fetch the directory and index the published keys by their thumbprint.
const { keys } = await fetch(
  'https://www.crawlforge.dev/.well-known/http-message-signatures-directory'
).then((r) => r.json());

// 2. Read the parameters off Signature-Input, dropping the "sig1=" label.
const params = signatureInput.replace(/^[^=]+=/, '');
const keyid = /keyid="([^"]+)"/.exec(params)?.[1];
const published = keys.find((k) => k.kid === keyid);
if (!published) throw new Error('keyid is not in the directory — not us');

// 3. Rebuild the signature base from the request you received. The covered
//    components are listed in the parentheses at the start of params.
const covered = /^\(([^)]*)\)/.exec(params)[1];
const lines = [`"@authority": ${request.headers.host}`];
if (covered.includes('"signature-agent"')) {
  lines.push(`"signature-agent": ${request.headers['signature-agent']}`);
}
lines.push(`"@signature-params": ${params}`);

// 4. Verify the Ed25519 signature (base64, between the colons).
const key = createPublicKey({
  key: { kty: 'OKP', crv: 'Ed25519', x: published.x },
  format: 'jwk',
});
const bytes = Buffer.from(
  signature.replace(/^[^=]+=:/, '').replace(/:$/, ''),
  'base64'
);
const ok = verify(null, Buffer.from(lines.join('\n'), 'utf8'), key, bytes);

// 5. Finally, reject a stale signature: params carries created= and expires=,
//    and we sign with a five-minute window.
没有签名的请求就是未通过验证 如果某个请求自称携带我们的 User-Agent 却没有签名——或者签名无法通过验证——那么对你而言它就不是 CrawlForge,你完全可以据此处理。请写信到 support@crawlforge.dev,我们会确认那些流量是否来自我们。

屏蔽 CrawlForge

一条 robots.txt 规则即可覆盖全部。组名就是产品令牌,两个运行面都以它进行匹配,因此这条规则会屏蔽两边的所有 CrawlForge 工具。

把它加进你的 robots.txt。下一次抓取即生效:我们在每次抓取开始时按来源读取一次该文件。

robots.txtBash
User-agent: CrawlForge
Disallow: /

我们不会对你隐瞒的部分

所有抓取工具都默认遵守 robots.txt。客户也可以在单次请求中传入 respect_robots: false:这个覆盖开关确实存在,有文档记载,而且是有意保留的——有些客户与被抓取的站点另有协议,把这个决定逼到暗处只会让它变得不可见,而不会让它变少。

它并不是悄无声息的。该覆盖只作用于一次请求,绝不作用于账户或整个产品。响应中会带上一条使用了覆盖的警告,请求也会在服务端记录为一条 robots_override 条目,包含 URL、工具名以及提出请求的 API 密钥的内部 ID——绝不包含密钥本身——因此有争议的抓取可以追溯到做出该选择的客户。

在这一切之下还有一层平台级排除,任何参数都触及不到它。如果一条 robots.txt 规则对你还不够,请改用排除通道。

出口 IP 地址

我们目前不公布出口 IP 地址清单。我们的托管 API 与浏览器后端运行在第三方基础设施上;在我们能够承诺一个下个月依然准确的地址段之前,公布一个只会比什么都不公布更糟——基于过期地址段建立的白名单会挡住真实流量,却对其他所有人敞开。等我们有了能够为之背书的清单,它会出现在本节。

无论如何,签名验证都是更可靠的检查。地址段只能证明数据包从哪里发出,而任何能在该段内租到地址的人都会一并继承这个声明;常见的补救办法——再加一次反向 DNS 查询——证明的是对某个主机名的控制权,而不是对这个请求的控制权。Ed25519 签名证明的是持有那把私钥,其公钥就在我们的目录中;即便我们更换托管商它依然有效,也无法被重放到另一个 authority 上。

如果就你方的商务安排而言签名还不够,请写信到 support@crawlforge.dev 说明你的需求。

排除与下架请求

如需在平台层面被永久排除——覆盖所有工具、所有 API 密钥和所有套餐,且没有任何客户端参数可以推翻——请写信到 support@crawlforge.dev,说明域名和相关页面。同一地址也处理下架请求,以及你认为来自我们的流量的任何疑问。

相关文档
CrawlForge 抓取时的行为,以及面向客户的条款。
抓取器运行规则
本页背后的八条基本规则、每条规则的理由,以及它们如何落实。
可接受使用政策
客户使用 API 时可以做什么、不可以做什么:禁止的行为、违规处理与举报。
隐私政策
我们收集哪些信息,以及保留多久。

页脚

CrawlForge MCP

面向 AI Agent 的企业级网页抓取。29 个专业 MCP 工具,专为构建智能系统的现代开发者而设计。

产品

  • 功能
  • Playground
  • 价格
  • 应用场景
  • 集成
  • 替代方案
  • 更新日志

资源

  • 快速上手
  • API 参考
  • 模板
  • 指南
  • 博客
  • 术语表
  • 常见问题
  • 网站地图

开发者

  • MCP 协议
  • Claude Desktop
  • Cursor IDE
  • LangChain
  • LlamaIndex

公司

  • 关于我们
  • 联系我们
  • 隐私政策
  • 服务条款
  • 可接受使用政策
  • Cookie

保持更新

获取新工具和新功能的最新动态。

基于 Next.js 和 MCP 协议构建

© 2025-2026 CrawlForge。保留所有权利。