トークン認証を使うと、ユーザー登録なしで、文書、ファイル、メディアへのアクセスを特定の利用者に限定できます。有料コンテンツや閲覧制限のあるコンテンツの無断取得と不正な共有を防ぐのに役立ちます。
トークン認証の設定方法は 2 つあります。Cloudflare Workers を使う方法と、カスタムルールを使う方法です。
トークン認証の実装例として、次の Cloudflare Workers の資料を参照してください。
- Sign requests の例
- Auth with headers のテンプレート
Workers を始めるには、テンプレート を参照してください。
Rules 言語の 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%3DEnterprise プランの場合は、次の手順で、オリジンサーバー上の URL 生成が正しいかを確認できます。
- カスタムルールのアクションを Log に設定します。
- Security Events のサンプリングログを確認します。
同じシークレットキーで、複数の URI パスを保護できます。
前の例では、検証関数の MessageMAC 引数に http.request.uri を渡しています。
http.request.uri にはアセットのパスが含まれ、リクエストごとにその値が取り出されます。そのため、検証関数は同じシークレットキーで、downloads.example.com へのすべてのリクエスト URI を評価します。
同じシークレットキーで複数のパスを認証できますが、認証したいメッセージごとに HMAC トークンを生成する必要があります。
固定長の URI パスプレフィックス全体を、1 つの HMAC 署名で保護できます(シークレットも同じものを使います)。そのためには、is_timed_hmac_valid_v0() 関数の MessageMAC 引数に、完全な URI パスではなく URI パスプレフィックスと、元のクエリ文字列を渡します。
完全な URI パスからプレフィックスを取り出すには、substring() 関数を使います。
次の例では、1 つの 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最初の 2 つの URI パスは、カスタムルールが検証する同じ 51 文字のプレフィックス(/case-studies/12345678-90ab-4cde-f012-3456789abcde/)を共有するため、同じ HMAC 署名を使えます。
3 つ目の URI パスはプレフィックスが異なるため、別の HMAC 署名が必要です。