演習 - シークレットを使用して Webhook ペイロードをセキュリティで保護する

完了

この演習では、シークレットを使って Webhook のペイロードをセキュリティで保護し、また Azure Function を使ってペイロードが実際に GitHub からのものであることを検証する方法を学習します。

Azure 関数のキーを取得する

  1. Azure portal で、モジュールの最初の演習で作成した関数アプリに戻ります。

  2. 左側のメニュー ペインの [関数] で、[関数] を選択します。 "関数アプリ" の [関数] ペインが表示されます。

  3. 作成した HttpTrigger1 を選択します。 "関数" の [HtttpTrigger1] ペインが表示されます。

  4. 左側のメニュー ウィンドウの [開発者] で、[コードとテスト] を選択します。 "関数" の [コード + テスト] ペインが表示されます。

  5. 関数の index.js JavaScript ファイルで、ファイルの先頭の module.exports ステートメントの上に crypto-js ライブラリへの参照を追加します。

    const Crypto = require('crypto');
    
  6. 上部のメニュー バーで、[保存] を選択します。 ペインの下部に [ログ] ペインが表示されます。

  7. 左側のメニュー ウィンドウの [開発者] で、[関数キー] を選択します。 "関数" の [Function Keys](関数キー) ペインが表示されます。

  8. [値] 列で、[値の表示] リンクを選択します。

  9. [クリップボードにコピー] アイコンを選択し、次の手順で使用するためにこのキーを保存します。

  10. 左側のメニュー ウィンドウの [開発者] で、[コードとテスト] を選択します。 "関数" の [コード + テスト] ペインが表示されます。

  11. コード ブロックの context.log ステートメントの後に、次のコードを追加します。 "<既定のキー>" は、クリップボードにコピーしたばかりの既定のキーに置き換えます。

    const hmac = Crypto.createHmac("sha1", "<default key>");
    const signature = hmac.update(JSON.stringify(req.body)).digest('hex');
    

    このコードでは、GitHub と同じメカニズムを使用してキーのハッシュを計算します。

  12. 要求ヘッダーの x-hub-signature の形式と一致するように、キーの先頭の前に sha1= を追加する別の const を追加します。 関数に次のコードを追加します。

    const shaSignature = `sha1=${signature}`;
    
  13. 次のコードを追加して、要求ヘッダーから GitHub の署名を取得します。

    const gitHubSignature = req.headers['x-hub-signature'];
    
  14. 2 つの文字列を比較します。 一致する場合は、次のように要求を処理します。

    if (!shaSignature.localeCompare(gitHubSignature)) {
        // Existing code
        if (req.body.pages[0].title) {
            ...
        }
        else {
            ...
        }
    }
    
  15. 文字列が一致しない場合は、署名が一致しないことを送信者に知らせるメッセージと共に、HTTP 401 (Unauthorized) 応答が返されます。

    if (!shaSignature.localeCompare(gitHubSignature))
    {
        ...
    }
    else {
        context.res = {
            status: 401,
            body: "Signatures don't match"
        };
    }
    
    

    完成した関数は次のようになります。

    const Crypto = require('crypto');
    
    module.exports = async function (context, req) {
        context.log('JavaScript HTTP trigger function processed a request.');
    
        const hmac = Crypto.createHmac("sha1", "<default key>");
        const signature = hmac.update(JSON.stringify(req.body)).digest('hex');
        const shaSignature =  `sha1=${signature}`;
        const gitHubSignature = req.headers['x-hub-signature'];
    
        if (!shaSignature.localeCompare(gitHubSignature)) {
            if (req.body.pages[0].title) {
                context.res = {
                    body: "Page is " + req.body.pages[0].title + ", Action is " + req.body.pages[0].action + ", Event Type is " + req.headers['x-github-event']
                };
            }
            else {
                context.res = {
                    status: 400,
                    body: ("Invalid payload for Wiki event")
                }
            }
        }
        else {
            context.res = {
                status: 401,
                body: "Signatures don't match"
            };
        }
    };
    
  16. 上部のメニュー バーで、[保存] を選択します。 "接続完了" ステートメントと共に [ログ] ペインが表示されます。

Webhook のシークレットを更新する

  1. GitHub ポータルで GitHub アカウントに切り替えます。

  2. リポジトリを選択します。

  3. 上部のメニュー バーで、[Settings](設定) を選択します。 [設定] ペインが表示されます。

  4. サイドバーで、[Webhooks] を選択します。 [Webhook] ペインが表示されます。

  5. Webhook の横にある [Edit](編集) を選択します。

  6. [シークレット] テキスト ボックスに、この演習で先ほど保存した関数の既定のキーを入力します。

  7. ページの下部までスクロールし、[Update webhook](webhook の更新) を選択します。 [Webhooks/Manage webhooks](Webhook/Webhook の管理) ペインが表示されます。

Webhook と Azure 関数をテストする

  1. [Recent Deliveries](最近のデリバリ) タブを選択します。

  2. 省略記号 ([...]) ボタンを選択して最新の (一番上の) 配信エントリを選択します。

  3. [Redeliver](再配信) を選択します。 [Redeliver payload?](ペイロードを再配信しますか?) ボックスで [Yes, redeliver this payload](はい、このペイロードを再配信します) を選択します。

    この操作で、Wiki ページの編集がもう一度シミュレートされます。

  4. 省略記号 ([...]) ボタンを選択して最新の (一番上の) 配信エントリを選択します。

  5. ヘッダー セクションに、x-hub-signature が表示されます。 また、応答コードが 200 であることもわかります。これは、要求が正常に処理されたことを示します。

    Request URL: https://testwh123456.azurewebsites.net/api/HttpTrigger1?code=aUjXIpqdJ0ZHPQuB0SzFegxGJu0nAXmsQBnmkCpJ6RYxleRaoxJ8cQ%3D%3D
    Request method: POST
    content-type: application/json
    Expect:
    User-Agent: GitHub-Hookshot/16496cb
    X-GitHub-Delivery: ce122460-6aae-11e9-99d4-de6a298a424a
    X-GitHub-Event: gollum
    X-Hub-Signature: sha1=<hash of default key>
    

無効な署名をテストする

  1. GitHub ポータルの webhook ページで、[Settings](設定) タブを選択します。

  2. [Secret](シークレット) テスト ボックスで、[Change Secret](シークレットの変更) を選択します。

  3. ランダムな文字列を入力し、下にスクロールして、[Update webhook](Webhook の更新) をクリックします。

    Webhook によって使用されているキーは、Azure 関数で想定されているものと一致しなくなります。

  4. [Recent Deliveries](最近のデリバリ) タブを選択します。

  5. 省略記号 ([...]) ボタンを選択して最新の (一番上の) 配信エントリを選択します。

  6. [Redeliver](再配信) を選択し、[Redeliver payload?](ペイロードを再配信しますか?) ボックスで [Yes, redeliver this payload](はい、このペイロードを再配信します) を選択します。

  7. 今回は、応答コードが 401 と表示されます。これは、要求が承認されなかったことを示します。

  8. 省略記号ボタン ([...]) を選択して最新の (一番上の) 配信エントリ ("再配信") を選択します。

  9. [Response](応答) タブを選択し、[Body](本文) セクションに "Signatures don't match" (署名が一致しません) というメッセージが応答の本文として表示されることを確認します。