XSS
JSF est conçu pour avoir une prévention XSS intégrée. Vous pouvez réafficher en toute sécurité tous entrée contrôlée par l'utilisateur (en-têtes de demande (y compris les cookies !), paramètres de demande (également ceux qui sont enregistrés dans la base de données !) et corps de demande (fichiers texte téléchargés, etc.)) en utilisant n'importe quel composant JSF.
<h:outputText value="#{user.name}" />
<h:outputText value="#{user.name}" escape="true" />
<h:inputText value="#{user.name}" />
etc...
Notez que si vous utilisez JSF 2.0 sur Facelets, vous pouvez utiliser EL dans le texte du modèle comme suit :
<p>Welcome, #{user.name}</p>
Ceci sera aussi implicitement échappé. Vous n'avez pas nécessairement besoin de <h:outputText>
ici.
Seulement quand vous êtes explicitement Décomposition de l'entrée contrôlée par l'utilisateur en utilisant escape="false"
:
<h:outputText value="#{user.name}" escape="false" />
alors vous avez un trou potentiel d'attaque XSS !
Si vous souhaitez réafficher les entrées contrôlées par l'utilisateur sous forme de HTML, et si vous souhaitez n'autoriser qu'un sous-ensemble spécifique de balises HTML telles que <b>
, <i>
, <u>
etc., alors vous devez assainir l'entrée par une liste blanche. L'analyseur HTML Jsoup est très utile dans ce.
itemLabelEscaped
bogue dans Mojarra < 2.2.6
Anciennes versions de Mojarra avant 2.2.6 avait le bug dans lequel <f:selectItems itemLabel>
rend de manière incorrecte le libellé non encodé lorsqu'il est fourni avec un fichier List<T>
via <f:selectItems var>
au lieu de List<SelectItem>
o SelectItem[]
comme valeur ( numéro 3143 ). En d'autres termes, si vous réaffichez des données contrôlées par l'utilisateur sous la forme d'étiquettes d'éléments via un fichier de type List<T>
alors vous avez une faille XSS potentielle. Si la mise à jour vers au moins Mojarra 2.2.6 n'est pas une option, alors vous devez explicitement configurer itemLabelEscaped
à l'attribut true
pour empêcher cela.
<f:selectItems value="#{bean.entities}" var="entity" itemValue="#{entity}"
itemLabel="#{entity.someUserControlledProperty}" itemLabelEscaped="true" />
CSRF
JSF 2.x dispose déjà d'une prévention CSRF intégrée dans la saveur de javax.faces.ViewState
champ caché dans le formulaire lors de l'utilisation de l'enregistrement de l'état côté serveur. Dans JSF 1.x, cette valeur était plutôt faible et trop facilement prévisible (elle n'a jamais été conçue comme une prévention CSRF). Dans JSF 2.0, cela a été amélioré en utilisant une valeur autogénérée longue et forte au lieu d'une valeur de séquence plutôt prévisible, ce qui en fait une prévention CSRF robuste.
Dans JSF 2.2, cette fonction est encore améliorée en en faisant une partie obligatoire de la spécification JSF, avec une clé AES configurable pour chiffrer l'état du côté client, au cas où la sauvegarde de l'état du côté client est activée. Voir aussi Question de la spécification JSF 869 y Réutilisation de la valeur ViewState dans une autre session (CSRF) . La nouveauté de JSF 2.2 est la protection CSRF sur les demandes GET en <protected-views>
.
Seulement quand vous utilisez des vues sans état comme dans <f:view transient="true">
ou s'il y a un trou d'attaque XSS dans l'application, il y a un trou d'attaque CSRF potentiel.
Injection SQL
Ce n'est pas la responsabilité de JSF. La façon d'éviter cela dépend de l'API de persistance que vous utilisez (JDBC brut, JPA moderne ou le bon vieux Hibernate), mais tout se résume à ce qui suit jamais concaténer les entrées contrôlées par l'utilisateur en chaînes SQL comme suit
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 + "')";
Imaginez ce qui se passerait si l'utilisateur final choisissait le nom suivant :
x'; DROP TABLE user; --
Vous devez toujours utiliser des requêtes paramétrées, le cas échéant.
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)";
En JDBC classique, vous devez utiliser PreparedStatement
pour remplir les valeurs des paramètres et dans JPA (et Hibernate), l'élément Query
offre également des paramètres pour cela.