跳转到内容
搜索文档

Web Bot Auth

最后更新 查看 MarkdownAgent 设置

Web Bot Auth 是一种身份验证方法,它利用 HTTP 消息中的密码学签名来验证请求是否来自自动化 bot。Web Bot Auth 用作已验证的 bot 和代理的验证方法。

它依赖于 IETF 草案:一个目录草案 (directory draft) 允许爬虫共享其公钥,以及一个协议草案 (protocol draft) 定义如何使用这些密钥将爬虫的身份附加到 HTTP 请求中。

本篇文档介绍了 Cloudflare 内部的具体集成方法。

1. 生成有效的签名密钥

您需要生成一个签名密钥,用于对您的 bot 请求进行身份验证。

  1. 生成唯一的 Ed25519 私钥以对您的请求进行签名。此示例使用 OpenSSL genpkey 命令:

    openssl genpkey -algorithm ed25519 -out private-key.pem
  2. 提取您的公钥。

    openssl pkey -in private-key.pem -pubout -out public-key.pem
  3. 使用您选择的工具将公钥转换为 JSON Web Key (JWK)。此示例使用 jwker 命令行应用程序。

    go install github.com/jphastings/jwker/cmd/jwker@latest
    jwker public-key.pem public-key.jwk

通过按照这些步骤操作,您已生成了一个私钥和一个公钥,然后将公钥转换为了 JWK。

2. 托管密钥目录

您需要托管一个密钥目录,为您的 bot 创造一种向 Cloudflare 验证其请求的方式。 该目录应符合 draft-meunier-http-message-signatures-directory-03 中的定义。

  1. /.well-known/http-message-signatures-directory 托管密钥目录(注意,这是一项要求)。该密钥目录应提供一个 JSON Web Key Set (JWKS),其中包含从您的签名密钥导出的公钥。

  2. 通过 HTTPS(而非 HTTP)提供该网页。

  3. 计算与您的 Ed25519 公钥关联的 Base64 URL 编码的 JWK 指纹 (thumbprint)

  4. 使用 HTTP 消息签名规范对您的 HTTP 响应进行签名,密钥目录中的每个密钥对应一个签名。这可确保没有其他人可以镜像您的目录并尝试代表您进行注册。您的响应必须包含以下标头:

    • Content-Type:此标头的值必须为 application/http-message-signatures-directory+json
    • Signature:在您选择的组件上构建 Signature 标头
    • Signature-Input:在您选择的组件上构建 Signature-Input 标头。该标头必须满足以下要求。
      必需组件/参数 要求
      tag 这应等于 http-message-signatures-directory
      keyid 您的目录中对应密钥的 JWK 指纹。
      created 这应等于与您的应用程序发送消息时关联的 Unix 时间戳。
      expires 这应等于与 Cloudflare 不应再尝试验证消息时关联的 Unix 时间戳。
      @authority 这应等于请求发送的 Host 标头的值。您应该设置 req 组件参数

    以下示例显示了针对 https://example.com 且带有必需标头的带注释的请求和响应。此处的 Signature 值纯粹是为了说明目的,而不是实际生成的签名。

    GET /.well-known/http-message-signatures-directory HTTP/1.1
    Host: example.com
    Accept: application/http-message-signatures-directory+json
    
    HTTP/1.1 200 OK
    Content-Type: application/http-message-signatures-directory+json
    Signature: sig1=:TD5arhV1ved6xtx63cUIFCMONT248cpDeVUAljLgkdozbjMNpJGr/WAx4PzHj+WeG0xMHQF1BOdFLDsfjdjvBA==:
    Signature-Input: sig1=("@authority";req);alg="ed25519";keyid="poqkLGiymh_W0uP6PZFw-dvez3QJT5SolqXBCW38r0U";nonce="ZO3/XMEZjrvSnLtAP9M7jK0WGQf3J+pbmQRUpKDhF9/jsNCWqUh2sq+TH4WTX3/GpNoSZUa8eNWMKqxWp2/c2g==";tag="http-message-signatures-directory";created=1750105829;expires=1750105839
    Cache-Control: max-age=86400
    {
      "keys": [{
        "kty": "OKP",
        "crv": "Ed25519",
        "x": "JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs", // Base64 URL-encoded public key, with no padding
      }]
    }

您可以使用 Cloudflare 开发的 http-signature-directory 命令行工具来帮助您验证您的目录。

3. 注册您的 bot 和密钥目录

您需要注册您的 bot 及其密钥目录,以将您的 bot 添加到已验证 bot 列表中。

  1. 登录到 Cloudflare 仪表板,然后选择您的账户和域。
  2. 前往 Manage Account(管理账户) > Configurations(配置)
  3. 前往 Bot Submission Form(Bot 提交表单) 选项卡。
  4. 对于 Verification Method(验证方法):选择 Request Signature(请求签名)
  5. 对于 Validation Instructions(验证说明):输入您的密钥目录 URL。您还可以提供将由您的 bot 发送的用户代理 (User Agents) 值(及其匹配模式)。
  6. 选择 Submit(提交)

Cloudflare 接受在您的密钥目录中找到的所有有效 Ed25519 密钥。如果 Cloudflare 的注册数据库中已存在某个密钥,Cloudflare 将与您合作提供新密钥,或轮换您的现有密钥。

验证成功后,您将能够发送已验证的请求。

4. (验证后)对您的请求进行签名

在您的 bot 成功通过验证后,您的 bot 就可以对其请求进行签名了。签名协议在 draft-meunier-web-bot-auth-architecture-02 中定义。

4.1. 选择一组要签名的组件

选择一组要签名的组件。

组件要么是 HTTP 标头,要么是 HTTP 消息签名规范中的任何派生组件 (derived components)。Cloudflare 建议执行以下操作:

  • 至少选择 @authority 派生组件,它表示您要向其发送请求的域名。例如,发送到 https://example.com 的请求将被解释为具有 example.com@authority
  • 使用仅包含 ASCII 值的组件。HTTP 消息签名规范不允许使用非 ASCII 字符,否则会导致无法验证您的 bot 请求。

4.2. 计算 JWK 指纹

根据您在 Cloudflare 注册的公钥,计算 Base64 URL 编码的 JWK 指纹 (thumbprint)

4.3. 构建所需的标头

为 Web Bot Auth 构建三个必需的标头。

Signature-Input 标头

在您选择的组件上构建 Signature-Input 标头。该标头必须满足以下要求。

必需组件参数 要求
tag 这应等于 web-bot-auth
keyid 这应等于第 2 步中计算的指纹。
created 这应等于与您的应用程序发送消息时关联的 Unix 时间戳。
expires 这应等于与 Cloudflare 不应再尝试验证消息时关联的 Unix 时间戳。较短的 expires 可以降低重放攻击的可能性,Cloudflare 建议选择合适的短期时间间隔。

Signature 标头

在您选择的组件上构建 Signature 标头

Signature-Agent 标头

构建指向您的密钥目录的 Signature-Agent 标头。Cloudflare 实现了来自 draft-meunier-http-message-signatures-directory-03Signature-Agent 格式,其中标头值是一个结构化字符串,例如 "https://signature-agent.test"

在以下情况下,Cloudflare 将无法验证消息:

  • 消息包含的 Signature-Agent 标头不是 https://
  • 消息包含有效的 URI,但未用双引号将其括起来。这是由于 Signature-Agent 是一个结构化字段。
  • 消息使用了后期草案中的字典形式,例如 sig2="https://signature-agent.test"
  • 消息具有有效的 Signature-Agent 标头,但在 Signature-Input 的组件列表中未包含它。

4.4. 将标头添加到您的 bot 请求中

将这三个标头附加到您的 bot 请求中。

示例请求可能如下所示:

Signature-Agent: "https://signature-agent.test"
Signature-Input: sig2=("@authority" "signature-agent")
 ;created=1735689600
 ;keyid="poqkLGiymh_W0uP6PZFw-dvez3QJT5SolqXBCW38r0U"
 ;alg="ed25519"
 ;expires=1735693200
 ;nonce="e8N7S2MFd/qrd6T2R3tdfAuuANngKI7LFtKYI/vowzk4lAZYadIX6wW25MwG7DCT9RUKAJ0qVkU0mEeLElW1qg=="
 ;tag="web-bot-auth"
Signature: sig2=:jdq0SqOwHdyHr9+r5jw3iYZH6aNGKijYp/EstF4RQTQdi5N5YYKrD+mCT1HA1nZDsi6nJKuHxUi/5Syp3rLWBA==:

传递信任与 Forwarded 标头

到达您的站点的代理通常不是由构建它的公司运行的。一个平台可以代表许多不同的最终用户运行自动化,因此运营商和最终用户并不是同一方。Cloudflare 将此链 — 网站所有者 → bot 运营商 → 最终用户 — 称为传递信任 (transitive trust)

为了在该链中携带运营商的身份,Cloudflare 正在尝试使用 RFC 7239 中定义的 Forwarded 标头。这就像用于 IP 地址的 X-Forwarded-For 一样工作:无论该运营商是直接还是通过 Cloudflare 信任的中介机构到达您,允许运营商的偏好都会保留。

运营商使用 for 参数标识:

Forwarded: for="openai"

该标头还可以携带运营商针对其访问的内容所承诺的 content-use 值:

Forwarded: for="openai";use="reference"

限制

Cloudflare 的 Web Bot Auth 实现不支持 IETF RFC 9421 中定义的所有组件和参数。如果您在请求的 Signature-Input 标头中包含以下任何内容,验证将失败。

  • @query-params:Cloudflare 建议使用 @query 组件对整个查询进行签名,而不是对单个参数进行签名。
  • @status:这不可能包含在请求路径中。

不支持 IETF RFC 9421 中定义的以下组件参数,如果包含它们,Cloudflare 将无法验证消息:

  • sf(用于 HTTP 标头字段)
  • bs(用于 HTTP 标头字段)
  • key(用于 HTTP 标头字段)
  • req(用于 HTTP 标头字段或派生组件)
  • name(用于 @query-param 支持 - 这需要 @query-param 支持)

故障排除

消息验证失败

如果您的消息验证失败,原因可能包括:

  • 确保您具有 Signature-Agent 标头,并且其值在双引号中。
  • 确保您的 Signature-Agent 标头使用结构化字符串,而不是字典。
  • 确保在 Signature-Input 标头的组件列表中包含了 signature-agent
  • 确保您的 expires 时间戳不要太短,以至于当它到达 Cloudflare 服务器时已经过期。一分钟通常就足够了。
  • 确保您没有对包含非 ASCII 值的组件或在不支持列表上的组件进行签名。

在没有 Cloudflare 验证的区域上使用 HTTP 消息签名/Web Bot Auth

如果您希望在您自己的源站处理中使用 HTTP 消息签名 (Web Bot Auth),并且不希望 Cloudflare 的验证介入或填充 cf.bot_management.verified_bot 字段,您可以请求为您的区域禁用 Cloudflare 验证功能。

要禁用 Web Bot Auth 验证,请联系 Cloudflare 支持

禁用此功能意味着 Cloudflare 将不验证传入的签名。已验证的 bot 将回退到其他方法(例如反向 DNS 验证)来确定流量是否合法。

更多资源

您可能希望参考以下资源。

这篇文档对您有帮助吗?