XSS
JSF は組み込みの XSS 防止機能を持つように設計されています。任意の JSF コンポーネントを使用して、すべてのユーザー制御入力 (リクエスト ヘッダー (Cookie を含む)、リクエスト パラメータ (DB に保存されるものも!)、リクエスト ボディ (アップロードされたテキスト ファイルなど)) を安全に再表示できます。
<h:outputText value="#{user.name}" />
<h:outputText value="#{user.name}" escape="true" />
<h:inputText value="#{user.name}" />
etc...
Facelets で JSF 2.0 を使用している場合、次のようにテンプレート テキストで EL を使用できることに注意してください。
<p>Welcome, #{user.name}</p>
これも暗黙的にエスケープされます。ここは必ずしも必要ではありません<h:outputText>
。
を使用してユーザー制御の入力を明示的にエスケープ解除する場合のみescape="false"
:
<h:outputText value="#{user.name}" escape="false" />
次に、潜在的な XSS 攻撃穴があります!
<b>
ユーザー制御の入力を HTML として再表示し、<i>
、 、 などの HTML タグの特定のサブセットのみを許可する場合は<u>
、ホワイトリストによって入力をサニタイズする必要があります。これには、HTML パーサーJsoupが非常に役立ちます。
itemLabelEscaped
Mojarra < 2.2.6 のバグ
2.2.6より前の Mojarra の古いバージョンには、値の代わりにまたは値としてvia を指定すると<f:selectItems itemLabel>
、エスケープされていないラベルが誤ってレンダリングされるというバグがありました(問題 3143 )。つまり、ユーザーが制御するデータを を介して項目ラベルとして再表示する場合、XSS ホールの可能性があります。少なくとも Mojarra 2.2.6 にアップグレードできない場合は、それを防ぐために属性を明示的に設定する必要があります。List<T>
<f:selectItems var>
List<SelectItem>
SelectItem[]
List<T>
itemLabelEscaped
true
<f:selectItems value="#{bean.entities}" var="entity" itemValue="#{entity}"
itemLabel="#{entity.someUserControlledProperty}" itemLabelEscaped="true" />
CSRF
javax.faces.ViewState
JSF 2.x には、サーバー側の状態保存を使用する場合、フォームの非表示フィールドのフレーバーで CSRF 防止が既に組み込まれています。JSF 1.x では、この値は非常に弱く、簡単に予測できました (実際には、CSRF 防止を意図したものではありませんでした)。JSF 2.0 では、かなり予測可能なシーケンス値の代わりに、長く強力な自動生成値を使用することでこれが改善され、堅牢な CSRF 防止になります。
JSF 2.2 では、クライアント側の状態の保存が有効になっている場合に、クライアント側の状態を暗号化するための構成可能な AES キーとともに、JSF 仕様の必須部分にすることで、これはさらに改善されます。JSF 仕様の問題 869およびReusing ViewState value in other session (CSRF)も参照してください。JSF 2.2 の新機能は、 による GET リクエストに対する CSRF 保護<protected-views>
です。
のようにステートレス ビューを使用している場合<f:view transient="true">
、またはアプリケーションのどこかに XSS 攻撃ホールがある場合にのみ、CSRF 攻撃ホールの可能性があります。
SQL インジェクション
これは JSF の責任ではありません。これを防ぐ方法は、使用している永続化 API (生の JDBC、最新の JPA、または古き良き Hibernate) によって異なりますが、結局のところ、ユーザー制御の入力を SQL 文字列に連結してはいけません。
String sql = "SELECT * FROM user WHERE username = '" + username + "' AND password = md5(" + password + ")";
String jpql = "SELECT u FROM User u WHERE u.username = '" + username + "' AND u.password = md5('" + password + "')";
エンドユーザーが次の名前を選択するとどうなるか想像してみてください。
x'; DROP TABLE user; --
該当する場合は、常にパラメーター化されたクエリを使用する必要があります。
String sql = "SELECT * FROM user WHERE username = ? AND password = md5(?)";
String jpql = "SELECT u FROM User u WHERE u.username = ?1 AND u.password = md5(?2)";
プレーンな JDBC では、パラメーター値を入力するために使用する必要がPreparedStatement
あり、JPA (および Hibernate) では、Query
オブジェクトはこのためのセッターも提供します。