Jakarta Facesの出力エスケープ無効化によるXSS

Jakarta Facesの出力エスケープが無効になっています。

説明

Jakarta Facesの標準コンポーネントh:outputText、h:outputFormat、h:outputLabelは、HTML/XMLマークアップに意味を持つ文字を既定でエスケープします。escapeをfalseにすると保護が無効になり、値がマークアップとして表示されます。ユーザー入力などの信頼できないデータが含まれる場合、攻撃者が実行可能なHTMLやスクリプトを挿入するおそれがあります。

escape="false"だけで攻撃が成立するわけではなく、信頼できない値がその出力へ到達する必要があります。ただし、既定の出力エンコードを回避する設定なので、データの取得元と変換処理を確認してください。Jakarta Faces 4.1のVDL文書では、3つのコンポーネントの既定値をtrueと定義しています。

想定される影響

  • 被害者の権限による操作やアカウントのなりすまし
  • ページに表示された機密情報の閲覧・外部送信
  • フィッシング画面の挿入、内容の改ざん、悪意のあるサイトへの誘導

対処方法

  • 通常のテキストはescapeを省略するかescape="true"を指定し、既定のエスケープを維持してください。
  • 入力検証や文字列フィルターで出力エンコードを置き換えないでください。実際の出力コンテキストに合わせて値をエンコードしてください。
  • ユーザーが作成するリッチHTMLが必要なら、維持管理されているOWASP Java HTML Sanitizerなどの最小限の許可リストポリシーで、サーバー側で無害化した値だけを表示してください。escape="false"を使う箇所のポリシーとデータ経路を確認し、sanitizeという関数名だけで安全と判断しないでください。
  • CSPは追加の防御として使い、出力エンコードやHTMLの無害化の代わりにしないでください。

例

変更前

html
<ui:composition xmlns:ui="jakarta.faces.facelets"
                xmlns:h="jakarta.faces.html">
  <h:outputText value="#{profile.biography}" escape="false" />
</ui:composition>

変更後

html
<ui:composition xmlns:ui="jakarta.faces.facelets"
                xmlns:h="jakarta.faces.html">
  <h:outputText value="#{profile.biography}" />
</ui:composition>

説明:

  • 変更前: ユーザーが編集できる紹介文をescape="false"で表示するため、値のマークアップがブラウザーに解釈されます。
  • 変更後: escapeを省略して既定値trueを使い、同じ値をHTMLテキストとしてエンコードします。

参考資料