Una aplicación web existente se está ejecutando en Tomcat 4.1. Hay un problema de XSS con una página, pero no puedo modificar la fuente. Decidí escribir un filtro de servlet para desinfectar el parámetro antes de que lo vea la página.
Me gustaría escribir una clase de filtro como esta:
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) {
}
}
Pero ServletRequest.setParameter
no existe.
¿Cómo puedo cambiar el valor del parámetro de solicitud antes de pasar la solicitud por la cadena?
java
servlet-filters
Jeremy Stein
fuente
fuente
Respuestas:
Como ha notado
HttpServletRequest
, no tiene un método setParameter. Esto es deliberado, ya que la clase representa la solicitud tal como proviene del cliente, y modificar el parámetro no lo representaría.Una solución es usar la
HttpServletRequestWrapper
clase, que le permite envolver una solicitud con otra. Puede subclasificar eso y anular elgetParameter
método para devolver su valor desinfectado. Luego, puede pasar esa solicitud envuelta enchain.doFilter
lugar de la solicitud original.Es un poco feo, pero eso es lo que la API del servlet dice que debes hacer. Si intenta pasar algo más
doFilter
, algunos contenedores de servlets se quejarán de que ha violado la especificación y se negarán a manipularla.Una solución más elegante requiere más trabajo: modifique el servlet / JSP original que procesa el parámetro, para que espere un atributo de solicitud lugar de un parámetro. El filtro examina el parámetro, lo desinfecta y establece el atributo (uso
request.setAttribute
) con el valor desinfectado. Sin subclases, sin suplantación de identidad, pero requiere que modifique otras partes de su aplicación.fuente
<property name="username" value="[email protected]" /> //Change email on logging in <property name="password" value="*********" />//Change Password on logging in
Para que conste, aquí está la clase que terminé escribiendo:
fuente
Escriba una clase simple que subcalifique
HttpServletRequestWrapper
con un método getParameter () que devuelva la versión desinfectada de la entrada. Luego, pase una instancia de suHttpServletRequestWrapper
to enFilter.doChain()
lugar del objeto de solicitud directamente.fuente
Tuve el mismo problema (cambiar un parámetro de la solicitud HTTP en el Filtro). Terminé usando un
ThreadLocal<String>
. En elFilter
tengo:En mi procesador de solicitudes (
HttpServlet
, controlador JSF o cualquier otro procesador de solicitudes HTTP), recupero el valor del hilo actual:Ventajas:
HttpServletRequestWrapper
calderarequest.setAttribute(String,Object)
, es decir, puede acceder a la variable en otros filtros.Desventajas:
java.util.stream.Stream.parallel
,java.util.concurrent.Future
,java.lang.Thread
.Algunas notas al margen:
El servidor tiene un grupo de subprocesos para procesar las solicitudes HTTP. Dado que esto es piscina:
if (value!=null) { THREAD_VARIABLE.set(value);}
porque reutilizará el valor de la solicitud HTTP anterior cuandovalue
es nulo: los efectos secundarios están garantizados).HttpSession.setAttribute()
@RequestScoped
usa internamente aThreadLocal
, pero usar elThreadLocal
es más versátil: puede usarlo en contenedores que no sean JEE / CDI (por ejemplo, en aplicaciones JRE multiproceso)fuente
@RequestScoped
hace lo mismo internamente)? ¿Las solicitudes múltiples verán el mismo hilo = no (o al menos no tiene garantía)? He editado la respuesta para precisar estos puntos.Esto es lo que terminé haciendo
fuente
Basado en todos sus comentarios, aquí está mi propuesta que funcionó para mí:
nota: queryString () requiere procesar TODOS los valores para cada CLAVE y no olvide encodeUrl () cuando agregue sus propios valores de parámetro, si es necesario
Como limitación, si llama a request.getParameterMap () o cualquier método que llame a request.getReader () y comience a leer, evitará más llamadas a request.setCharacterEncoding (...)
fuente
Puede utilizar la expresión regular para la desinfección. Dentro del filtro antes de llamar al método chain.doFilter (solicitud, respuesta) , llame a este código. Aquí está el código de muestra:
fuente
Prueba
request.setAttribute("param",value);
. Funcionó bien para mí.Encuentre este ejemplo de código:
fuente