HMAC 署名ヘッダーの設定ガイド

Miterl からの監視リクエストに署名ヘッダーを付与し、お客様の WAF / CDN 側で正規のリクエストとして除外する方法を説明します。

動作の仕組み

監視を「HMAC 署名」を有効にした状態で発行すると、Miterl のプローブはすべての HTTP リクエストに署名ヘッダーを付与します。形式は以下のとおりです(Stripe Webhook 流儀)。

X-Miterl-Signature: t=1714112000,v1=a3b1...d9

ヘッダー名はデフォルトで X-Miterl-Signature ですが、変更可能です。

  • t は Unix タイムスタンプ(リプレイ攻撃を防ぐ目的で使えます)
  • v1 は HMAC-SHA256(secret, "<t>.<METHOD>.<PATH>") の hex 文字列
  • クエリ文字列は署名対象に含まれません

設定手順

  1. Miterl の監視編集画面で「HMAC 署名」を有効にし、「自動生成」でシークレットを発行してください(または任意の文字列を入力)。
  2. 発行されたシークレットを安全な場所に保管します(再表示はできません)。
  3. 下記の WAF / CDN 設定例を参考に、お客様の環境にルールを追加してください。

Cloudflare WAF の設定例

Pro プラン以上で WAF Custom Rules が利用できます。Free プランでは Bot Fight Mode の完全なバイパスはできません。

# Cloudflare WAF Custom Rule (Pro plan or above)
# Field: HTTP Header  → "X-Miterl-Signature"
# Operator: matches regex
# Value: ^t=\d+,v1=[a-f0-9]{64}$
# Action: Skip → All remaining custom rules + Bot Fight Mode

AWS WAF の設定例

WebACL に Allow ルールを優先度 0 で追加すると、署名付きリクエストを最優先で許可できます。

# AWS WAF Rule (JSON snippet)
{
  "Name": "AllowMiterlProbes",
  "Priority": 0,
  "Action": { "Allow": {} },
  "Statement": {
    "ByteMatchStatement": {
      "FieldToMatch": { "SingleHeader": { "Name": "x-miterl-signature" } },
      "PositionalConstraint": "STARTS_WITH",
      "SearchString": "t=",
      "TextTransformations": [{ "Priority": 0, "Type": "NONE" }]
    }
  }
}

Nginx の設定例

# nginx (skip rate limiting / ModSecurity for signed requests)
map $http_x_miterl_signature $is_miterl_probe {
    ~^t=\d+,v1=[a-f0-9]{64}$  1;
    default                    0;
}

server {
    location / {
        if ($is_miterl_probe) {
            # bypass rules — set whatever flag your stack reads
            set $skip_modsec 1;
        }
        # ...
    }
}

オリジン側で署名を検証する(任意)

ヘッダーの存在チェックだけでも実用上は十分ですが、より確実にするためにオリジン側で HMAC を検証することもできます。PHP のサンプルです。

<?php
// On your origin: verify the signature is genuinely from Miterl.
// Use this if you want stronger assurance than "header exists".

\$header = \$_SERVER['HTTP_X_MITERL_SIGNATURE'] ?? '';
if (! preg_match('/^t=(\d+),v1=([a-f0-9]{64})\$/', \$header, \$m)) {
    http_response_code(401); exit;
}

[\$_, \$ts, \$sig] = \$m;
if (abs(time() - (int) \$ts) > 300) {
    http_response_code(401); exit; // replay protection: 5min window
}

\$secret = getenv('MITERL_HMAC_SECRET');
\$expected = hash_hmac('sha256', "{\$ts}.{\$_SERVER['REQUEST_METHOD']}.{\$_SERVER['REQUEST_URI']}", \$secret);

if (! hash_equals(\$expected, \$sig)) {
    http_response_code(401); exit;
}

よくある質問

シークレットをローテーションするには?

監視編集画面で「自動生成」を再度クリックして上書き保存してください。すぐに新しいシークレットで署名するようになります。

シークレットが漏洩した場合は?

上記と同様に再生成してください。漏洩したシークレットは無効になります。WAF 側のルールはヘッダーの存在チェックだけなら変更不要です。

URL のクエリ文字列を含めて署名できますか?

現状は署名対象が <METHOD>.<PATH> のみです。WAF キャッシュキーで揺れる可能性を避けるためです。