Eine vorhandene Webanwendung wird unter Tomcat 4.1 ausgeführt. Es gibt ein XSS-Problem mit einer Seite, aber ich kann die Quelle nicht ändern. Ich habe beschlossen, einen Servlet-Filter zu schreiben, um den Parameter zu bereinigen, bevor er auf der Seite angezeigt wird.
Ich möchte eine Filterklasse wie folgt schreiben:
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) {
}
}
Existiert ServletRequest.setParameter
aber nicht.
Wie kann ich den Wert des Anforderungsparameters ändern, bevor ich die Anforderung an die Kette weitergebe?
java
servlet-filters
Jeremy Stein
quelle
quelle
Antworten:
Wie Sie bereits bemerkt haben,
HttpServletRequest
gibt es keine setParameter-Methode. Dies ist absichtlich, da die Klasse die Anforderung darstellt, wie sie vom Client stammt, und das Ändern des Parameters dies nicht darstellen würde.Eine Lösung besteht darin, die
HttpServletRequestWrapper
Klasse zu verwenden, mit der Sie eine Anforderung mit einer anderen umschließen können. Sie können dies in Unterklassen unterteilen und diegetParameter
Methode überschreiben , um Ihren bereinigten Wert zurückzugeben. Sie können diese umschlossene Anforderung dann anchain.doFilter
anstelle der ursprünglichen Anforderung übergeben.Es ist ein bisschen hässlich, aber genau das sagt die Servlet-API, dass Sie tun sollten. Wenn Sie versuchen, etwas anderes weiterzugeben
doFilter
, beschweren sich einige Servlet-Container, dass Sie gegen die Spezifikation verstoßen haben, und lehnen es ab, damit umzugehen.Eine elegantere Lösung ist mehr Arbeit - das Original - Servlet / JSP ändern, die die Parameter verarbeitet, so dass er eine Anforderung erwartet Attribut anstelle einem Parameter. Der Filter untersucht den Parameter, bereinigt ihn und setzt das Attribut (using
request.setAttribute
) mit dem bereinigten Wert. Keine Unterklassen, kein Spoofing, aber Sie müssen andere Teile Ihrer Anwendung ändern.quelle
<property name="username" value="[email protected]" /> //Change email on logging in <property name="password" value="*********" />//Change Password on logging in
Für die Aufzeichnung ist hier die Klasse, die ich am Ende geschrieben habe:
quelle
Schreiben Sie eine einfache Klasse, die
HttpServletRequestWrapper
mit einer getParameter () -Methode subkalssiert, die die bereinigte Version der Eingabe zurückgibt. Übergeben Sie dann eine Instanz vonHttpServletRequestWrapper
anFilter.doChain()
anstelle des Anforderungsobjekts direkt.quelle
Ich hatte das gleiche Problem (Ändern eines Parameters aus der HTTP-Anforderung im Filter). Am Ende habe ich a verwendet
ThreadLocal<String>
. In der habeFilter
ich:In meinem Anforderungsprozessor (
HttpServlet
, JSF-Controller oder einem anderen HTTP-Anforderungsprozessor) erhalte ich den aktuellen Thread-Wert zurück:Vorteile:
HttpServletRequestWrapper
Boilerplaterequest.setAttribute(String,Object)
, dh Sie können in anderen Filtern auf die Variable zugreifen.Nachteile:
java.util.stream.Stream.parallel
,java.util.concurrent.Future
,java.lang.Thread
.Einige Randnotizen:
Der Server verfügt über einen Thread-Pool zum Verarbeiten der HTTP-Anforderungen. Da dies Pool ist:
if (value!=null) { THREAD_VARIABLE.set(value);}
weil Sie den Wert wiederverwenden von der vorherigen HTTP-Anfrage, wennvalue
null ist: Nebenwirkungen sind garantiert).HttpSession.setAttribute()
@RequestScoped
intern aThreadLocal
, aber die Verwendung vonThreadLocal
ist vielseitiger: Sie können es in Nicht-JEE / CDI-Containern verwenden (z. B. in Multithread-JRE-Anwendungen).quelle
@RequestScoped
intern dasselbe). Werden mehrere Anfragen den gleichen Thread sehen = nein (oder zumindest haben Sie keine Garantie). Ich habe die Antwort bearbeitet, um diese Punkte zu präzisieren.Das habe ich letztendlich getan
quelle
Basierend auf all Ihren Bemerkungen hier ist mein Vorschlag, der für mich funktioniert hat:
Hinweis: Bei queryString () müssen ALLE Werte für jeden KEY verarbeitet werden. Vergessen Sie nicht, encodeUrl () zu verwenden, wenn Sie bei Bedarf eigene Parameterwerte hinzufügen
Wenn Sie request.getParameterMap () oder eine Methode aufrufen, die request.getReader () aufruft und mit dem Lesen beginnt, verhindern Sie als Einschränkung weitere Aufrufe von request.setCharacterEncoding (...).
quelle
Sie können den regulären Ausdruck für die Desinfektion verwenden. Rufen Sie diesen Code im Filter auf, bevor Sie die Methode chain.doFilter (Anfrage, Antwort) aufrufen. Hier ist Beispielcode:
quelle
Versuchen Sie es
request.setAttribute("param",value);
. Es hat gut für mich funktioniert.Bitte finden Sie dieses Codebeispiel:
quelle