Une application Web existante s'exécute sur Tomcat 4.1. Il y a un problème XSS avec une page, mais je ne peux pas modifier la source. J'ai décidé d'écrire un filtre de servlet pour nettoyer le paramètre avant qu'il ne soit vu par la page.
Je voudrais écrire une classe Filter comme celle-ci:
import java.io.*;
import javax.servlet.*;
public final class XssFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
String badValue = request.getParameter("dangerousParamName");
String goodValue = sanitize(badValue);
request.setParameter("dangerousParamName", goodValue);
chain.doFilter(request, response);
}
public void destroy() {
}
public void init(FilterConfig filterConfig) {
}
}
Mais ServletRequest.setParameter
n'existe pas.
Comment puis-je modifier la valeur du paramètre de demande avant de transmettre la demande dans la chaîne?
java
servlet-filters
Jeremy Stein
la source
la source
Réponses:
Comme vous l'avez noté, il
HttpServletRequest
n'y a pas de méthode setParameter. Ceci est délibéré, car la classe représente la demande telle qu'elle provient du client et la modification du paramètre ne le représenterait pas.Une solution consiste à utiliser la
HttpServletRequestWrapper
classe, qui vous permet d'encapsuler une requête avec une autre. Vous pouvez sous-classer cela et remplacer lagetParameter
méthode pour renvoyer votre valeur filtrée. Vous pouvez ensuite transmettre cette demande encapsulée à lachain.doFilter
place de la demande d'origine.C'est un peu moche, mais c'est ce que l'API de servlet dit que vous devriez faire. Si vous essayez de transmettre autre chose à
doFilter
, certains conteneurs de servlet se plaindront que vous avez enfreint la spécification et refuseront de le gérer.Une solution plus élégante demande plus de travail - modifiez le servlet / JSP d'origine qui traite le paramètre, de sorte qu'il attend un attribut de requête au lieu d'un paramètre. Le filtre examine le paramètre, le nettoie et définit l'attribut (en utilisant
request.setAttribute
) avec la valeur filtrée. Pas de sous-classement, pas d'usurpation d'identité, mais vous oblige à modifier d'autres parties de votre application.la source
<property name="username" value="[email protected]" /> //Change email on logging in <property name="password" value="*********" />//Change Password on logging in
Pour mémoire, voici le cours que j'ai fini par écrire:
la source
Écrivez une classe simple qui se sous-calcule
HttpServletRequestWrapper
avec une méthode getParameter () qui renvoie la version filtrée de l'entrée. Passez ensuite directement une instance de votreHttpServletRequestWrapper
àFilter.doChain()
au lieu de l'objet de requête.la source
J'ai eu le même problème (changer un paramètre de la requête HTTP dans le filtre). J'ai fini par utiliser un fichier
ThreadLocal<String>
. Dans leFilter
j'ai:Dans mon processeur de requêtes (
HttpServlet
, contrôleur JSF ou tout autre processeur de requêtes HTTP), je récupère la valeur de thread actuelle:Avantages:
HttpServletRequestWrapper
partoutrequest.setAttribute(String,Object)
, c'est-à-dire que vous pouvez accéder à la variable dans d'autres filtreurs.Désavantages:
java.util.stream.Stream.parallel
,java.util.concurrent.Future
,java.lang.Thread
.Quelques notes secondaires:
Le serveur dispose d'un pool de threads pour traiter les requêtes HTTP. Puisqu'il s'agit d'une piscine:
if (value!=null) { THREAD_VARIABLE.set(value);}
parce que vous allez réutiliser la valeur de la requête HTTP précédente quandvalue
est nul: les effets secondaires sont garantis).HttpSession.setAttribute()
@RequestScoped
utilise en interne aThreadLocal
, mais son utilisationThreadLocal
est plus polyvalente: vous pouvez l'utiliser dans des conteneurs non JEE / CDI (par exemple dans des applications JRE multithread)la source
@RequestScoped
fait la même chose en interne). Les requêtes multiples verront-elles le même fil = non (ou du moins vous n'avez aucune garantie). J'ai édité la réponse pour préciser ces points.C'est ce que j'ai fini par faire
la source
Sur la base de toutes vos remarques, voici ma proposition qui a fonctionné pour moi:
note: queryString () nécessite de traiter TOUTES les valeurs de chaque KEY et n'oubliez pas d'encodeUrl () lors de l'ajout de vos propres valeurs de param, si nécessaire
En guise de limitation, si vous appelez request.getParameterMap () ou toute autre méthode qui appellerait request.getReader () et commencer à lire, vous éviterez tout autre appel à request.setCharacterEncoding (...)
la source
Vous pouvez utiliser l' expression régulière pour la désinfection. À l'intérieur du filtre avant d'appeler la méthode chain.doFilter (demande, réponse) , appelez ce code. Voici un exemple de code:
la source
Essayez
request.setAttribute("param",value);
. Cela a bien fonctionné pour moi.Veuillez trouver cet exemple de code:
la source