プロンプトと適用範囲
あるエンタープライズサービスでは、未認証のクライアントが 401 レスポンスやチャレンジを通じてリソースの存在を探索(プローブ)できないようにしつつ、認可された鍵を持つクライアントに選択されたリソースへのアクセスを許可したいと考えています。チームは2025年2月に発行されたStandards Track RFCであるIETF RFC 9729の採用を検討しています。この方式はTLS鍵素材エクスポータ(TLS keying-material exporter)を使用して接続にバインドされた署名入力を生成し、Authorization: Concealed で証明を送信します。
クライアント、エッジゲートウェイ、およびオリジンのデプロイを設計してください。48バイトのエクスポータ出力、認証パラメータ、TLSバージョンの要件、接続の再利用、鍵の失効、レガシー向けフォールバック、およびロールアウトテストについて説明してください。実装監査には、2026年に確認された正誤表(verified erratum)も含めてください。
面接官が評価するポイント
面接官は、認証機能の隠蔽と鮮度(freshness)の保証を区別して考えられているかを評価します。RFC 9729はチャレンジを送信しませんが、証明の鮮度は下位のTLS接続の有効期間によって制限されます。
優れた回答では、単にいくつかのヘッダー名を挙げるだけでなく、Concealed-Auth-Export の安全な転送、プロトコル固有の鍵、HTTP/2およびHTTP/3の多重化の分離、失効キャッシュの一貫性、フォールバック動作、構成エラーの診断を網羅します。
最初に確認すべき明確化の質問
- クライアント鍵は誰が発行し、鍵はオリジン固有ですか?また、短期間の鍵はサポートされていますか?
- ゲートウェイとオリジンは分離されていますか?その場合、TLSエクスポータの出力はそれらの間でどのように渡されますか?
- リソースには接続レベルの鮮度が必要ですか、それともリクエストレベルの鮮度が必要ですか?
- レガシークライアントがTLS 1.2のみをサポートしている場合、Extended Master Secretはネゴシエートされましたか?
- 失効は数秒以内に有効になる必要がありますか、それともキャッシュウィンドウが許容されますか?
30秒での回答
「オリジンごとの公開鍵ディレクトリを維持します。クライアントはTLS接続上でRFC 9729エクスポータを使用し、規定されたコンテキストに署名してパラメータを送信します。ゲートウェイは信頼できるエクスポータ素材のみを解析して転送し、オリジンが最終的な認証および認可の決定を行います。TLS 1.3はバインディング要件を満たしますが、TLS 1.2ではExtended Master Secretが必要であり、そうでない場合リクエストは未認証として扱われます。デュアルリード・シングルライトの鍵ローテーションと短い失効キャッシュを使用します。証明は接続スコープであるため、より強力な鮮度が必要な場合は接続の再確立を行います。ロールアウトのメトリクスでは、リソースの存在を明かすことなく、解析、検証、失効、およびフォールバックをカバーします。」
ステップバイステップの解決策
鍵とオリジンのディレクトリを構築する
各オリジンについて、鍵IDを公開鍵、アルゴリズム、realm、発行時刻、および失効状態にマッピングします。クライアントの秘密鍵はConcealed認証専用とし、他のプロトコルで再利用しません。RFC 9729は固定の署名プレフィックスを追加しますが、鍵の分離はデプロイ側の責任です。鍵IDはユーザーのプライバシー情報をエンコードすべきではなく、監査ログには内部の不可逆な識別子を使用します。
接続バインドされた証明を計算する
クライアントはエクスポータラベル EXPORTER-HTTP-Concealed-Authentication、指定されたコンテキスト、および48バイトの出力を使用します。最初の32バイトは署名入力に供給され、最後の16バイトは検証素材として送信されます。コンテキストには、アルゴリズム、鍵ID、公開鍵、スキーム、ホスト、ポート、およびrealmが含まれます。不一致がある場合は検証失敗となり、寛容なパーサーであってもそれを『修復』してはなりません。
exported = TLS-Exporter(label, context, 48)
signature_input = exported[0:32] + domain_separation_prefix
verification = exported[32:48]
Authorization: Concealed k=..., a=..., s=..., p=..., v=...ゲートウェイとオリジンの境界を定義する
モノリシックなオリジンはTLSエクスポータを直接読み取ることができます。分離されている場合、ゲートウェイはパラメータの構文を検証し、信頼できる内部チャネル経由で48バイトのエクスポータ出力を Concealed-Auth-Export で送信します。パブリッククライアントがその名前のヘッダーを偽造する可能性があるため、ゲートウェイは外部の値を上書きまたは削除する必要があります。オリジンは依然としてターゲットフィールド、アルゴリズム、鍵ID、公開鍵、および署名を検証します。ゲートウェイによる解析は認可ではありません。
TLSとプロトコルの制約を適用する
RFC 9729にはTLS 1.3、またはExtended Master Secretを伴うTLS 1.2が必要です。そうでない場合、サーバーはリクエストを未認証として扱います。HTTP/2およびHTTP/3はこのバインディングを使用できますが、接続レベルの証明が1つの接続上の複数のリクエストをカバーする場合があります。あるテナントが別のテナントのAuthorizationヘッダーを読み取ることができないよう、クライアントとゲートウェイはセキュリティコンテキストを分離する必要があります。
鮮度、再利用、リプレイを処理する
エクスポータの鮮度はTLS接続の期間を超えて持続しません。これはHTTPリクエストごとの独立したnonceではありません。リソースがより短いウィンドウを必要とする場合は、接続を閉じるかHTTP/3 GOAWAYを送信するなどして新しい接続を要求し、それを短期間の鍵IDおよびサーバーの時間ポリシーと組み合わせます。v をリクエストnonceとして扱ったり、ホスト、ポート、realmを検証せずに署名を受け入れたりしてはなりません。
ローテーション、失効、フォールバック
デュアルリード・シングルライト方式のローテーションを使用します。新しい鍵を公開し、一時的に古い鍵IDを受け入れ、クライアントを移行してから古い鍵を失効させます。失効は認可の前にチェックされ、キャッシュTTLと無効化は明示的に設定されます。レガシークライアントは既存の認証パスを使用できますが、フォールバックレスポンスはリソースが存在するかどうかを開示しないように同じ外部形状を維持します。
失敗の監視と診断
パラメータ解析の失敗、非対応のTLS、不明な鍵ID、公開鍵の不一致、署名の失敗、失効ヒット、ゲートウェイ転送エラー、フォールバック率を、オリジン、クライアントバージョン、プロトコル、アルゴリズム別にセグメント化します。秘密鍵、完全な署名、またはリンク可能なユーザー鍵は決してログに記録しないでください。RFC 9729 セクション3.3のコンテキスト文字列およびセクション4の整数ABNFに影響を与える検証済み正誤表(erratum)を監査します。
安全にステージングとテストを実施する
まず1つのオリジンと失効可能な低特権リソースで有効化します。TLS 1.3、TLS 1.2+EMS、HTTP/2、HTTP/3、分離されたゲートウェイ、および接続の再確立をテストします。不正なホスト、ポート、realm、アルゴリズム、鍵ID、エクスポータ長、重複ヘッダー、古い失効キャッシュ、クロステナント接続のケースを注入します。これらはすべて未認証として扱われなければなりません。ロールバック時は、古いディレクトリと監査記録を保持したまま、新しい鍵の発行とスキームの受け入れを停止します。
模範的な高評価の回答
「RFC 9729はリクエストごとのnonceではなく、接続にバインドされた探索不可能な認証です。クライアントはエクスポータコンテキストを構築し、48バイトを取得して専用の鍵で署名します。ゲートウェイは構文を検証し、信頼できるエクスポータ出力を転送します。オリジンはTLS条件、ターゲットフィールド、鍵ID、公開鍵、署名、失効、および認可を検証します。TLS 1.3またはTLS 1.2+EMSが必要です。鍵はオリジンスコープであり、デュアルリードでローテーションされます。より強力な鮮度が必要な場合は接続を再確立します。ロールアウトのメトリクスは解析、検証、失効、フォールバックをカバーし、ロールバックはリソースの状態を公開することなく新しいスキームの使用を停止します。」
よくある間違い
- エクスポータをリクエストごとのnonceとして扱う → 長時間接続で証明が再利用される可能性がある → 接続の鮮度を明記し、必要に応じて接続を再確立する。
- ゲートウェイでのみ検証を行う → オリジンが偽造された内部ヘッダーを信頼してしまう可能性がある → オリジンがコンテキストと認可を検証する。
- EMSなしのTLS 1.2を受け入れる → エクスポータのバインディングが不十分 → 未認証として扱う。
- プロトコル間で鍵を再利用する → クロスプロトコルの署名混乱 → スキームとオリジン専用の鍵を割り当てる。
- 失効キャッシュを長く保持しすぎる → 失効したクライアントがアクセスを維持してしまう → TTL、無効化、優先順位を定義する。
- フォールバック時に異なるリソースエラーを返す → リソースの存在が観測可能になってしまう → 外部向けの状態を一様に保ち、内部的に理由をログに記録する。
フォローアップの質問と回答
フォローアップ1:オリジンがチャレンジを送信しないのはなぜですか?
チャレンジは未認証のクライアントに対し、そのリソースが認証を期待していることを伝えてしまうため、探索不可能という目標が損なわれます。RFC 9729では、接続にバインドされたTLSエクスポータ素材から導出された証明をクライアントが送信できるようにします。
フォローアップ2:48バイトを32バイトと16バイトに分割するのはなぜですか?
仕様では、サーバーがエクスポータ出力を確認できるように、最初の32バイトに署名し、最後の16バイトを検証素材として送信します。実装ではこれらの正確な範囲を使用する必要があり、48バイト全体を単一のnonceとして扱ってはなりません。
フォローアップ3:ゲートウェイからエクスポータを転送するのは安全ですか?
信頼され、整合性が保護されたゲートウェイ-オリジン間チャネル上でのみ安全です。パブリッククライアントはそのヘッダー名を偽造できるため、ゲートウェイはそれを上書きまたは削除する必要があり、オリジンは内部チャネルを認証して長さを検証する必要があります。
フォローアップ4:既存の接続での失効はどのように処理しますか?
接続作成時だけでなく、認可決定のたびに失効をチェックします。より強力な鮮度を確保するには、古い鍵を失効させ、接続終了をシグナルし、クライアントに新しい鍵で再接続するよう要求します。