GitHub webhookに48個のIP追加:許可リストでも署名確認は必要です

Dev
閲覧数 3

PRは作成されたのに、デプロイ用のボットが動きません。アプリを調べる前に、リクエストがファイアウォールで止まっている可能性があります。GitHubの10月29日の発表は、この受信経路に関わる変更です。

受信側に加える3つのアドレス範囲

追加されたCIDRは9.234.98.160/28、9.234.98.176/28、9.234.106.48/28です。github.comのwebhook配信が対象で、GitHub Enterprise Cloudを含む全プランに適用されます。固定の許可リストでは、既存の範囲を残して追加します。

各/28には16個、合計48個のアドレスが含まれます。図はPythonのipaddressで実際にローカル計算した結果で、アカウント数や配信サーバー数ではありません。GET /metaのhooksで定期更新している場合、今回の追加に伴う別途の変更は不要とGitHubは説明しています。

Pythonで実行したCIDR計算を独自に可視化。3つの/28に合計48個のアドレスが含まれます。
Pythonで実行したCIDR計算を独自に可視化。3つの/28に合計48個のアドレスが含まれます。

IP許可と署名は別の問いに答えます

許可リストは、どの送信元ネットワークから受け付けるかを決めます。使うのはhooksであり、Actionsランナーの別経路を示すactionsではありません。イベントの受信と、CIから外部APIへの通信は向きが違います。

通過後は、そのwebhookのsecretでX-Hub-Signature-256を確認します。GitHubはsecretと本文からHMAC-SHA256を生成します。受信した元のバイト列で計算し、hmac.compare_digestやcrypto.timingSafeEqualなどの定時間比較を使います。許可IPでも省略できません。

同じ意味のJSONでもバイト列は変わります

{"action":"opened"}を再生成して{"action": "opened"}にすると空白が増えます。意味が同じでも署名は一致しない場合があります。公開デモ用secretによるローカル実行では、同じバイト列はTrue、空白追加後はFalseでした。実際のGitHub配信を記録したものではありません。

公開デモ用secretを使ったローカルHMAC実行例。空白1つでバイト列が変わります。実配信のキャプチャーではありません。
公開デモ用secretを使ったローカルHMAC実行例。空白1つでバイト列が変わります。実配信のキャプチャーではありません。

変換前の生の本文を確保し、プロキシやフレームワークによる変更も確認します。調査のためにpayload URLへsecretを入れると、別の漏えい経路になります。安全なサーバー設定で管理します。

復旧後に完了済みの仕事を繰り返さないために

通信を直したら失敗した配信を確認し、必要なものを再配信します。X-GitHub-Deliveryは再配信でも元と同じです。完了済み処理と、失敗して再開できる処理を区別します。既知のIDをすべて捨てると復旧まで妨げかねません。

GitHubは10秒以内の2XX応答と、長い処理のキュー化を推奨しています。署名検証、永続的な受け付け、再試行可能な状態管理をつなげます。3つのCIDRを、到着・検証・完了という経路の中で捉えると原因を理解しやすくなります。

出典と関連資料

GitHub Changelog · 2026-10-29

GitHub Docs · Meta API

GitHub Docs · Webhook signatures

GitHub Docs · Webhook best practices