timingSafeEqualの使用
`timingSafeEqual`を使用して値を安全に比較することで、タイミング攻撃から保護します。
crypto.subtle.timingSafeEqual 関数は、定数時間アルゴリズムを使用して2つの値を比較します。かかる時間は、値の内容に依存しません。
文字列を等価演算子(== または ===)を使用して比較すると、比較は最初の不一致の文字で終了します。timingSafeEqualを使用することで、攻撃者はタイミングを利用して2つの文字列のどのポイントに違いがあるかを見つけることができなくなります。
timingSafeEqual関数は、比較する2つのArrayBufferまたはTypedArray値を受け取ります。これらのバッファは同じ長さでなければならず、そうでない場合は例外がスローされます。
この関数は、パラメータの長さに関して定数時間ではなく、周囲のコードに対しても定数時間を保証しないことに注意してください。
秘密情報の取り扱いには、タイミングサイドチャネルを導入しないように注意が必要です。
2つの文字列を比較するには、TextEncoder APIを使用する必要があります。
interface Environment { MY_SECRET_VALUE?: string;}
export default { async fetch(req: Request, env: Environment) { if (!env.MY_SECRET_VALUE) { return new Response("秘密バインディングがありません", { status: 500 }); }
const authToken = req.headers.get("Authorization") || "";
if (authToken.length !== env.MY_SECRET_VALUE.length) { return new Response("未認証", { status: 401 }); }
const encoder = new TextEncoder();
const a = encoder.encode(authToken); const b = encoder.encode(env.MY_SECRET_VALUE);
if (a.byteLength !== b.byteLength) { return new Response("未認証", { status: 401 }); }
if (!crypto.subtle.timingSafeEqual(a, b)) { return new Response("未認証", { status: 401 }); }
return new Response("ようこそ!"); },};from js import Response, TextEncoder, crypto
async def on_fetch(request, env): auth_token = request.headers["Authorization"] or "" secret = env.MY_SECRET_VALUE
if secret is None: return Response.new("秘密バインディングがありません", status=500)
if len(auth_token) != len(secret): return Response.new("未認証", status=401)
if a.byteLength != b.byteLength: return Response.new("未認証", status=401)
encoder = TextEncoder.new() a = encoder.encode(auth_token) b = encoder.encode(secret)
if not crypto.subtle.timingSafeEqual(a, b): return Response.new("未認証", status=401)
return Response.new("ようこそ!")