一尘不染

带有Tomcat的JSR-356 WebSockets-如何限制单个IP地址内的连接?

tomcat

我制作了一个JSR-356 @ServerEndpoint,其中我希望限制单个IP地址的活动连接,以防止简单的DDOS攻击。

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

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

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


阅读 265

收藏
2020-06-16

共1个答案

一尘不染

根据Tomcat开发人员的介绍,@ mark-thomas客户端IP 不会 通过JSR-356公开,因此无法使用纯JSR-356 API-
s实现此类功能。

您必须使用一个相当丑陋的技巧来解决该标准的局限性。

需要做的事情归结为:

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

至少有两个hacky选项可以实现这一目标。

使用HttpSession

  1. 使用侦听传入的HTTP请求 ServletRequestListener
  2. 调用request.getSession()传入请求以确保它具有会话并将客户端IP存储为会话属性。
  3. 使用方法创建一个ServerEndpointConfig.Configurator从中提取客户端IP HandshakeRequest#getHttpSession并将其附加EndpointConfig为用户属性的modifyHandshake
  4. EndpointConfig用户属性获取客户端IP ,将其存储在map或其他内容中,如果每个IP的会话数超过阈值,则触发清除逻辑。

您也可以使用@WebFilter代替ServletRequestListener

请注意,除非您的应用程序已经使用会话(例如出于身份验证目的),否则此选项可能会占用大量资源。

将IP作为加密令牌传递给URL

  1. 创建附加到非websocket入口点的servlet或过滤器。例如/mychat
  2. 获取客户端IP,使用随机盐和密钥对其进行加密以生成令牌。
  3. 用于ServletRequest#getRequestDispatcher将请求转发给/mychat/TOKEN
  4. 配置您的端点以使用路径参数,例如 @ServerEndpoint("/mychat/{token}")
  5. 从中提取令牌@PathParam并解密以获取客户端IP。将其存储在map或其他内容中,如果每个IP的会话数超过阈值,则触发清除逻辑。

为了简化安装,您可能希望在应用程序启动时生成加密密钥。

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

2020-06-16