如何处理套接字中的网络端口滥用问题

时间:2013-01-03 19:54:26

标签: c++ c sockets networking tcp

我有一个用c ++编写的web应用程序,使用TCP / IP通过在Linux上运行的标准网络套接字。该服务对野生和羊毛互联网开放。

我会定期收到来自运行自动脚本的垃圾邮件发送者的滥用请求。我可以检测到这些并关闭套接字。现在我只是做一个礼貌的套接字关闭,就像我对已经完成的任何有效请求所做的那样,套接字lib接近这样:

close( mSocket );

但有时关闭套接字通常会通知垃圾邮件脚本套接字连接已终止,并立即发起另一个欺诈请求。

终止TCP / IP连接的最佳方法是什么,它可以清理系统上的打开套接字,但会使远程方挂起。这就是我希望以对我来说成本最低的方式关闭套接字,但是它们的成本最高。

@Nicholas Wilson:

使用TCP_REPAIR似乎是一个好主意。在TCP_REPAIR模式下关闭套接字时,不会发送FIN或RST数据包。远程插座悬空。我打算试试并报告。这是我的(未经测试的)代码:

if ( abuse )
{
   int aux = 1;
   if ( setsockopt( mSocket, SOL_TCP, TCP_REPAIR, &aux, sizeof( aux )) < 0 )
      reportError( "Tried to do a rude socket close... but could not turn on repair mode.\n" );
}
close( mSocket );

我会报告这是否有效。 (@edit:测试答案如下)

@“保持套接字开放”的想法:

这有效,但是次优。攻击者可以使用开放式套接字使系统饱和。每个请求都会创建一个保持打开的新套接字。有了DOS攻击,你最终会用尽套接字。

然后管理开放套接字也存在问题:

  1. 只是不要关闭它。打开套接字永远存在。攻击者的代价:高 - 他们没有鳍。我的成本:更高。我的所有文件描述符最终都会被使用。
  2. 每个插槽生成一个线程以休眠10分钟,然后关闭套接字。攻击者的代价:高 - 他们没有鳍。我的成本:更高。虽然我最终关闭套接字,但对于每个请求,我的套接字耗尽的时间比攻击者用的时间长,并且我有一个线程的开销。
  3. 生成一个处理所有滥用套接字到期的线程。攻击者的代价:高 - 他们没有鳍。我的成本:更高。像2一样,很多插座都是敞开的。管理它的单个线程的开销。代码复杂,令人烦恼。

4 个答案:

答案 0 :(得分:4)

好的,做了一些研究,我有一个适合我的答案,基于TCP_REPAIR。它比我刚开始想的要复杂一点:

if ( abuse )
{
   // read some bytes from the spammer - to establish the connection
   u32 tries = 20;
   while ( tries )
   {
      sleep( 1000 );
      char tmpBuf[32];
      s32 readCount = recv( mSocket, &tmpBuf[0], 32, 0 );
      if ( readCount > -1 ) break;
      tries--;
   }
#ifdef TCP_REPAIR
   int aux = 1;
   if ( setsockopt( mSocket, SOL_TCP, TCP_REPAIR, &aux, sizeof( aux )) < 0 )
   {
     reportError( "could not turn on repair mode" );
   }
#else // !TCP_REPAIR
   // no TCP REPAIR - best we can do is an abort close
   struct linger so_linger;
   so_linger.l_onoff = 1;
   so_linger.l_linger = 0;
   if ( setsockopt( mSocket, SOL_SOCKET, SO_LINGER, &so_linger, sizeof so_linger ) < 0  )
   {
      reportError( "Cannot turn off SO_LINGER" );
   }
#endif // TCP_REPAIR
}
close( mSocket );

在内核级别,如果关闭连接,TCP堆栈将发送FIN或RST数据包,无论您如何操作(关闭或关闭)。无论哪种方式,都会通知攻击者您已关闭连接。

我们希望默默地关闭连接,让他们等待,意识到你没有回答......因为我们是报复性的。

TCP_REPAIR是一个新的套接字API,旨在允许您“冻结”套接字,保存其状态,并在另一个进程甚至另一个系统上重新加载套接字状态。在正常使用情况下,客户端永远不会知道他们的连接已转移到其

但是我们可以滥用这个API,我们将套接字置于修复模式,但不保存其状态并且永远不会恢复它。当我们在修复模式下关闭套接字时 - 它会被静默删除。

这适用于已经开始的滥用请求。那就是我们已经阅读了垃圾邮件发送者的请求,并认定这是欺诈行为,TCP_REPAIR将其杀死。

但是如果您在连接之后通过IP阻止请求,而没有先读取套接字,则会以某种方式通知远程方。他们获得了RST。或者可能连接中的某些内容从未完全完成,远程系统几乎立即中止请求。

所以我们先从黑客的socket读取几个字节。在我的情况下,套接字已经处于非阻塞模式。但是如果不是你想要将套接字设置为非阻塞,或者你打开自己的黑客开放连接,但不发送数据包并让你的服务器挂起 - 就像你打算对他做的那样。如果在几微秒之后你没有得到一个数据包,你就会把他关闭。

但如果你从他那里读了几个字节,那么他的程序就会等待你的回复永远不会来。

TCP_REPAIR仅适用于Linux Kernel 3.5及更高版本。在那之下,我能做的最好的是一个'脏'插座关闭。这是他送你和RST而不是给他发送FIN的地方。它看起来像是从未建立过有效的连接。为此,关闭SO_LINGER,基本上打破套接字连接关闭握手,然后调用close。

像魅力一样,将浏览器指向此处:

http://oroboro.com/fail

Chrome至少会在那里停留5-10秒。看看我的日志,我每秒得到10次点击 - 他只能每10秒左右打我一次。从我的系统加载:0。

见ya sucker!

答案 1 :(得分:3)

当您检测到恶意客户端时,我建议您不要关闭连接,还要拒绝来自同一IP地址的任何新连接。

至少可以做的是将应用程序中的IP列入黑名单。保留一个禁止的IP地址列表,并立即关闭任何来自该列表上IP的接受套接字。

但是为了保护更多资源,在网络架构中进一步阻止连接会更好。如果能够这样做,请通知网关路由器阻止它。如果那是不可能的,请尝试让负载均衡器阻止它。如果做不到这一点,至少要将规则添加到服务器的本地防火墙。

但请记住,许多此类攻击来自消费级互联网连接(无论用户是否知晓)。这通常意味着他们的IP地址被分配并定期动态重新分配。几天前垃圾邮件发送者使用的IP现在可能被合法用户使用。因此,基于IP的禁令不应该永远存在。

答案 2 :(得分:1)

使用此:

#include <sys/socket.h>

int shutdown(int socket, int how);

它会立即发送RST并关闭(连接)。这似乎表明,该端口上没有服务,攻击者希望停止在该端口上发送垃圾邮件。致电close()以释放手柄。

答案 3 :(得分:0)

当您检测到abuse

时 当你使用其中一个套接字检测到abuse将它们放入锅中时,

为“垃圾邮件发送者”设置了一个套接字池。如果没有可用的空闲套接字,则回收最旧的套接字,然后关闭并关闭它。

如果连接符合!abuse条件,请让他们使用正确的套接字。