I made a JSR-356 @ServerEndpoint in which I want to limit alive connections from single IP address, to prevent simple DDOS attacks.
Note that I'm search for Java solution (JSR-356, Tomcat or Servlet 3.0 specs).
I have tried custom endpoint configurer but I don't have access to IP address even in HandshakeRequest object.
How to limit JSR-356 connection count from single IP address without external software like iptables?
According to Tomcat developer @mark-thomas client IP is not exposed via JSR-356 thus it is impossible to implement such a function with pure JSR-356 API-s.
You have to use a rather ugly hack to work around the limitation of the standard.
What needs to be done boils down to:
There are at least two hacky options to achieve that.
Use HttpSession
ServletRequestListenerrequest.getSession()on incoming request to ensure it has a session and store client IP as a session attribute.ServerEndpointConfig.Configuratorthat lifts client IP fromHandshakeRequest#getHttpSessionand attaches it toEndpointConfigas a user property using themodifyHandshakemethod.EndpointConfiguser properties, store it in map or whatever and trigger cleanup logic if the number of sessions per IP exceeds a threshold.You can also use a
@WebFilterinstead ofServletRequestListenerNote that this option can have a high resource consumption unless your application already uses sessions e.g. for authentication purposes.
Pass IP as an encrypted token in the URL
/mychatServletRequest#getRequestDispatcherto forward the request to/mychat/TOKEN@ServerEndpoint("/mychat/{token}")@PathParamand decrypt to get client IP. Store it in map or whatever and trigger cleanup logic if the number of sessions per IP exceeds a threshold.For ease of installation you may wish to generate encryption keys on application startup.
Please note that you need to encrypt the IP even if you are doing an internal dispatch that is not visible to the client. There is nothing that would stop an attacker from connecting to
/mychat/2.3.4.5directly thus spoofing the client IP if it's not encrypted.See also: