如何让客户端等待javajax-RS服务以防止DOS
我遇到了一个web服务问题,用户试图通过在随机ID上循环来猜测应用程序ID 坏的请求来自随机IP,所以我不能仅仅禁止它们的IP(除非我动态地这样做,但我还没有研究) 目前,当我检测到一个客户端进行了10次错误的应用程序ID尝试时,我将其放在我的应用程序的阻止列表中,并拒绝该IP的进一步请求 我希望尽可能减少服务器所需的工作量,因为坏客户端将继续发送1000个请求,即使它们被拒绝。我知道有动态防火墙解决方案,但现在我想在我的应用程序中实现一些简单的解决方案。目前我正在睡眠5秒钟以减少呼叫,但我想做的只是不向客户端发送响应,因此它必须超时 有人知道如何在Java和JAX-RS中做到这一点吗 我的服务就像如何让客户端等待javajax-RS服务以防止DOS,java,web-services,rest,jax-rs,ddos,Java,Web Services,Rest,Jax Rs,Ddos,我遇到了一个web服务问题,用户试图通过在随机ID上循环来猜测应用程序ID 坏的请求来自随机IP,所以我不能仅仅禁止它们的IP(除非我动态地这样做,但我还没有研究) 目前,当我检测到一个客户端进行了10次错误的应用程序ID尝试时,我将其放在我的应用程序的阻止列表中,并拒绝该IP的进一步请求 我希望尽可能减少服务器所需的工作量,因为坏客户端将继续发送1000个请求,即使它们被拒绝。我知道有动态防火墙解决方案,但现在我想在我的应用程序中实现一些简单的解决方案。目前我正在睡眠5秒钟以减少呼叫,但我想做
@Path("/api")
public class MyServer {
@GET
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
@Path("/my-request")
public String myRequest(String type,
@Context HttpServletRequest requestContext,
@Context HttpServletResponse response) {
...
}
见:
有许多可能的解决方案,我想到了您给出的两种可能的解决方案: 1) 使用已支持限制请求的转发代理。我个人已经使用过,并且可以推荐它,部分原因是它设置简单。相关速率限制配置:
2) 用于让检测到的恶意请求超时。可以直接处理Sane请求。但是要小心后果,无论哪种方式,这种方法都会消耗服务器上的资源 我没有试过这个。。。。这只是在黑暗中拍摄的一张照片,所以要谨慎对待。因此,问题是,一旦您检测到可疑的内容并将IP置于块模式,您就不想在该请求上浪费更多资源,也不想让它们浪费时间超时。但如果抛出异常,框架将做出响应。中断当前线程怎么样?您可以通过
Thread.currentThread().interrupt()实现这一点代码>。希望处理请求的Java容器能够检查中断状态。它可能不会那样做。我知道我看到过IO相关类没有处理请求,因为设置了中断标志
编辑:如果中断线程不起作用,也可以尝试抛出InterruptedException。就我所知,在Servlet规范中没有这样的机制。由于JAX-RS实现使用servlet(至少是Jersey和Resteasy),所以在Java中没有实现这一点的标准方法
使用aynchronous JAX-RS的想法比Thread.sleep(5000)
要好,但它仍然会使用一些资源,只是以后处理请求的一种方式,而不是忽略对always的请求。您正在查找JAX-RS支持的请求。包含一些如何实现对请求的异步响应的示例
对于异步响应,负责响应请求的线程将被释放,以便在请求完成之前处理另一个请求。此功能通过添加带有@Suspended
注释的参数激活。此外,您还需要注册一个专门的服务器,该服务器负责在给定的超时后唤醒您的请求,如本例所示:
@Path("/api")
public class MyServer {
private ScheduledExecutorService scheduler = ...;
@GET
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
@Path("/my-request")
public String myRequest(String type,
@Context HttpServletRequest requestContext,
@Context HttpServletResponse response,
@Suspended AsyncResponse asyncResponse) {
scheduler.schedule(new Runnable() {
@Override
public void run() {
asyncResponse.resume(...)
}
}, 5, TimeUnit.SECOND);
}
}
这样,线程就不会在5秒钟的等待时间内被阻塞,从而有机会同时处理其他请求
JAX-RS不提供一种在没有应答的情况下完全丢弃请求的方法。您需要保持连接打开以产生超时,如果您终止连接,将通知用户终止。最好不要回答异步请求,但这仍然会消耗一些资源。如果要避免这种情况,就必须在JAX-RS之外解决这个问题,例如,通过将请求代理给另一台服务器
一种方法是,您可以使用错误代码回答代理的恶意请求,并为此类请求设置非常大的重试限制。我建议将IP拒绝逻辑从REST移动到普通HTTP筛选器:
@WebFilter(urlPatterns = "/*", asyncSupported = true)
@WebListener
public class HttpFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException { }
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
if(denyIP(servletRequest.getRemoteAddr())) {
AsyncContext asyncContext = servletRequest.startAsync();
asyncContext.setTimeout(100000);
}else{
filterChain.doFilter(servletRequest, servletResponse);
}
}
@Override
public void destroy() { }
private boolean denyIP(String address){
//todo
return true;
}
}
对于应用服务器来说更便宜:无需XML/JSON反序列化,无需调用REST类。您可能还注意到,我从未调用asyncContext.start
。我检查了Wildfly 8.2服务器。在这种情况下,Wildfly不会对每个请求使用线程。我发送了很多请求,但线程数量是恒定的
PS
尝试通过在随机ID上循环来猜测应用程序ID
这不是DOS攻击。这是暴力攻击 您可以尝试Tomcat 3.0支持的asyncContext。 此功能将web请求处理程序和处理器解耦。在您的情况下,接受请求的线程必须等待/睡眠超过配置的超时时间。让同一个线程睡眠如此长的时间将使它们挨饿,并将极大地影响服务器的性能。因此,异步处理是正确的方法 我将asyncContext与Java单线程执行器一起使用 这对我很有效。我有类似的商业案例,我不得不模仿我的申请 请参阅此文件以了解实施情况
单线程执行器不会占用资源,它是这个用例的理想选择。我曾经通过创建TCP/IP隧道应用程序解决了类似的问题。 它是一个小型应用程序,侦听外部端口(例如http端口80)。在正常情况下,所有接收到的呼叫都会被接受,从而创建专用的套接字对象这些单独的套接字然后调用真正的(隐藏的)Web服务器,它运行在同一个物理服务器上,或者本地网络中的任何服务器上 隧道本身类似于调度器,但也可以充当负载平衡器。它可以是多功能的 事情是这样的