如何让客户端等待Java JAX-RS服务来阻止DOS

问题描述 投票:24回答:7

我遇到了一个Web服务的问题,用户试图通过循环随机ID来猜测应用程序ID。

坏请求来自随机IP,所以我不能只禁止他们的IP(除非我动态地做,但我还没有考虑过)。

目前,当我检测到已经进行了10次不良应用ID尝试的客户端时,我将它们放在我的应用中的阻止列表中,并拒绝当天该IP的进一步请求。

我想尽量减少我的服务器需要做的工作量,因为坏客户端将继续发送1000个请求,即使它们被拒绝。我知道有动态防火墙解决方案,但现在想要在我的应用程序中轻松实现。目前我正在睡觉5秒以减少呼叫,但我想要做的只是不向客户端发送响应,因此它必须超时。

任何人都知道如何在JAX-RS中用Java做到这一点?

我的服务就像,

@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) {
...
}

见:How to stop hack/DOS attack on web API

java web-services rest jax-rs ddos
7个回答
8
投票

您正在寻找JAX-RS支持的asynchronous responsestutorial for Jersey包含一些如何实现对请求的异步响应的示例。

使用异步响应,负责回答请求的线程将在请求完成之前处理另一个请求。通过使用@Suspended注释添加参数来激活此功能。你还需要做的是注册一个专用的scheduler,负责在给定的超时后唤醒你的请求,如下例所示:

@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之外的问题,例如通过代理另一台服务器的请求。

一种方法是使用set up mod_proxy,您可以使用错误代码回答代理,以查找恶意请求,并为此类请求设置非常大的重试限制。


4
投票

有许多可能的解决方案,您已经给出了限制,我想到了两种可能的解决方案:

1)使用已经支持限制请求的转发代理。我个人使用过Nginx,可以部分推荐它,因为它很容易设置。相关的速率限制配置:Limit Req Module

2)使用Asynchronous JAX-RS来超时检测到的恶意请求。可以直接处理Sane请求。但要注意后果,这种方法会消耗服务器上的资源!


4
投票

我可能会建议将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攻击。这是暴力攻击。


1
投票

您可以尝试从Tomcat 3.0支持的asyncContext。此功能将Web请求处理程序和处理程序分离。在您的情况下,接受请求的线程必须等待/休眠超过配置的超时。让相同的线程睡眠这么长时间会使他们饿死,这会严重影响服务器的性能。因此,异步处理是正确的方法。

我使用asyncContext与Java单线程执行器http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html它对我很有用。我有类似的商业案例,我不得不模仿我的申请。

请参阅此实现http://peter-braun.org/2013/04/asynchronous-processing-from-servlet-3-0-to-jax-rs-2-0/

单线程执行器不会占用资源,也不适合这种用例。


0
投票

我没有尝试过这个......只是在黑暗中拍摄,所以带上一粒盐。所以问题在于,一旦你发现了一些可疑的东西并将IP置于块模式,你就不希望在这个请求上浪费另外的资源,并且还会浪费时间超时。但是如果抛出异常,您的框架将会响应。打断你当前的线程怎么样?你可以通过Thread.currentThread().interrupt();来做到这一点。希望处理请求的Java容器将检查中断状态。它可能不会这样做。我知道我已经看到IO相关类没有处理请求,因为设置了中断标志。

编辑:如果中断您的线程不起作用,您也可以尝试抛出InterruptedException。它可能会达到预期的效果。


0
投票

据我所知,在Servlet规范中没有这样的机制。由于JAX-RS实现使用servlet(至少是Jersey和Resteasy),因此没有一种标准方法可以在Java中实现。

使用异步JAX-RS的想法比Thread.sleep(5000)更好,但它仍然会使用一些资源,只是一种处理请求的方法,而不是忽略总是请求。


0
投票

我曾经通过创建TCP / IP隧道应用程序解决了类似的问题。

它是一个小型应用程序,可以监听外部端口(例如http端口80)。在正常情况下,接受所有接收的呼叫,创建专用套接字对象。然后,这些单个套接字将调用真实(隐藏)Web服务器,该服务器在同一物理服务器或本地网络中的任何服务器上运行。

隧道本身就像一个调度员,但也可以像一个负载均衡器。它可以是多功能的。

问题是,此时你正在使用套接字进行低级操作。如果你将一个禁止的ip-address列表交给这个应用程序,那么它可以在很低的级别上关闭应用程序(甚至根本不接受它们的套接字调用)。

您也可以将它集成到同一个Java应用程序中。但我认为将此视为单独的应用程序更为灵活。

(如果您需要一些源代码,请告诉我,我可能会有一些代码可以帮助您入门)

© www.soinside.com 2019 - 2024. All rights reserved.