GH GambleHub

リクエストの署名と検証

リクエストの署名は、送信者の信頼性とコンテンツの完全性を証明します。TLS(チャネルを保護する)とは異なり、適用された署名は、各メッセージをプロキシ、キャッシュ、および遅延配信に対して検証可能で耐性があるものにします。

目的:

1.信頼性(送信者)と整合性(変更されませんでした)。

2.独自性(リプレイに対する保護)。

3.トランスポートからのデカップリング(HTTP、キュー、Webhookの上で動作します)。

4.可聴性(数ヶ月後の再現性チェック)。

1)脅威モデル(最小)

ルートに沿ったボディ/ヘッダーの置換。
リプレイ(正当なリクエストを繰り返します)。
ダウングレード/ストリップキャプション。
統合の秘密を盗む。
非同期クロック(クロックスキュー)と長いキュー。

2)プリミティブの選択

HMAC(対称性):シンプルで高速で、キーは両側に格納されます。B2B Webhookや内部APIに適しています。
RSA/ECDSA(非対称性):送信者からの秘密鍵、受信者からの公開鍵。オープンな統合に適しており、秘密を共有しないことが重要な場合。
mTLS:トランスポート層の相互認証とNMAC/body署名を組み合わせることがよくあります。
JWT/JWS:ベアラートークンと自給自足スタンプに便利です。ボディに署名するには、canonicalization+JWS Detached/HTTP Message Signaturesを使用することをお勧めします。
HTTPメッセージ署名(リクエストの選択された部分の署名):RESTの現代的なアプローチ。

推薦:webhooksのため-HMAC+timestamp+nonce+body canonicalization;public API-HTTPメッセージ署名またはJWS;高いリスク-mTLSを追加します。

3)正規化(私たちが署名するもの)

あなたは、両方の当事者によって均等に回復可能である決定論的な文字列に署名する必要があります。

参照構成:

method \n path_with_query_normalized \n content-type \n digest: SHA-256=BASE64(SHA256(body)) \n x-ts: <unix    iso> \n x-nonce: <uuid> \n host \n x-tenant: <tenant_id> \n
総行:

canonical = join("\n", fields)
signature = HMAC(secret, canonical)  # или ECDSA_sign(private_key, canonical)
ルール:
  • クエリパラメータのパスと順序を正規化します。
  • スペース/unicode/case-修正(小文字ヘッダ、トリムなど)。
  • 大きなボディ-ハッシュ(ダイジェスト)、「そのまま」オンにしないでください。

4)タイトル形式

HMACの例:

X-Signature-Alg: hmac-sha256
X-Signature: v1=hex(hmac),ts=1730379005,nonce=550e8400-e29b-41d4-a716-446655440000,kid=prov_42
Digest: SHA-256=BASE64(SHA256(body))
X-Tenant: brand_eu
非対称性の例(ECDSA P-256):

Signature: keyId="prov_42", alg="ecdsa-p256-sha256",
ts="2025-10-31T12:30:05Z", nonce="550e...", headers="(request-target) host digest x-tenant",
sig="BASE64(raw_signature)"

'kid'/'keyId'では、レジストリからキーを選択できます(回転を参照)。

5)受領時の検証

擬似コード:
python def verify(request):
1) Basic assert abs (now () - request. ts) <= ALLOWED_SKEW  # напр., 300 с assert not replayed(request. nonce, window = TTL) # store nonce/ts in KV

2) Restore canonical canonical = build_canonical (
method=request. method,
path=normalize_path(request. path, request. query),
content_type=request. headers["content-type"],
digest=hash_body(request. body),
ts=request. ts,
nonce=request. nonce,
host=request. headers["host"],
tenant=request. headers. get("x-tenant")
)

3) Get the key key = key_registry. get(request. kid) # secret (HMAC) или public key (ECDSA)

4) Verify if request signature. alg. startswith("hmac"):
ok = hmac_compare(key. secret, canonical, request. signature)
else:
ok = asym_verify(key. public, canonical, request. signature)

5) Solution if not ok: return 401, "SIGNATURE_INVALID"
return 200, "OK"

定時HMAC比較、高速KV (TTL ≥配信ウィンドウ)に'nonce'/'(ts、 event_id)'を格納します。

6)反再生および窓

Timestamp+Nonce: '± Δ'より古いリクエストを拒否する(例:5分)とnonceはこのウィンドウで再試行します。
Webhookの場合:安定した'event_id'と受信ボックスのテーブルを使用します。これはnonceよりも信頼性が高くなります。
再配信(リトレイ)は、新しいものを生成しないで、同じts/nonce/event_idを使用する必要があります。

7)複数のテナントおよび地域

テナント/リージョンごとのキーの保存:'kid=<tenant>: <region>: <key_id>'。
個別の秘密プールと制限;データレジデンシーを監視します。
見出し/正規化では、'X-Tenant'を示し、この領域はチェックされているコンテキストの一部です。

8)キー管理および回転

キーレジストリ(KMS/Vault): 'kid'、 type、 algorithm、 status ('active'、 'deprecating'、 'reited')、 'valid_from/valid_to'。
デュアルシークレット:現在のキーと次のキーを同時に保持します(レシーバは両方を受け入れます)。
スケジュールとイベントのローテーション(妥協)。
キーのピン留め(可能であれば)およびキー材料へのアクセスを制限します。
キーへのアクセスとそれらのアクションのログ。

9) mTLSおよびOAuthとの組合せ

mTLSは、証明書レベルでチャンネルと「あなたが誰であるか」をチェックします。
署名はメッセージを保護します(proxies/caches/queuesを通じて便利です)。
OAuth/JWTは認証/承認を補完しますが、(正規化で署名されていない限り)本体の完全性を保証するものではありません。
ベストプラクティス:mTLS+body signature (Digest)+HMAC/ECDSA+short 'ts' -interval。

10)エラーと応答コード

'401 SIGNATURE_INVALID'は無効な署名/アルゴリズムです。
'401 KEY_REVOKED'-'kid'は無効/期限切れです。
'400 TIMESTAMP_OUT_OF_RANGE'-時計/ウィンドウ。
'409 NONCE_REPLAYED'-やり直しが検出されました。
'400 DIGEST_MISMATCH'-ボディが変更されました。
'415 UNSUPPORTED_ALGORITHM'は未解決の'alg'です。
'429 TOO_MANY_ATTEMPTS'-キー/テナントのスロットリング。

マシン読み取り可能な'error_code'で正確な原因を蹴ります。「そのまま」秘密/正規化を返さないでください。

11)観察可能性および監査

メトリクス:
  • 'verify_p95_ms'、' verify_error_rate'、'digest_mismatch_rate'、'replay_blocked_rate'、'alg_usage {hmac、 ecdsa}'、'clock_skew_ms'。
  • ログ(構造):'kid'、 'alg'、 'tenant'、 'region'、 'ts'、 'nonce'、 'digest_hash'、 'decision'、 'reason'。
  • トレース:属性の署名。「キッド」「サイン」alg'、'signature。 。 。
  • 監査:回転、キーの使用法および許容フラグの不変のログ。

12)パフォーマンス

ストリーミングによって体をハッシュします(あなたのメモリにそれを保持しないでください)。
短いTTLとイベントによる障害で「子供」によって公開鍵をキャッシュします。
エッジ/ゲートウェイで、予備チェック(ts/nonce/format)を行います。
ECDSAより速いHMAC;ECDSAは、外部統合と「非共有」キーにより便利です。

13)テスト

据え付け品セット:同じ要求→同じcanonicalization/signature;dirty spaces/query order/→ヘッダは安定です。
Negative:無効な'kid/alg'、変更されたbody/host、 nonce repeat、 ovolete ts、 clock skew。
プロパティベース:すべての同等のクエリは、単一の正規文字列を生成します。
Interop:クロスランゲージチェック(Go/Java/Node/Python)。
カオス:遅延、後退、オンザフライのキー変更。

14)プレイブック(ランブック)

1.'SIGNATURE_INVALID'スパイク

キーの回転、クロックのずれ、送信者での正規化の変更を確認します。
一時的に"dual-accept'を有効にします古い"子供"、パートナーに通知します。

2.'REPLAYED'の増加

nonceストレージのTTLを増やし、送信者でリトレーナーを確認し、クロックスキューを確認します。
エッジ上の虐待的IP/ASNをオーバーライドします。

3.'DIGEST_MISMATCH'大量

プロキシ/圧縮/書き換えヘッダーをチェックします。正規化バージョンを修正しました。
本体/ヘッダー侵入者を無効にします。

4.主な妥協点

すぐに'kid'を取り消し、'next_kid'に翻訳し、すべての秘密/トークンを再生成し、アクセスを監査します。

15)典型的なエラー

order→field permutationの脆弱性を修正せずに"body part'またはJSONに署名します。
「ダイジェスト」→「プロキシ」が存在しないと、気づいていない体を変更することができます。
ノンスのない長い't'ウィンドウは→リプレイするために開いています。
KMS/Vaultなしで環境変数に秘密を保持します。
一定時間ではない署名を比較します。
canonicalization→forward attackで'host'/'path'を無視します。
「子供」のテナントや地域を混ぜる。

16)売り上げ前のチェックリスト

  • 定義された正規化フォーマット(メソッド、パス+クエリ、コンテンツタイプ、ダイジェスト、ts、 nonce、ホスト、テナント)。
  • 「キッド」、キーレジストリ、デュアルシークレットでHMAC/ECDSAを実装。
  • Webhook用のアンチリプレイ(nonce+ts)とinbox/event_idストレージが含まれています。
  • エラーコード/リトレイポリシーを設定し、テナント/キーごとにスロットリングします。
  • Observability:メトリック、ログ、トレース、バーストのアラートを確認します。
  • キー回転が自動化されています。監査とアクセス権は制限されています。
  • Canonicalizationとinterlanguage互換性テストキット。
  • 3-4言語と修正の例を持つインテグレータのためのドキュメント。
  • mTLSは敏感な統合のために有効になりました;JWTは追加としてのみ使用され、ボディの署名の代わりには使用されません。

結論

リクエストの署名と検証は「1つのヘッダー」ではなく、明確な正規化、時間の短いウィンドウ、アンチリプレイ、キーの回転、および観測可能性という規律です。すべての統合(APIとWebhook)のための単一の標準を構築し、'kid '/KMSを使用し、回転中に2つのキーを受け入れると、輪郭はなりすまし、予測可能で監査が容易になります。

Contact

お問い合わせ

ご質問やサポートが必要な場合はお気軽にご連絡ください。いつでもお手伝いします!

Telegram
@Gamble_GC
統合を開始

Email は 必須。Telegram または WhatsApp は 任意

お名前 任意
Email 任意
件名 任意
メッセージ 任意
Telegram 任意
@
Telegram を入力いただいた場合、Email に加えてそちらにもご連絡します。
WhatsApp 任意
形式:+国番号と電話番号(例:+81XXXXXXXXX)。

ボタンを押すことで、データ処理に同意したものとみなされます。