Overview
Basic Concepts
Quick Start
Manage Functions In Edge Cloud Apps
Function Deployment
Trigger Your Functions
Edge KV
Developer Tools
Examples
Examples Overview
Page Rewriting
Terminal-Based Content Adaptation
Edge Rendering
Edge Website Building
Request Signature and Legitimacy Verification
Multilingual Support with WASM
Site Proxy
Websocket Interaction
Virtual Waiting Room
Runtime APIs
CloudIDE
Limits
CDNetworks ドキュメントセンター Edge Application Developer Tools Request Signature and Legitimacy Verification

Request Signature and Legitimacy Verification

最終更新日:2024-09-03 17:00:38

この例では、Edge Cloud Apps関数Web Crypto APIを使用して、特定のWebサイトリソースへのアクセスを保護する方法を示します。実例として、http://ecatest.cdnetworks.com/ECA-test/pet-shop-website-template/about.htmlにあるペットショップの「会社概要」ページを使用します。このページにアクセスするには、HMACおよびSHA-256アルゴリズムを使用して生成された有効な署名が必要です。Edge Cloud Apps関数は、クライアントに代わって送信リクエストに署名したり、受信した署名付きリクエストを検証したりして、セキュリティゲートキーパーとして機能できます。権限のないリクエストは、エラーページに遭遇します。

利点

  • **セキュリティの強化:**暗号化署名を使用すると、不正アクセスを効果的に防止し、機密性の高いWebサイトリソースを保護できます。
  • **エッジ暗号化:**Edge Cloud Apps関数とWeb Crypto APIを活用することで、エッジで直接暗号化操作を実行できるようになり、レイテンシーが短縮され、効率が向上します。
  • **柔軟な制御:**開発者は、署名アルゴリズムと検証ロジックをカスタマイズして、特定の要件に基づいて柔軟なアクセス制御戦略を実装できます。

コード例

const SECRET_KEY = "my secret symmetric key";

// リクエストを処理し、リクエストメソッドに基づいて署名または検証を行います
async function handleRequest(request) {
    if (request.method === "POST") {
        return signRequest(request);
    } else {
        return verifyRequest(request);
    } 
}

// リクエスト署名を検証します
async function verifyRequest(request) {
    const url = new URL(request.url);

    // リクエストに必要なクエリパラメータが含まれていることを確認します
    if (!url.searchParams.has("mac") || !url.searchParams.has("expiry")) {
        return failPage("クエリパラメータがありません");
    }

    const encoder = new TextEncoder();
    const secretKeyData = encoder.encode(SECRET_KEY);

    // 署名検証のためにキーをインポートします
    const key = await crypto.subtle.importKey(
        "raw",
        secretKeyData,
        { name: "HMAC", hash: "SHA-256" },
        false,
        ["verify"],
    );

    // 検証が必要なデータの抽出:パスと有効期限のタイムスタンプ
    const expiry = Number(url.searchParams.get("expiry"));
    const dataToAuthenticate = url.pathname + expiry;

    // 受信したBase64エンコードされたMACをUint8Arrayに変換します
    const receivedMacBase64 = url.searchParams.get("mac");
    const receivedMac = byteStringToUint8Array(atob(receivedMacBase64));

    // タイミング攻撃を防ぐためにcrypto.subtle.verify()を使用して署名を検証します
    const verified = await crypto.subtle.verify(
        "HMAC",
        key,
        receivedMac,
        encoder.encode(dataToAuthenticate),
    );

    // 検証に失敗した場合は、エラーページを返します
    if (!verified) {
        return failPage("無効なMAC");
    }

    // URLの有効期限が切れているかどうかを確認します
    if (Date.now() > expiry) {
        return failPage(`${new Date(expiry)}にURLの有効期限が切れました`);
    }

    // 検証に成功しました。リソースへのアクセスを許可します
    return fetch(request);
}

// ByteStringをUint8Arrayに変換します
function byteStringToUint8Array(byteString) {
    const ui = new Uint8Array(byteString.length);
    for (let i = 0; i < byteString.length; ++i) {
        ui[i] = byteString.charCodeAt(i);
    }
    return ui;
}

// リクエストに署名します
async function signRequest(request) {
    const url = new URL(request.url);
    return generateSignedUrl(url);
}

// 署名付きURLを生成します
async function generateSignedUrl(url) {
    // 署名生成のためにキーをインポートします
    const encoder = new TextEncoder();
    const secretKeyData = encoder.encode(SECRET_KEY);
    const key = await crypto.subtle.importKey(
      "raw",
      secretKeyData,
      { name: "HMAC", hash: "SHA-256" },
      false,
      ["sign"],
    );
  
    // URLの有効期限を設定します
    const expirationMs = 18000; // 18秒
    const expiry = Date.now() + expirationMs;
    const dataToAuthenticate = url.pathname + expiry;
  
    // 署名を生成します
    const mac = await crypto.subtle.sign("HMAC", key, encoder.encode(dataToAuthenticate));
  
    // 署名をBase64エンコードされた文字列に変換します
    const base64Mac = btoa(String.fromCharCode(...new Uint8Array(mac)));
  
    // 署名と有効期限をURLクエリパラメータに追加します
    url.searchParams.set("mac", base64Mac);
    url.searchParams.set("expiry", expiry);
  
    return new Response(url);
  }

// エラーページを生成します
function failPage(msg) {
    let page = FAILPAGE.replace('{{error-msg}}', msg);
    return new Response(page, {headers: {"Content-Type": "text/html; charset=utf-8"}});
}

// エラーページのHTMLテンプレート
const FAILPAGE = `
<!DOCTYPE html>
<html>
<head>
<title>エラーページ</title>
<style>
// ... ページスタイル ... 
</style>
</head>
<body>
<div class="container">
<h1>エラー</h1>
<p>アクセスしようとしているURLは正しく署名されていません: {{error-msg}}</p>
<div class="url-section">
    <div class="url-wrapper">
        <p><span class="url-display" id="current-url" style="display: block;"></span></p>
    </div>
    <div class="button-wrapper">
        <button class="url-button" type="button" onclick="getSignedUrl()">URLに署名する</button>
    </div>
    <div class="url-wrapper" id="signed-url-section">
        <p><strong>署名付きURLは18秒後に期限切れになります</strong></p>
        <p><span class="url-display" id="signed-url"></span></p>
    </div>
</div>
</div>

<script>
// ... ページスクリプト ... 
</script>
</body>
</html>
`;
                    
addEventListener("fetch", event => {
    return event.respondWith(handleRequest(event.request));
});

注意

Edge Cloud Apps関数は、Web Crypto APIを完全にサポートしており、エッジでの暗号化と復号化のニーズを満たすことができます。Edge Cloud Apps関数を使用して、クライアントに代わってリクエストに署名したり、受信した署名付きリクエストを検証したりすることで、不正アクセス(ホットリンク保護)を効果的に防止できます。