Istniejąca aplikacja internetowa działa na Tomcat 4.1. Wystąpił problem z XSS na stronie, ale nie mogę zmodyfikować źródła. Zdecydowałem się napisać filtr serwletów, aby oczyścić parametr, zanim zostanie on zauważony przez stronę.
Chciałbym napisać taką klasę filtru:
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) {
}
}
Ale ServletRequest.setParameter
nie istnieje.
Jak mogę zmienić wartość parametru żądania przed przekazaniem żądania w dół łańcucha?
java
servlet-filters
Jeremy Stein
źródło
źródło
Odpowiedzi:
Jak zauważyłeś
HttpServletRequest
, nie ma metody setParameter. Jest to celowe, ponieważ klasa reprezentuje żądanie w takiej postaci, w jakiej pochodziło od klienta, a modyfikacja parametru tego nie reprezentuje.Jednym z rozwiązań jest użycie
HttpServletRequestWrapper
klasy, która pozwala zawijać jedno żądanie drugim. Możesz to podklasować i zastąpićgetParameter
metodę, aby zwrócić oczyszczoną wartość. Następnie możesz przekazać to opakowane żądaniechain.doFilter
zamiast pierwotnego żądania.To trochę brzydkie, ale to właśnie mówi API serwletów, co powinieneś zrobić. Jeśli spróbujesz przekazać cokolwiek innego
doFilter
, niektóre kontenery serwletów będą narzekać, że naruszyłeś specyfikację, i odmówią obsługi tego.Bardziej eleganckie rozwiązanie to więcej pracy - zmodyfikuj oryginalny serwlet / JSP, który przetwarza parametr, tak aby oczekiwał atrybutu żądania zamiast parametru. Filtr sprawdza parametr, oczyszcza go i ustawia atrybut (używając
request.setAttribute
) na wartość oczyszczoną. Bez podklas, bez fałszowania, ale wymaga modyfikacji innych części aplikacji.źródło
<property name="username" value="[email protected]" /> //Change email on logging in <property name="password" value="*********" />//Change Password on logging in
Dla przypomnienia, oto klasa, którą napisałem:
źródło
Napisz prostą klasę, która poddaje podskalowanie
HttpServletRequestWrapper
za pomocą metody getParameter (), która zwraca oczyszczoną wersję danych wejściowych. Następnie przekaż swoje wystąpienie bezpośrednioHttpServletRequestWrapper
doFilter.doChain()
zamiast obiektu żądania.źródło
Miałem ten sam problem (zmiana parametru z żądania HTTP w filtrze). Skończyło się na użyciu
ThreadLocal<String>
. WFilter
mam:W moim procesorze żądań (
HttpServlet
kontrolerze JSF lub jakimkolwiek innym procesorze żądań HTTP) otrzymuję z powrotem aktualną wartość wątku:Zalety:
HttpServletRequestWrapper
szablonowyrequest.setAttribute(String,Object)
, tj. możesz uzyskać dostęp do zmiennej w innych filtrach.Niedogodności:
java.util.stream.Stream.parallel
,java.util.concurrent.Future
,java.lang.Thread
.Kilka uwag dodatkowych:
Serwer ma pulę wątków do przetwarzania żądań HTTP. Ponieważ to jest pula:
if (value!=null) { THREAD_VARIABLE.set(value);}
ponieważ ponownie użyjesz wartości z poprzedniego żądania HTTP, gdyvalue
ma wartość null: efekty uboczne są gwarantowane).HttpSession.setAttribute()
@RequestScoped
wewnętrznie używa aThreadLocal
, ale użycieThreadLocal
jest bardziej wszechstronne: można go używać w kontenerach innych niż JEE / CDI (np. W wielowątkowych aplikacjach JRE)źródło
@RequestScoped
wewnętrznie robi to samo). Czy wiele żądań zobaczy ten sam wątek = nie (lub przynajmniej nie masz żadnej gwarancji). Zredagowałem odpowiedź, aby uściślić te punkty.Oto, co ostatecznie zrobiłem
źródło
Na podstawie wszystkich twoich uwag oto moja propozycja, która zadziałała dla mnie:
uwaga: queryString () wymaga przetworzenia WSZYSTKICH wartości dla każdego KLUCZA i nie zapomnij o encodeUrl () podczas dodawania własnych wartości parametrów, jeśli jest to wymagane
W ramach ograniczenia, jeśli wywołasz request.getParameterMap () lub jakąkolwiek metodę, która wywoła request.getReader () i zaczniesz czytać, zapobiegniesz dalszym wywołaniom request.setCharacterEncoding (...)
źródło
Możesz użyć wyrażenia regularnego do odkażania. Wewnątrz filtru przed wywołaniem metody chain.doFilter (żądanie, odpowiedź) wywołaj ten kod. Oto przykładowy kod:
źródło
Spróbuj
request.setAttribute("param",value);
. U mnie to działało dobrze.Znajdź ten przykładowy kod:
źródło