example crear java tomcat servlets websocket jsr356

java - crear - JSR-356 WebSockets con Tomcat: cómo limitar las conexiones dentro de una única dirección IP?



websocket java netbeans (3)

el objeto socket está oculto en WsSession, por lo que puede usar reflection para obtener la dirección IP. el tiempo de ejecución de este método es de aproximadamente 1 ms. esta solución no es perfecta pero útil.

public static InetSocketAddress getRemoteAddress(WsSession session) { if(session == null){ return null; } Async async = session.getAsyncRemote(); InetSocketAddress addr = (InetSocketAddress) getFieldInstance(async, "base#sos#socketWrapper#socket#sc#remoteAddress"); return addr; } private static Object getFieldInstance(Object obj, String fieldPath) { String fields[] = fieldPath.split("#"); for(String field : fields) { obj = getField(obj, obj.getClass(), field); if(obj == null) { return null; } } return obj; } private static Object getField(Object obj, Class<?> clazz, String fieldName) { for(;clazz != Object.class; clazz = clazz.getSuperclass()) { try { Field field; field = clazz.getDeclaredField(fieldName); field.setAccessible(true); return field.get(obj); } catch (Exception e) { } } return null; }

y la configuración pom es

<dependency> <groupId>javax.websocket</groupId> <artifactId>javax.websocket-all</artifactId> <version>1.1</version> <type>pom</type> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-websocket</artifactId> <version>8.0.26</version> <scope>provided</scope> </dependency>

Hice un JSR-356 @ServerEndpoint en el que quiero limitar conexiones vivas desde una sola dirección IP, para evitar ataques DDOS simples.

Tenga en cuenta que estoy buscando una solución Java (especificaciones JSR-356, Tomcat o Servlet 3.0).

He probado el configurador de punto final personalizado, pero no tengo acceso a la dirección IP incluso en el objeto HandshakeRequest .

¿Cómo limitar el conteo de conexiones JSR-356 desde una sola dirección IP sin software externo como iptables?


De acuerdo con el cliente de Tomcat developer @ mark-thomas, la IP no está expuesta a través de JSR-356 por lo que es imposible implementar dicha función con las API JSR-356 puras.

Tienes que usar un hack bastante feo para evitar la limitación del estándar.

Lo que debe hacerse se reduce a:

  1. Genere a cada usuario un token que contenga su IP en la solicitud inicial (antes de la toma de contacto de websocket)
  2. Pase la ficha por la cadena hasta que llegue a la implementación del punto final

Hay al menos dos opciones de hacky para lograr eso.

Usar HttpSession

  1. Escucha las solicitudes HTTP entrantes con ServletRequestListener
  2. Llame a request.getSession() en la solicitud entrante para asegurarse de que tenga una sesión y almacene la IP del cliente como un atributo de sesión.
  3. Cree un ServerEndpointConfig.Configurator que levante la IP del cliente de HandshakeRequest#getHttpSession y la HandshakeRequest#getHttpSession a EndpointConfig como una propiedad del usuario utilizando el método modifyHandshake .
  4. Obtenga la IP del cliente de las propiedades de usuario de EndpointConfig , guárdela en el mapa o lo que sea y active la lógica de limpieza si el número de sesiones por IP excede un umbral.

También puede usar un @WebFilter lugar de ServletRequestListener

Tenga en cuenta que esta opción puede tener un alto consumo de recursos a menos que su aplicación ya use sesiones, por ejemplo, con fines de autenticación.

Pase IP como un token cifrado en la URL

  1. Cree un servlet o un filtro que se una a un punto de entrada que no sea de websocket. por ejemplo /mychat
  2. Obtenga IP del cliente, encripte con una sal al azar y una clave secreta para generar un token.
  3. Use ServletRequest#getRequestDispatcher para reenviar la solicitud a /mychat/TOKEN
  4. Configure su punto final para usar parámetros de ruta, por ejemplo @ServerEndpoint("/mychat/{token}")
  5. Levante la ficha de @PathParam y descifre para obtener IP del cliente. Guárdelo en el mapa o lo que sea y active la lógica de limpieza si el número de sesiones por IP excede un umbral.

Para facilitar la instalación, es posible que desee generar claves de cifrado en el inicio de la aplicación.

Tenga en cuenta que debe encriptar la IP incluso si está realizando un despacho interno que no es visible para el cliente. No hay nada que impida que un atacante se conecte a /mychat/2.3.4.5 directamente, falsificando así la IP del cliente si no está encriptada.

Ver también:


Si está utilizando Tyrus, que es compatible con JSR-356, puede obtener la dirección IP de la instancia de sesión, pero este es un método no estándar.

Mira aquí.