restful jax example java web-services rest jax-rs ddos

example - Cómo dejar al cliente esperando el servicio Java JAX-RS para evitar DOS



jax-rs example (7)

Está buscando respuestas asíncronas compatibles con JAX-RS. El tutorial de Jersey contiene algunos ejemplos sobre cómo implementar una respuesta asincrónica a una solicitud.

Con las respuestas asincrónicas, el hilo que es responsable de una respuesta a una solicitud se libera para gestionar otra solicitud antes de que se complete una solicitud. Esta característica se activa al agregar un parámetro con la anotación @Suspended . Lo que necesitaría hacer adicionalmente, sería registrar un scheduler dedicado que es responsable de despertar sus solicitudes después de un tiempo de espera dado como en este ejemplo:

@Path("/api") public class MyServer { private ScheduledExecutorService scheduler = ...; @GET @Consumes(MediaType.APPLICATION_XML) @Produces(MediaType.APPLICATION_XML) @Path("/my-request") public String myRequest(String type, @Context HttpServletRequest requestContext, @Context HttpServletResponse response, @Suspended AsyncResponse asyncResponse) { scheduler.schedule(new Runnable() { @Override public void run() { asyncResponse.resume(...) } }, 5, TimeUnit.SECOND); } }

De esta forma, no se bloquea ningún hilo por el tiempo de espera de cinco segundos, lo que da la oportunidad de manejar otras solicitudes mientras tanto.

JAX-RS no ofrece una forma de descartar por completo una solicitud sin una respuesta. Deberá mantener la conexión abierta para producir un tiempo de espera, si finaliza la conexión, un usuario no está notificado de la finalización. Lo mejor que podría hacer sería nunca responder a una solicitud asíncrona, pero esto aún consumirá algunos recursos. Si quisiera evitar esto, tendría que resolver el problema fuera de JAX-RS, por ejemplo, enviando el pedido a otro servidor.

Una forma de hacerlo sería configurar mod_proxy donde podría responder al proxy con un código de error para las solicitudes maliciosas y establecer un límite de reintento muy grande para dichas solicitudes.

Tengo un problema con un servicio web en el que los usuarios intentan adivinar las ID de las aplicaciones mediante el uso de ID aleatorios.

Las malas solicitudes provienen de direcciones IP aleatorias, por lo que no puedo simplemente prohibir su IP (a menos que lo haga de forma dinámica, pero aún no estoy investigando eso).

Actualmente, cuando detecto un cliente que ha realizado 10 intentos de identificación de aplicaciones incorrectos, los incluyo en una lista de bloqueo en mi aplicación y rechazo otras solicitudes de esa IP para el día.

Quiero minimizar la cantidad de trabajo que mi servidor necesita hacer, ya que el cliente malo continuará enviando miles de solicitudes aunque sean rechazadas. Sé que hay soluciones dinámicas de Firewall, pero quiero algo fácil de implementar en mi aplicación por ahora. Actualmente estoy durmiendo durante 5 segundos para reducir las llamadas, pero lo que quiero hacer es simplemente no enviar una respuesta al cliente, por lo que tiene que esperar.

Alguien sabe cómo hacer esto en Java, en JAX-RS?

Mi servicio es como,

@Path("/api") public class MyServer { @GET @Consumes(MediaType.APPLICATION_XML) @Produces(MediaType.APPLICATION_XML) @Path("/my-request") public String myRequest(String type, @Context HttpServletRequest requestContext, @Context HttpServletResponse response) { ... }

Ver: Cómo detener el ataque de hack / DOS en la API web


Hasta donde yo sé, en la especificación de Servlet no existe tal mecanismo. Como las implementaciones JAX-RS usan servlets (al menos Jersey y Resteasy), no tiene una forma estándar de lograr eso en Java.

La idea de usar el JAX-RS ayundante es mejor que Thread.sleep(5000) , pero aún utilizará algunos recursos y no es más que una forma de procesar la solicitud más tarde, en lugar de ignorar la solicitud de siempre.


Hay muchas soluciones posibles, con las restricciones que me has dado, me vienen a la mente 2 posibles soluciones:

1) Use un proxy de reenvío que ya tenga soporte para limitar las solicitudes. Personalmente, he usado Nginx y puedo recomendarlo en parte porque es simple de configurar. Configuración de limitación de velocidad relevante: Módulo de límite de solicitud

2) Use JAX-RS asíncrono para permitir el tiempo de espera de la solicitud maliciosa que ha detectado. Una buena solicitud puede procesarse directamente. ¡Pero cuidado con las consecuencias, de cualquier forma, tal enfoque consumirá recursos en el servidor!


No lo he intentado ... solo un tiro en la oscuridad aquí, así que tómalo con un grano de sal. Entonces, el problema es que una vez que detecta algo sospechoso y pone la IP en modo bloque, no quiere desperdiciar ni un ápice de recursos en esta solicitud y también puede hacer que pierda tiempo. Pero su marco responderá si lanza una excepción. ¿Qué hay de la interrupción de su hilo actual? Puedes hacerlo por Thread.currentThread().interrupt(); . La esperanza es que el contenedor de Java que procesa la solicitud verifique el estado de la interrupción. Puede que no esté haciendo eso. Sé que he visto clases relacionadas con IO que no procesan solicitudes porque se estableció el indicador de interrupción.

EDITAR: Si la interrupción de su hilo no funciona, también puede intentar lanzar una InterruptedException. Puede lograr el efecto deseado.


Puede probar asyncContext compatible con Tomcat 3.0. Esta característica desacopla el manejador de solicitudes web y el procesador. En su caso, el hilo que acepta la solicitud tiene que esperar / dormir más que el tiempo de espera configurado. Hacer que el hilo duerma durante tanto tiempo los mataría de hambre y afectaría drásticamente el rendimiento de los servidores. Entonces, el procesamiento asíncrono es el camino correcto a seguir.

He usado asyncContext con Java single thread executor http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html Me funcionó bien. Tuve un caso comercial similar, donde tuve que burlarme de mi aplicación.

Refiera esto para la implementación http://peter-braun.org/2013/04/asynchronous-processing-from-servlet-3-0-to-jax-rs-2-0/

El ejecutor de subproceso único no consumiría recursos y es ideal para este caso de uso.


Puedo sugerir mover IP denegar la lógica de REST al filtro HTTP simple:

@WebFilter(urlPatterns = "/*", asyncSupported = true) @WebListener public class HttpFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { if(denyIP(servletRequest.getRemoteAddr())) { AsyncContext asyncContext = servletRequest.startAsync(); asyncContext.setTimeout(100000); }else{ filterChain.doFilter(servletRequest, servletResponse); } } @Override public void destroy() { } private boolean denyIP(String address){ //todo return true; } }

Es más económico para el servidor de aplicaciones: sin deserialización XML / JSON, sin llamadas a clases REST. También puede observar que nunca llamo asyncContext.start . Reviso el servidor Wildfly 8.2. En este caso, Wildfly no usa hilo por solicitud. Envié muchas solicitudes, pero la cantidad de hilos fue constante.

PD

tratando de adivinar las identificaciones de las aplicaciones mediante el bucle sobre identificadores aleatorios

No es un ataque de DOS. Es un ataque de fuerza bruta.


Una vez resolví un problema similar al crear una aplicación de túnel TCP / IP.

Es una pequeña aplicación que escucha un puerto externo (por ejemplo, el puerto http 80). En condiciones normales, se aceptan todas las llamadas recibidas, creando objetos de socket dedicados. Estos sockets individuales llaman al servidor web real (oculto) , que se ejecuta en el mismo servidor físico, o cualquier servidor dentro de su red local.

El túnel en sí es como un despachador , pero también puede actuar como un equilibrador de carga . Puede ser multifuncional.

El problema es que estás trabajando a bajo nivel con conectores en este punto. Si entrega una lista de direcciones IP prohibidas a esta aplicación, puede excluir aplicaciones en un nivel muy bajo (sin aceptar siquiera sus llamadas de socket).

También puede integrar esto en la misma aplicación Java. Pero creo que es más flexible considerar esto como una aplicación separada.

(Avíseme si necesita algún código fuente, es posible que tenga algún código para comenzar)