代表的な面接トピック

総合面接:APIリンクにURIテンプレートを安全に使用するにはどうすればよいですか?

一般難しい
Offer.cc 編集チーム公開日 更新日

質問

APIゲートウェイがページネーション、フィルター、リソースリンクにURIテンプレートを使用しています。RFC 6570の展開ルールを説明し、パストラバーサル、SSRF、エンコーディングエラーを防ぐ実装とテストを設計してください。

プロンプトとコンテキスト

チームは、APIドキュメント、ページネーションリンク、および/users{?status,limit}などの一括クエリURLのためにURIテンプレートを求めています。テンプレートは設定から取得され、一部の変数値はユーザーから取得されます。RFC 6570の式レベル、予約文字およびリストの展開、そして結果を解析、展開、検証するためのセキュリティ境界を説明してください。

面接官がテストしていること

  • テンプレート構文、変数エンコーディング、最終URIの解析および検証の分離。
  • 単純展開、予約文字展開、パス展開、マトリクスパラメータ展開、クエリ展開の違いの説明。
  • リスト、連想マップ、explode(展開修飾子)、プレフィックス切り捨て、未定義変数の処理。
  • 信頼できないテンプレートによるSSRF、パストラバーサル、オープンリダイレクト、データ漏洩リスクの認識。

最初に明確にすべき質問

  1. テンプレートは静的コードですか、レビュー済みの設定ですか、それともテナント/ユーザーから提供されるものですか?
  2. 結果は表示のみですか、それともサーバー側のHTTPクライアントによって直接送信されますか?
  3. 変数は文字列、リスト、連想マップ、またはネストされたJSONですか?
  4. 許可されるスキーム、ホスト、ポート、パスプレフィックスは何ですか。結果は現在のAPIオリジン内にとどまる必要がありますか?
  5. 実装はすべてのRFC 6570レベルをサポートする必要がありますか、それとも承認された演算子のサブセットのみですか?

30秒の回答フレームワーク

テンプレートの解析、変数のエンコーディング、最終URIのポリシーを分離します。まずサポートされているRFC 6570演算子と値の型を定義し、次に演算子ごとにパーセントエンコーディング、リスト、および連想マップの展開を適用します。未定義の変数は仕様に従って省略する必要があります。展開されたすべての値を信頼できないURIとして扱い、そのスキーム、ホスト、ポート、正規化されたパスを解析および検証し、テンプレートによってサーバー側の任意のネットワークターゲットが選択されないようにします。テストでは、予約文字、Unicode、空の値、重複キー、プレフィックス、悪意のあるパスをカバーします。

ステップバイステップの詳細な回答

ステップ1:URIテンプレートの境界を定義する

URIテンプレートは、変数を含むURI参照を表現するための構文です。HTTPクライアント、URL許可リスト、またはビジネスルーターではありません。実装は、値から結果を生成する前にリテラルと式を解析する必要があります。テンプレートをリクエストにそのまま連結したり、展開された値をすでに安全なURLとして扱ったりしてはなりません。

ステップ2:レベルごとに演算子を実装する

RFC 6570は単純な変数展開から始まり、予約文字、フラグメント、ラベル、パスセグメント、マトリクスパラメータ、クエリ、クエリ継続の形式を追加します。一般的な演算子には、+#./;?&などがあります。演算子は区切り文字、空の値の動作、および残すことができる予約文字を定義します。単一の汎用文字列置換ルールでは不十分です。

ステップ3:エンコーディングと複合値を処理する

単純な文字列内の予約文字は、式に従ってパーセントエンコードされます。リストはカンマで結合するか、繰り返されるパラメータに展開(explode)できます。連想マップには独自のキー/値区切り文字があります。プレフィックス修飾子は文字列のプレフィックスを取得するものであり、Unicode文字数、バイト数、または安全な切り捨てと誤認してはなりません。UTF-8、空文字列、未定義変数の動作を指定します。

ステップ4:テンプレートと変数のソースを分離する

静的でコードレビュー済みのテンプレートは、より多くの演算子をサポートできます。テナント設定では、式、変数名、出力コンポーネントを制限する必要があります。値はリクエストから取得される場合がありますが、テンプレートが関数を呼び出したり、環境変数を読み取ったり、任意のスキームを構成したりしてはなりません。変数名が新しい式構文を注入できないように、テンプレートASTを変数マップから分離しておきます。

ステップ5:最終URIを検証する

展開後、標準のURIパーサーを使用してスキーム、オーソリティ、パス、クエリ、フラグメントを解析します。サーバー側のリクエストの場合、スキーム、ホスト、ポートは許可リストと一致する必要があり、DNS解決によってループバック、リンクローカル、プライベートアドレスもブロックし、リダイレクトも再チェックする必要があります。エンコードされた..がルールをバイパスできないように、許可されたルートを確認する前にパスを正規化します。

ステップ6:APIリンクの保守性を確保する

ページネーションテンプレートではどの変数がサーバー生成であるかを指定し、フィルターでは固定の変数名と型を使用する必要があります。公開テンプレートや結果に署名、アクセストークン、内部ホスト名を含めないでください。テンプレートのバージョン、変数スキーマ、展開エラーを記録します。安定した順序付けが必要な場合は、パラメータ文字列の順序に依存するのではなく、ビジネス層でそれを提供する必要があります。

ステップ7:テストと監視を構築する

仕様の例に対して、単一値、リスト、マップ、空の値、未定義値を使用してすべての演算子をテストします。予約文字、Unicode、重複するクエリキー、長いプレフィックス、二重エンコーディング、%2e%2e、代替スキーム、リダイレクト、DNS解決のケースを追加します。展開エラー、拒否理由、送信先オリジンの分布、異常な長さを監視し、テンプレート設定が変更されたときにレビューをトリガーします。

高品質な回答例

まず、サポートするRFC 6570演算子を制限し、テンプレートAST、変数スキーマ、パーセントエンコーディング、最終URI検証を分離します。リスト、マップ、explode、プレフィックスは個別のルールに従い、未定義の変数は省略されます。値が式として再解析されることはありません。すべての結果は信頼できないURIのままです。それを解析し、APIのスキーム、ホスト、ポート、正規化されたパスのみを許可し、サーバー側リクエストに対してプライベートアドレスをブロックし、すべてのリダイレクトを再チェックします。テストはRFCの例、Unicode、空の値、重複キー、二重エンコーディング、トラバーサル、SSRFをカバーし、テンプレートのバージョンと拒否理由を記録します。

よくある間違い

  • 演算子のセマンティクスを文字列連結に置き換え、区切り文字やパーセントエンコーディングを破損すること。
  • +の予約展開を「エンコーディングなし」として扱い、コンポーネントの境界を無視すること。
  • リスト、マップ、explodeを1つのカンマ結合形式として扱うこと。
  • 展開されたスキーム、ホスト、ポート、正規化されたパスではなく、テンプレートテキストのみを検証すること。
  • URLエンコーディングをSSRF保護として扱い、再検証なしにリダイレクトに従うこと。

フォローアップの質問と回答

フォローアップ1:未定義の変数には何が起こるべきですか?

式に従って未定義の変数と必要な区切り文字を省略します。nullという文字列をレンダリングしないでください。ビジネススキーマで変数が必要な場合は、展開前に拒否します。

フォローアップ2:なぜ1つのURLエンコード関数を呼び出さないのですか?

エンコーディングは式とURIコンポーネントに依存します。クエリパラメータ、パスセグメント、予約展開には異なる区切り文字とルールがあります。1つの関数で複合値、空の値、プレフィックス、演算子を決定することはできません。

フォローアップ3:テナントテンプレートのリスクをどのように軽減しますか?

レビュー済みの演算子サブセット、固定の変数スキーマ、固定の出力コンポーネントを使用します。任意のスキームやオーソリティを禁止し、展開後もオリジン許可リスト、パス正規化、DNS/IPチェック、リダイレクトの再検証を適用します。

フォローアップ4:プレフィックス修飾子でシークレットを切り捨てることはできますか?

これはURIテンプレートの文字列プレフィックスのセマンティクスであり、プライバシーマスキングやUnicodeセーフな切り捨てではありません。長さと文字境界が明示的なポリシーであるビジネス層で機密データをマスクしてください。

フォローアップ5:RFC 6570の互換性をどのように証明しますか?

RFC 6570仕様の例と演算子レベルのテストを実行し、各変数の型について予想される展開を比較し、プロジェクト固有の拒否ケースを追加して、サポートされていないレベルと相違点を文書化します。

公開情報ソース

関連する質問