5

我正在阅读Richard Stevens 的UNIX Network Programming Volume 1 并尝试编写一个使用 Telnet 协议的 TCP Echo Client。我仍处于早期阶段并尝试编写读写函数。

我想写它来使用 I/O 多路复用和 Select 函数,因为它需要是多客户端的,我不想在尝试学习 Berkeley Sockets 库时尝试学习 C++ 线程同时。在 I/O 多路复用一章的末尾,Stevens 有一小节介绍 DOS 攻击,他说我计划使用的方法容易受到 DOS 攻击,这种攻击在连接后只发送一个字节然后挂起。之后他提到了 3 种可能的解决方案——非阻塞 IO、线程(出)和对 I/O 操作设置超时。

我的问题是,还有其他方法可以避免这种攻击吗?如果不是,其中哪一个是最好的?我浏览了关于设置操作超时的部分,但它看起来不像我想做的事情。他建议的方法看起来很复杂,我不知道如何将它们变成我已经拥有的。我只看了关于 NIO 的章节,看起来这是现在要走的路,但我想看看是否有其他方法可以解决这个问题,然后再花几个小时浏览这一章。

有任何想法吗?

4

5 回答 5

4

基本阅读:C10K 问题

每个连接使用线程(或进程)可以生成非常简单的代码。连接数的限制实际上是您的系统可以轻松执行多任务的线程数的限制。

使用异步 IO 将所有套接字放在单个线程中并不是那么简单的代码(由 libevent 和libev2很好地包装),但更具可扩展性 - 它受系统允许的打开文件句柄数量的限制 - 例如最近的 linux 构建- 可以以百万计!由于这个原因,大多数 Web 服务器和其他服务器使用异步 IO。

但是,您的服务器仍然是一种可能会耗尽的有限资源,并且存在比简单地耗尽处理新连接的能力更严重的攻击。

防火墙和损坏限制(例如备份、DMZ 等)是真正面向 Internet 的服务中必不可少的元素。

于 2009-08-22T22:43:22.083 回答
3

...有没有其他方法可以避免这种攻击?

是的,异步 I/O是另一种通用方法。

如果问题是阻塞read()可能会无限期暂停您的执行,那么您的一般对策是:

  1. 有多个执行线程

    多线程,多进程,两者兼而有之。

  2. 限时阻塞操作

    例如,瞬时(非阻塞 I/O),或不是(SO_RCVTIMEO,,alarm()等)

  3. 异步操作

    例如,aio_read

……哪一个是最好的?

对于新手,我建议将非阻塞 I/O 与限时select()/结合使用poll()。您的应用程序可以跟踪连接是否在“足够短的时间内”生成了“足够的数据”(例如,整行)。

这是一种功能强大、可移植且常用的技术。

但是,更好的答案是“视情况而定”。平台支持,更重要的是,这些选择的设计后果必须根据具体情况进行评估。

于 2009-08-23T03:07:12.917 回答
2

如果您刚刚开始学习套接字编程,您可能最好专注于套接字的基本功能,而暂时不要太担心安全问题。当您编写了一些客户端-服务器应用程序并彻底了解它们的工作原理时,您将能够更好地了解它们是如何破坏.

保护面向 Internet 的网络应用程序免受恶意客户端的攻击并非易事,并且可能涉及您提到的所有高级技术,然后是一些!例如,将一些责任从应用程序代码转移到路由器或防火墙级别是很常见的。您可以限制对受信任主机的访问,或者检测过多的连接尝试并在流量到达您的应用程序之前限制或阻止它们。

于 2009-08-22T22:20:14.390 回答
1

我的问题是,还有其他方法可以避免这种攻击吗?

对于服务器,我想要一个应用程序级别的计时器:

  • 每个连接的输入数据缓冲区
  • 哑套接字读取代码将数据从套接字读取到输入缓冲区
  • 特定于应用程序的代码解析输入缓冲区的内容

特定于应用程序的代码可以终止与已允许空闲“太长时间”的输入缓冲区相关联的连接。

这样做意味着异步 I/O,或专用 I/O 线程[s]。

于 2009-08-22T22:50:19.633 回答
1

我之前所做的,为了解决这个问题(大约在 1997 年 :) 是要求在一定时间内发送一个幻数,否则连接被关闭。

如果您有异步连接,则套接字不会被阻塞,并且您需要一个线程来轮询尚未发送有效命令的当前连接列表,并且如果大约 20 毫秒后没有收到消息这表示一个有效的命令,然后关闭该连接并执行您需要做的任何清理工作。

这并不完美,但对于您当前的担忧,它可能有助于解决它,并允许通过建立过多的连接来消耗资源。

所以它确实需要一个主线程和一个第二线程来清理,所以它不是单线程的。

于 2009-08-23T01:59:07.923 回答