如何防止拒绝服务在Java中耗尽套接字服务器上的线程池?

时间:2011-10-12 02:54:25

标签: java sockets ddos

对于工作,我编写了一个专门的HTTP服务器,它只对网站执行301/302 /帧重定向。最近,一些邪恶的客户端故意打开套接字并每500毫秒写一个字符以打败我的TCP套接字超时。然后,它们无限期地保持套接字打开,并让多个客户端在分布式拒绝服务中执行相同的操作。这最终耗尽了处理TCP连接的线程池。您如何编写代码以使其不易受到这种不良行为的影响?这是我的套接字代码:

while (true) {
    // Blocks while waiting for a new connection
    log.debug("Blocking while waiting for a new connection.") ;
    try {
        Socket server = httpServer.accept() ; 

        // After receiving a new connection, set the SO_LINGER and SO_TIMEOUT options
        server.setReuseAddress(true) ;
        server.setSoTimeout(timeout) ;
        server.setSoLinger(true, socketTimeout) ;

        // Hand off the new socket connection to a worker thread
        threadPool.execute(new Worker(cache, server, requests, geoIp)) ;
    } catch (IOException e) {
        log.error("Unable to accept socket connection.", e) ;
        continue ;
    }
}

timeout和socketTimeout当前设置为500毫秒。

1 个答案:

答案 0 :(得分:3)

经过一段时间后开始关闭套接字。如果插座已经打开太长时间,请将其关闭。你可以用两种方式做到这一点:

您还可以对客户端向您发送请求所需的时间设置时间限制。如果他们没有维持一定程度的吞吐量,那么关闭em。当您的线程通过在开始时添加System.currentTimeInMillis()并与循环时的位置进行比较来读取请求时,在读取循环中这很容易。如果它漂移超过一定限度,它们将被关闭并掉落。

这个想法的另一个想法可能不是拒绝它们,而是让你的线程返回到池中,但是将套接字放在堆栈上观察。让字节堆积起来,在达到一定大小后,您可以将它们传递给池中的线程进行处理。这种混合方式可以减少它们,也许它们不是很糟糕但很慢。

另一种处理方法是观察线程处理请求的时间长度,如果未在时间限制内完成,请关闭底层套接字。然后线程将获得SocketException,它可以关闭并清理。

以下是其他一些主要涉及使用防火墙,负载平衡器等外部硬件的想法。

https://security.stackexchange.com/questions/114/what-techniques-do-advanced-firewalls-use-to-protect-againt-dos-ddos/792#792