令牌身份验证可让您将文档、文件和媒体的访问限制给选定用户,而无需要求其注册。这有助于保护付费/受限内容免遭盗链和未经授权的分享。
配置令牌身份验证有两种选项:通过 Cloudflare Workers 或通过自定义规则。
有关令牌身份验证的两种不同实现,请参阅以下 Cloudflare Workers 资源:
- Sign requests 示例。
- Auth with headers 模板。
要开始使用 Workers,请参阅 Templates。
使用规则语言 is_timed_hmac_valid_v0() HMAC 验证函数,在自定义规则表达式中验证基于哈希的消息身份验证码(HMAC)令牌。
要验证令牌身份验证,请创建自定义规则,在规则表达式中调用 is_timed_hmac_valid_v0() 函数。可使用例如 Block 等操作。
本示例说明一条规则:在特定主机名和 URL 路径上,对未通过 HMAC 密钥验证的任何访问者进行阻止。令牌身份验证所需详情包括:
- 用于生成和验证 HMAC 的密钥(例如
mysecrettoken) - 您希望进行身份验证的路径(例如
downloads.example.com/images/cat.jpg) - 包含令牌的查询字符串参数名称(例如
verify) - 令牌生命周期(秒)(例如 3 小时 = 10,800 秒)
考虑以下示例 URL:
downloads.example.com/images/cat.jpg?verify=1484063787-9JQB8vP1z0yc5DEBnH6JGWM3mBmvIeMrnnxFi3WtJLE%3D其中:
/images/cat.jpg表示资产路径——要验证的 HMAC 消息。?verify=是资产路径与 HMAC 令牌签发时间戳之间的分隔符。1484063787表示令牌签发时的时间戳,以 UNIX 时间(秒)表示。9JQB8vP1z0yc5DEBnH6JGWM3mBmvIeMrnnxFi3WtJLE%3D是 Base64 编码的 MAC。
自定义规则的表达式类似于:
(http.host eq "downloads.example.com" and not is_timed_hmac_valid_v0("mysecrettoken", http.request.uri, 10800, http.request.timestamp.sec, 8))此示例自定义规则的组成部分(使用前面的示例 URL)包括:
- 令牌密钥 =
mysecrettoken - 令牌生命周期 =
10800(10,800 秒 = 3 小时) http.request.uri=/images/cat.jpg?verify=1484063787-9JQB8vP1z0yc5DEBnH6JGWM3mBmvIeMrnnxFi3WtJLE%3Dhttp.request.timestamp.sec=1484071925(例如)- 分隔符长度:
len("?verify=")=8
is_timed_hmac_valid_v0() 函数将使用 mysecrettoken 密钥生成的 MAC 值与编码在 http.request.uri 中的值进行比较。
若 MAC 值匹配,且根据以下公式令牌尚未过期:
http.request.timestamp.sec < (<TIMESTAMP_ISSUED> + 10800)则令牌有效,is_timed_hmac_valid_v0() 函数返回 true。
以下示例展示如何在源站服务器上,为上一节自定义规则所验证的路径生成令牌:
import hmac
import base64
import time
import urllib.parse
from hashlib import sha256
message = "/images/cat.jpg"
secret = "mysecrettoken"
separator = "verify"
timestamp = str(int(time.time()))
digest = hmac.new((secret).encode('utf8'), "{}{}".format(message, timestamp).encode('utf8'), sha256)
token = urllib.parse.quote_plus(base64.b64encode(digest.digest()))
print("{}={}-{}".format(separator, timestamp, token))import hmac
import base64
import time
import urllib
from hashlib import sha256
message = "/images/cat.jpg"
secret = "mysecrettoken"
separator = "verify"
timestamp = str(int(time.time()))
digest = hmac.new(secret, message + timestamp, sha256)
param = urllib.urlencode({separator: '%s-%s' % (timestamp, base64.b64encode(digest.digest()))})
print(param)<?php
$message = "/images/cat.jpg";
$secret = "mysecrettoken";
$separator = "verify";
$timestamp = time();
$token = urlencode(base64_encode(hash_hmac("sha256", $message . $timestamp, $secret, true)));
echo("{$separator}={$timestamp}-{$token}");有关 JavaScript (JS) 或 TypeScript (TS) 的完整示例,请参阅 Workers 文档中的 Sign requests 示例。
由于该示例 JS/TS 实现与 is_timed_hmac_valid_v0() 函数兼容,使用所提供源代码进行身份验证的请求可通过 WAF 自定义规则和 is_timed_hmac_valid_v0() 函数进行验证。
这将生成类似如下的 URL 参数:
verify=1484063787-9JQB8vP1z0yc5DEBnH6JGWM3mBmvIeMrnnxFi3WtJLE%3D您需要将此参数附加到受保护的 URL:
/images/cat.jpg?verify=1484063787-9JQB8vP1z0yc5DEBnH6JGWM3mBmvIeMrnnxFi3WtJLE%3D若您使用 Enterprise 计划,可通过以下方式测试源站服务器是否正确生成 URL:
- 将自定义规则操作设为 Log。
- 在 Security Events 中检查采样日志。
您可以使用同一密钥保护多个 URI 路径。
这在前面的示例中有说明,其中 http.request.uri 作为 MessageMAC 参数传递给验证函数。
由于 http.request.uri 包含资产路径,且该值会为每个请求提取,验证函数会使用同一密钥评估到 downloads.example.com 的所有请求 URI。
请注意,虽然您可以使用同一密钥验证多个路径,但必须为要验证的每条唯一消息生成一个 HMAC 令牌。
您可以用单个 HMAC 签名保护整个固定长度的 URI 路径前缀(也会使用同一密钥)。为此,请提供 URI 路径前缀(而不是完整 URI 路径)以及原始查询字符串,作为 is_timed_hmac_valid_v0() 函数的 MessageMAC 参数。
使用 substring() 函数从完整 URI 路径获取前缀。
在以下示例中,需要单个 HMAC 签名的 URI 路径前缀始终为 51 个字符长(x 为字符占位符):
/case-studies/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/在此情况下,您需要对每个不同的 51 字符长度 URI 路径前缀使用不同的 HMAC 签名。
若要阻止未通过 HMAC 验证的案例研究文件请求,可创建类似如下的自定义规则:
规则表达式:
(http.host eq "downloads.example.com" and starts_with(http.request.uri.path, "/case-studies") and not is_timed_hmac_valid_v0("mysecrettoken", concat(substring(http.request.uri.path, 0, 51), "?", http.request.uri.query), 10800, http.request.timestamp.sec, 1))操作:
- Block
有效传入请求的示例 URI 路径:
/case-studies/12345678-90ab-4cde-f012-3456789abcde/foobar-report.pdf?1755877101-5WOroVcDINdl2%2BQZxZFHJcJ6l%2Fep4HGIrX3DtSXzWO0%3D
/case-studies/12345678-90ab-4cde-f012-3456789abcde/acme-corp.pdf?1755877101-5WOroVcDINdl2%2BQZxZFHJcJ6l%2Fep4HGIrX3DtSXzWO0%3D
/case-studies/768bf477-22d5-4545-857d-b155510119ff/another-company-report.pdf?1755878057-jeMS5S1F3MIgxvL61UmiX4vODiWtuLfcPV6q%2B0Y3Rig%3D前两个 URI 路径可使用同一 HMAC 签名,因为它们共享自定义规则验证的相同 51 字符前缀(/case-studies/12345678-90ab-4cde-f012-3456789abcde/)。
第三个 URI 路径需要不同的 HMAC 签名,因为前缀不同。