Web Bot Auth 検証
このスキルは、既存のサービスに署名されたエージェントトラフィックの検証を追加します。難しいのは暗号化そのものではなく、署名の意味を実際よりも弱く見せる小さな詳細、つまり署名されていないコンポーネント、再利用されたノンス、フェッチをトリガーするヘッダー、クライアントが署名したものとは異なる方法で再構築されたURLなどです。ここでの参照コードとテストは、それらの詳細をエンコードします。あなたの仕事は、それらをユーザーのスタックに組み込み、弱体化させないことです。
仕様ステータス: draft-meunier-web-bot-auth-architecture-05(IETFインターネットドラフト、標準ではありません)をターゲットとし、多くのデプロイ済みエージェントがまだ送信しているレガシーなquoted-string形式のSignature-Agentを受け入れます。ユーザーに対して、これはドラフトであり変更される可能性があることを伝えてください。
ワークフロー
-
リクエストのエントリポイントを見つける。 フレームワークと、リクエストがどこで入ってくるか(ミドルウェア、エッジハンドラー、リバースプロキシフック)を特定します。サービスがプロキシまたはCDNの背後にあるかどうかを確認します。これはURLの再構築方法を決定するためです(
references/adapters.mdを参照)。 -
ユーザーとポリシー決定を確定する。
references/policy-decisions.mdを読み、会話で決まっていないことについて質問します:許可リストに追加するオペレーター、リクエストバインディングとノンスを要求するかどうか、ノンスストア、および各結果が何を行うべきか。厳しい設定を黙って選択しないでください。厳しいデフォルトは、現在デプロイされているほとんどのエージェントを拒否します。緩い設定も黙って選択しないでください。その設定が何を未保護のままにするかを説明してください。 -
検証機能を追加する。
- Python:
scripts/web_bot_auth.pyを変更せずにプロジェクトにコピーし(ライセンスヘッダーを保持)、依存関係にcryptographyを追加し、Requestを構築する小さなアダプターを作成します。 - その他の言語:
scripts/web_bot_auth.pyを移植し、その言語の確立されたEd25519ライブラリ(独自実装は不可)と、存在する場合はメンテナンスされたRFC 8941構造化フィールドパーサーを使用します。assets/test-vectors.jsonのすべてのケースに合格するまで移植は完了しません。
- Python:
-
アダプターを注意深く作成する。 ここでほとんどの統合が壊れます。
Requestは、送信されたままのメソッド、クライアントがリクエストした絶対URL、すべてのヘッダーの出現、および解析や圧縮解除前の生のボディバイトを保持する必要があります。フレームワークごとの注意事項についてはreferences/adapters.mdを参照してください。 -
ノンスストアを選択する。 単一プロセスの場合のみインメモリ。複数のワーカーまたはノードがある場合は、共有で強力な一貫性を持つストアが必要です。
references/nonce-stores.mdを参照してください。 -
結果をアクションにマッピングする。 ユーザーが別段の決定をしない限り、以下のテーブルを使用します。
-
統合をエンドツーエンドでテストする。 実際のフレームワーク(そのテストクライアント)を通じて、
sign_requestを使用して署名リクエストを生成するテストを作成します:1つの有効なリクエスト、1つの改ざんされたボディ、1つのリプレイ、1つの期限切れリクエスト。ファイルがコピーされた場合は、scripts/test_web_bot_auth.pyも実行します。 -
ログのみのロールアウトを推奨する。 何かを強制する前に、一定期間、すべてのリクエストに対して
outcome、reason、operator、keyid、binds_request、replay_protectedをログに記録します。
結果
| 結果 | 意味 | デフォルトのアクション |
|---|---|---|
unsigned | web-bot-auth署名なし | 既存のボット処理 / リスクスコアリング |
verified | 有効な署名、許可リストに登録されたオペレーター | そのエージェントとして許可。ただし、ユーザーごとの認証とレート制限は引き続き適用 |
signed_untrusted | 有効な署名、既知だが許可リストにないオペレーター | unsignedとして扱う。オプションでリスクを低く設定 |
unknown_operator | 整形式だが、利用可能なキーなし | unsignedとして扱う。オプションでバックグラウンドのディレクトリフェッチをキューイング |
invalid | 署名が存在し、間違っている | ブロック。正当なクライアントは壊れた署名を送信しない |
expired | 時間枠外 | ブロック |
replay | ノンスが既に使用済み | ブロック |
Result.hostileは最後の3つでtrueです。verifiedの場合は、2つのフラグも確認します。binds_requestがfalseの場合、署名はメソッド、パス、クエリ、ボディをカバーしていません。replay_protectedがfalseの場合、ノンスがないか、ストアが利用不可でした。安全なデフォルトは、安全なメソッド(GET、HEAD)に対してのみ、いずれかのフラグがfalseの検証済みリクエストを許可することです。
破りやすいルール
これらは、それぞれに具体的な攻撃が存在するために存在します。ユーザーの制約がこれらを破る必要があるように思われる場合は、リスクを説明し、決定を委ねてください。
- 許可リストにないオペレーターのためにキーディレクトリをインラインフェッチしないでください。
Signature-Agentは攻撃者によって制御されるため、その名前をフェッチすることはSSRFであり、誰でもリクエストパスを停止させることができます。未知のオペレーターは、safe_fetch_directoryを使用してバックグラウンドジョブでフェッチするか、まったくフェッチしないでください。 - Content-Digestがカバーされている場合は、常にボディに対して検証してください。 ヘッダーに署名しても、受信したバイトと一致するか誰もチェックしなければ意味がありません。
- 署名が検証された後にのみノンスを記録してください。 そうしないと、誰でもストアを埋めたり、正当なエージェントのノンスを事前に消費したりできます。
- インスタンス間で共有され、アトミックなノンスストアを使用してください。 プロセスごとのキャッシュでは、リプレイが別のワーカーに到達する可能性があります。
- 鮮度は
expiresだけでなくcreatedで制限してください。 エージェントは長い有効期限で署名する場合があります。Policy.max_ageは、リプレイウィンドウとノンスキャッシュを小さく保ちます。 - クライアントが実際にリクエストしたURLを再構築してください。 プロキシの背後では、信頼するプロキシからの転送されたスキームとホストのみを使用します。間違えると、有効な署名が検証に失敗したり、偽装されたホストヘッダーが信頼されたりします。
- 検証済み署名はオペレーターを識別し、ユーザーを識別しません。 通常の認証とユーザーごとの承認およびレート制限をその背後に維持してください。機密性の高いアクションにおけるユーザーの同意の代わりに署名を使用させないでください。
- 検証済みエージェントに人間の行動チェックを適用しないでください。 それらは設計上自動化されています。
ファイル
scripts/web_bot_auth.py: 検証機能、キーリゾルバー、ノンスストア、sign_request。単一ファイル。依存関係はcryptographyのみ。scripts/test_web_bot_auth.py: 攻撃ケーステストとRFC 9421 付録B.2.6準拠ベクトル。scripts/からpython -m unittest -v test_web_bot_authで実行。scripts/generate_vectors.py:assets/test-vectors.jsonを再生成。assets/test-vectors.json: 移植のための言語に依存しないベクトル(テストキーのみ)。references/policy-decisions.md: ユーザーと行う選択とそのトレードオフ。ステップ2で読む。references/adapters.md: 一般的なフレームワークとプロキシの背後でRequestを正しく構築する方法。ステップ4で読む。references/nonce-stores.md: 安全なストアとそのサイズ設定方法。ステップ5で読む。