リクエストに署名する
HMACおよびSHA-256アルゴリズムを使用して署名されたリクエストを検証するか、403を返します。
次のスニペットは以下のことを行います:
-
/generate/で始まるリクエストURLの場合、/generate/を/に置き換え、結果のパスにタイムスタンプを付加して署名し、レスポンスボディに完全な署名付きURLを返します。 -
その他のすべてのリクエストURLについては、署名されたURLを検証し、リクエストを通過させます。
export default { async fetch(request) { const secretKey = "your_secret_key"; // 実際の秘密鍵に置き換えてください const expiration = 60; // 有効期限(HMACトークンが有効であるべき時間、秒単位)
const encoder = new TextEncoder();
// HMAC-SHA256署名用の秘密鍵をインポート const key = await crypto.subtle.importKey( "raw", encoder.encode(secretKey), { name: "HMAC", hash: "SHA-256" }, false, ["sign", "verify"], );
const url = new URL(request.url);
// リクエストURLが/generate/で始まるか確認 if (url.pathname.startsWith("/generate/")) { // /generate/を/に置き換え url.pathname = url.pathname.replace("/generate/", "/");
const currentTimestamp = Math.floor(Date.now() / 1000); // 現在のタイムスタンプ(秒単位)
// 認証するデータ:パス名とタイムスタンプを結合 const dataToAuthenticate = `${url.pathname}${currentTimestamp}`;
// HMAC-SHA256でデータに署名 const signature = await crypto.subtle.sign( "HMAC", key, encoder.encode(dataToAuthenticate), );
// タイムスタンプとHMACを安全にエンコード const signatureBase64 = btoa( String.fromCharCode(...new Uint8Array(signature)), ); const signedData = `${currentTimestamp}-${signatureBase64}`; const encodedSignedData = encodeURIComponent(signedData);
// 署名付きURLを作成 const signedURL = `${url}?verify=${encodedSignedData}`;
// レスポンスボディに署名付きURLを返す return new Response(signedURL, { status: 200 }); }
// その他のすべてのリクエストURLについて、署名されたURLを検証 const params = new URLSearchParams(url.search); const verifyParam = params.get("verify");
if (!verifyParam) { return new Response("検証パラメータが欠落しています", { status: 403 }); }
// 検証パラメータをデコードし、タイムスタンプとHMACに分割 const decodedVerifyParam = decodeURIComponent(verifyParam); const [timestampStr, receivedMac] = decodedVerifyParam.split("-");
// タイムスタンプを解析し、有効な数値であることを確認 const timestamp = parseInt(timestampStr, 10); if (isNaN(timestamp)) { return new Response("無効なタイムスタンプ", { status: 403 }); }
// リクエストが期限切れか確認 const currentTimestamp = Math.floor(Date.now() / 1000); if (currentTimestamp > timestamp + expiration) { return new Response("署名付きURLは期限切れです", { status: 403 }); }
// URLを検証するために検証パラメータを削除 params.delete("verify"); url.search = params.toString();
// 検証のために認証するデータを構築 const dataToVerify = `${url.pathname}${timestamp}`;
// HMAC-SHA256で署名を検証 const isValid = await crypto.subtle.verify( "HMAC", key, new Uint8Array([...atob(receivedMac)].map((char) => char.charCodeAt(0))), encoder.encode(dataToVerify), );
if (!isValid) { return new Response("無効な署名", { status: 403 }); }
// 署名が有効な場合、リクエストの処理を続行 return fetch(request); },};