4

为了工作,我编写了一个专门的 HTTP 服务器,它只为网站执行 301/302/Frame 重定向。最近,一些邪恶的客户端故意打开套接字并每 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 毫秒。

4

1 回答 1

3

经过一定时间后开始关闭套接字。如果套接字保持打开的时间过长,只需将其关闭即可。你可以通过两种方式做到这一点:

您还可以对客户端向您发送请求所需的时间设置时间限制。如果它们不能维持一定水平的吞吐量,请关闭它们。当您的线程通过在开始时添加 System.currentTimeInMillis() 并与您在循环时所处的位置进行比较来读取请求时,这在您的读取循环中非常容易做到。如果它漂移超过某个限制,它们将被关闭并丢弃。

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

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

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

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

于 2011-10-12T03:06:50.157 回答