代表的な面接トピック

プロダクト面接:リッチテキストにHTML Sanitizer APIを採用すべきか?

プロダクト難しい
Offer.cc 編集チーム公開日 更新日

質問

自社のSaaSでユーザー作成のリッチテキストをサポートする予定です。ブラウザネイティブのHTML Sanitizer APIを採用すべきでしょうか?意思決定フレームワーク、段階的なフォールバック計画、およびリリース指標を提示してください。

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

あるSaaSプロダクトが、コメント、ナレッジベース、テンプレートにユーザー作成のリッチテキストを追加しようとしています。チームはカスタムフィルタリングルールを減らすためにブラウザネイティブのHTML Sanitizer APIを求めていますが、このAPIは一部の主要ブラウザでは利用できません。採用すべきかどうかを判断し、セキュリティ、ユーザー体験、互換性、運用のトレードオフを説明してください。

面接官が評価するポイント

  • 脅威モデル、許可されたコンテンツ、サーバーの信頼境界を最初に定義しているか。
  • setHTML()、カスタムSanitizer設定、setHTMLUnsafe()、Trusted Typesを区別しているか。
  • ブラウザのカバレッジ、フォールバック実装、コンテンツの一貫性、移行コストが定量化されているか。
  • 段階的なメトリクスによってXSSリスク、編集成功率、パフォーマンス、ロールバック準備態勢が検証されているか。

尋ねるべき確認質問

リッチテキストにリンク、画像、表、埋め込み、スタイル、カスタム属性が必要かどうかを確認します。また、コンテンツがサーバーサイドでレンダリングされるか、メールにエクスポートされるか、検索用にインデックスされるか、他のクライアントで再利用されるかを確認します。サポートされるブラウザ、既存のサニタイザー、コンプライアンス要件、攻撃対象領域、許容可能な機能低下についても確認してください。

30秒の回答

既存のサニタイザーを一括で置き換えるのではなく、ネイティブ優先でサーバー検証を伴う、機能階層化フォールバックを採用します。ネイティブのsetHTML()は安全なサニタイズパスに従いますが、カバレッジが限られているため、サポートされていないブラウザでは監査済みの同等ポリシーを使用します。コメントのような複雑度の低い領域から開始し、危険なペイロードのブロック率、コンテンツの再現性、編集成功率、レイテンシ、ブラウザの分布を測定します。サーバーは依然として出力境界でサニタイズとエンコードを行い、Trusted Typesはインジェクションシンクの周囲に制約を追加します。

ステップごとの詳細解説

1. ユーザー価値と脅威モデルの定義

ユーザー価値は信頼性の高いフォーマット済みコンテンツであり、主なリスクは信頼できないHTMLをDOMや他のレンダリングシンクに送信することです。メンテナンスコストに見合う機能を判断する前に、許可される要素、属性、URLスキーム、メディアソースを定義します。

2. ネイティブAPI機能の切り分け

Element.setHTML()Document.parseHTML()は安全なサニタイズのデフォルトを使用します。カスタム設定により許可リストを厳格化できます。setHTMLUnsafe()は特別な構造が必要な場合向けですが、厳格な設定とレビューが必要です。仕様ではスクリプト実行可能なマークアップを削除する安全なメソッドが義務付けられているため、このAPIは任意のHTMLを許可するものではありません。

3. カバレッジとフォールバックの評価

MDNではHTML Sanitizer APIが「Limited availability(限定的な利用可能性)」と表記されています。ネイティブパスを機能検出し、サポートされていない場合はサーバーまたは監査済みライブラリのパスを選択します。両方のパス間で許可リスト、テストフィクスチャ、バージョン記録を共有します。フォールバックでは、見た目の一致のためにポリシーを緩めるのではなく、高リスクな機能を削除すべきです。

4. クライアント間のコンテンツコントラクトの設計

元の入力と正規化された安全な表現を保存し、編集、プレビュー、メール、検索、エクスポートのそれぞれにどの表現を提供するかを定義します。サーバーのすべての出力境界で再検証します。クライアントサイドのサニタイズはDOMインジェクションのリスクを軽減しますが、サーバーの認可、ストレージ、またはレンダリングポリシーを代替するものではありません。

5. 段階的ロールアウトとメトリクスの設計

少数のテナントコホートに対して1つのコンテンツタイプを有効にし、ネイティブとフォールバックの結果を比較します。危険なペイロードのブロック、意図しない削除への異議申し立て、編集・送信の成功率、初回レンダリングおよび入力レイテンシ、ブラウザカバレッジ、ポリシーバージョンの整合性、セキュリティイベントを追跡します。

6. Trusted Typesと運用の処理

高リスクなシンクに対してTrusted Typesのレポートまたは強制を有効にし、ポリシー関数が検証済みタイプを返すことを義務付けます。ルール変更の承認フロー、悪意のあるフィクスチャに対するリグレッションテスト、コンテンツの再処理、緊急ロールバック手順を確立します。ブラウザのアップデートによってセキュリティポリシーが暗黙のうちに変更されないようにしてください。

高品質な回答サンプル

コンテンツ機能、脅威モデル、ランタイム環境を3つの決定テーブルにまとめます。HTML Sanitizer APIは、信頼できないHTMLがDOMに入る前のクライアントサイドでの構造化されたクリーニングに有用です。setHTML()は安全なデフォルトを持ち、WHATWG仕様によりスクリプト実行可能なマークアップが残る可能性が低減されていますが、MDNでは依然としてカバレッジが限定的と記載されています。プロダクト計画としては、許可された要素、属性、スキーム、フィクスチャを共有しつつ、成熟したライブラリまたはサーバーポリシーへのフォールバックを備えたネイティブ優先のアプローチを採用します。サーバーはオリジナルと安全な表現を保存し、ページ、メール、検索、エクスポート用に個別に検証します。クライアントのクリーニングは認可や完全なXSS保護を提供するものではありません。まずコメントからロールアウトし、ブロック率、再現性、送信成功率、パフォーマンス、ブラウザ分布、セキュリティイベントを測定します。setHTMLUnsafe()は、厳格な設定、Trusted Types、レビューを伴う正当な構造要件に対してのみ使用します。ポリシー更新後は過去の悪意あるフィクスチャをリプレイ検証し、リグレッションが発生した場合は直ちにロールバックします。

よくある間違い

  • ネイティブのブラウザAPIがあればサーバーサイドのサニタイズが不要になると想定すること。
  • デモのみをテストし、サポートされていないブラウザやフォールバックの一貫性を無視すること。
  • 任意の埋め込みを維持するためにsetHTMLUnsafe()の設定を緩和すること。
  • 再現性、意図しない削除、セキュリティのメトリクスを単一のフィルター成功率に置き換えてしまうこと。
  • Trusted Typesをサニタイザーとして扱ったり、サニタイザーを認可として扱ったりすること。

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

なぜすべての対象領域を即座にネイティブAPIに切り替えないのですか?

カバレッジ、コンテンツ機能、レガシーデータの移行が依然として不透明だからです。フォールバックを備えたリバーシブルなロールアウトにより、実際のブラウザとコンテンツの分布をまず検証します。

ネイティブとサーバーのポリシーが異なる場合はどうしますか?

バージョン管理された許可リストと悪意のあるフィクスチャを共有し、サーバーを最終境界とします。クライアント側で差異が検出された場合はポリシーのバージョンとサンプルを記録し、ルールを決して暗黙的に緩めてはなりません。

Trusted Typesの強制(enforcement)はいつ有効にする価値がありますか?

主要なシンクのインベントリが完了し、ポリシー関数とサードパーティコンポーネントが移行され、レポートオンリーモードでの誤検知が少ないことが確認された後、段階的に強制を有効にします。

公開情報ソース

関連する質問