JSR-356 WebSockets with Tomcat - 如何限制单个 IP 地址内的连接? [英] JSR-356 WebSockets with Tomcat - How to limit connections within single IP address?

查看:16
本文介绍了JSR-356 WebSockets with Tomcat - 如何限制单个 IP 地址内的连接?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我制作了一个 JSR-356 @ServerEndpoint,我想在其中限制来自单个 IP 地址的活动连接,以防止简单的 DDOS 攻击.

I made a JSR-356 @ServerEndpoint in which I want to limit alive connections from single IP address, to prevent simple DDOS attacks.

请注意,我正在搜索 Java 解决方案(JSR-356、Tomcat 或 Servlet 3.0 规范).

Note that I'm search for Java solution (JSR-356, Tomcat or Servlet 3.0 specs).

我尝试过自定义端点配置器,但即使在 HandshakeRequest 对象中,我也无法访问 IP 地址.

I have tried custom endpoint configurer but I don't have access to IP address even in HandshakeRequest object.

如何在没有 iptables 等外部软件的情况下限制单个 IP 地址的 JSR-356 连接数?

推荐答案

据 Tomcat 开发人员@mark-thomas 客户端 IP 通过 JSR-356 公开,因此不可能实现这样的功能使用纯 JSR-356 API-s.

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.

你必须使用一个相当丑陋的 hack 来解决标准的限制.

You have to use a rather ugly hack to work around the limitation of the standard.

需要做的事情归结为:

  1. 在初始请求时(在 websocket 握手之前)为每个用户生成一个包含其 IP 的令牌
  2. 将令牌沿链向下传递,直到到达端点实现

至少有两个 hacky 选项可以实现这一点.

There are at least two hacky options to achieve that.

  1. 使用 ServletRequestListener
  2. 监听传入的 HTTP 请求
  3. 对传入请求调用 request.getSession() 以确保它具有会话并将客户端 IP 存储为会话属性.
  4. 创建一个 ServerEndpointConfig.Configurator,从 HandshakeRequest#getHttpSession 中提取客户端 IP,并使用 作为用户属性将其附加到 EndpointConfig>modifyHandshake 方法.
  5. EndpointConfig 用户属性中获取客户端 IP,将其存储在地图或其他地方,如果每个 IP 的会话数量超过阈值,则触发清理逻辑.
  1. Listen to incoming HTTP requests with a ServletRequestListener
  2. Call request.getSession() on incoming request to ensure it has a session and store client IP as a session attribute.
  3. Create a ServerEndpointConfig.Configurator that lifts client IP from HandshakeRequest#getHttpSession and attaches it to EndpointConfig as a user property using the modifyHandshake method.
  4. Get the client IP from EndpointConfig user properties, store it in map or whatever and trigger cleanup logic if the number of sessions per IP exceeds a threshold.

您也可以使用 @WebFilter 代替 ServletRequestListener

You can also use a @WebFilter instead of ServletRequestListener

请注意,除非您的应用程序已经使用会话,否则此选项可能会消耗大量资源.用于身份验证.

Note that this option can have a high resource consumption unless your application already uses sessions e.g. for authentication purposes.

  1. 创建一个附加到非 websocket 入口点的 servlet 或过滤器.例如/mychat
  2. 获取客户端 IP,使用随机盐和密钥对其进行加密以生成令牌.
  3. 使用ServletRequest#getRequestDispatcher将请求转发到/mychat/TOKEN
  4. 配置您的端点以使用路径参数,例如@ServerEndpoint("/mychat/{token}")
  5. @PathParam 中提取令牌并解密以获取客户端 IP.如果每个 IP 的会话数超过阈值,则将其存储在地图或其他任何内容中并触发清理逻辑.
  1. Create a servlet or a filter that attaches to a non websocket entry point. e.g. /mychat
  2. Get client IP, encrypt it with a random salt and a secret key to generate a token.
  3. Use ServletRequest#getRequestDispatcher to forward the request to /mychat/TOKEN
  4. Configure your endpoint to use path parameters e.g. @ServerEndpoint("/mychat/{token}")
  5. Lift the token from @PathParam and 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.

请注意,即使您正在进行客户端不可见的内部调度,您也需要对 IP 进行加密.没有什么可以阻止攻击者直接连接到 /mychat/2.3.4.5 从而欺骗未加密的客户端 IP.

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.5 directly thus spoofing the client IP if it's not encrypted.

另见:

这篇关于JSR-356 WebSockets with Tomcat - 如何限制单个 IP 地址内的连接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆