我制作了一个JSR-356 @ServerEndpoint
,其中我想限制来自单个IP地址的活动连接,以防止简单的DDOS攻击。
请注意,我正在搜索Java解决方案(JSR-356,Tomcat或Servlet 3.0规范)。
我尝试过自定义端点配置程序,但即使在HandshakeRequest
对象中也无法访问IP地址。
如何在没有iptables等外部软件的情况下限制单个IP地址的JSR-356连接数?
答案 0 :(得分:11)
根据Tomcat开发人员@mark-thomas客户端IP 不通过JSR-356公开,因此用纯JSR-356 API-s实现这样的功能是不可能的。
你必须使用一个相当丑陋的黑客来解决标准的限制。
需要做的事情归结为:
实现这一目标至少有两个hacky选项。
ServletRequestListener
request.getSession()
以确保其具有会话并将客户端IP存储为会话属性。ServerEndpointConfig.Configurator
,将HandshakeRequest#getHttpSession
的客户端IP提升,并使用EndpointConfig
方法将其作为用户属性附加到modifyHandshake
。EndpointConfig
用户属性获取客户端IP,将其存储在地图或其他任何位置,并在每个IP的会话数超过阈值时触发清理逻辑。您还可以使用@WebFilter
代替ServletRequestListener
请注意,除非您的应用程序已使用会话,否则此选项可能会占用大量资源。用于身份验证。
/mychat
ServletRequest#getRequestDispatcher
将请求转发至/mychat/TOKEN
@ServerEndpoint("/mychat/{token}")
@PathParam
提取令牌并解密以获取客户端IP。将其存储在地图或其他任何内容中,并在每个IP的会话数超过阈值时触发清理逻辑。为了便于安装,您可能希望在应用程序启动时生成加密密钥。
请注意,即使您正在进行客户端不可见的内部调度,您也需要加密IP。没有什么可以阻止攻击者直接连接到/mychat/2.3.4.5
,从而欺骗客户端IP(如果它没有加密)。
另见:
答案 1 :(得分:3)
套接字对象隐藏在WsSession中,因此您可以使用反射来获取IP地址。该方法的执行时间约为1ms。这个解决方案并不完美但很有用。
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;
}
并且pom配置为
<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>
答案 2 :(得分:0)
如果您使用的是符合JSR-356标准的Tyrus, 那么你可以从Session实例中获取IP地址,但这是一种非标准的方法。