关于安全的三个最核心的元素CIA,也就是:
Confidentiality(保密性):信息只能被授权的人查阅。
Integrity(完整性):信息没有被意外地修改。
Availability(有效性):信息或者资源在需要的时候,总是可以使用的。
不同的产品对有效性的要求是不一样的,有的要求三个9,有的要求4个9。一个产品的可用性对客户的影响非常大,如果服务经常不可以使用,客户将可能选择其它产品。可用性对一个系统来说是十分关键的,如果一个系统经常不可用,就像12306那样,你会觉得很郁闷,客户也会觉得很郁闷。本片文章着重分析和总结了几种导致DOS的原因,作为参考。
DOS产生的主要原因有以下几种:
1)系统存在耗资源的操作,包括内存和CPU以及带宽
当一个操作需要消耗大量的CPU或者内存的时候,首先需要想的是:是否有其他不需要耗费这么多资源的方法可以实现?如果有则是最好的啦。如果没有,需要注意这个操作是那些角色可以操作?是内部接口还是外部接口?谁可以触发这个操作?如何避免被一般用户出发这个操作?
举个例子:一个搜索的页面,对于用户来说,可以设置每个页面显示多少条记录。某些别有用心的用户可能会尝试修改一个页面显示的最大记录数为一个很大的值,例如:10000。如果在端没有控制好,通过了验证,而且系统确实有大量的数据,这样的查询是非常耗资源的。也许你会认为10000条记录没什么,那么,如果修改为1000,000呢?
2)使用共享资源的操作,容易导致死锁
现在的系统都是并发量很大的系统,而一个系统又难免会有一些资源是共享的,如果系统存在一个线程需要使用两个共享的资源,在其他线程也需要使用这些资源,就有可能导致死锁,进而使得系统停止工作。而且,这样的问题还非常难以调查具体的原因,貌似程序运行的很好,其实,很多功能都已经停止工作。监控程序也可能漏掉这样的监控。所以,其危害比较大。
因此,在使用共享资源时,应该尽量减少保持的时间,用完快速释放。必须要同时使用多个资源时,必须保证以同样的顺序使用,最好是能够在一个API之内,统一处理。另外,一些系统的API也有可能会导致阻塞,在调用可能导致阻塞的API之前,必须保证不上锁任何资源。例如:访问有可能会因为数据库服务器的原因导致阻塞,这时,就可以采用先访问数据库,得到数据之后,再使用共享资源进行下一步操作。当然,最好的方法还是通过设计尽量避免在同一个线程里同时访问多个共享资源。
3)缓冲区溢出
缓冲区溢出是一个众所周知的导致程序不可用的原因。其危害性,不用说,可能大多说的C/C++c程序员也都知道,也都对峙耿耿于怀。其避免方法也很简单,通过有效的inputvalidation避免其发生,这一点很难做到。不过,还有另外一个比较好的方法就是:使用安全的库是最好的方法,例如:STL,Safe C。
4)内存泄漏
使用C/C++语言编程时,需要使用malloc/free和new/delete分配和释放内存。很容易犯的错误就是:
分配和释放不匹配:例如使用new分配,使用free释放,
这样会导致内存泄漏。
重复释放 :例如new 分配一块内存之后,delete两次,这样会导致程序crash。
不正确地释放: 使用new[]分配内存,使用delete释放,
这样会导致内存泄漏。
对于一些客户端程序来说,一点内存泄漏可能结果不是很严重。但是,对于后台程序来说,一点点的内存泄漏,都可能导致严重的Crash。因为,后台程序是常年累月地在运行,泄漏的内存会越来越多(这个根据泄漏内存的操作的频度有关),进而导致程序的内存不足。所以,严格按照语言设计的理念,正确地使用接口很重要。
5)不正确的缓存机制
a)不常用的对象就不要缓存
如果对象不经常使用而被缓存,则意味着经常使用的对象可能会因为内存的原因被从缓存中清除,这样当再次被使用时,有需要再次导入到内存。这样会消耗很多CPU资源和内存资源。使得整个系统的效率变得很低。所以,在决定需要缓存那些对象时,最好先调查对象使用频率。根据缓存的大小和使用频率决定缓存那些对象。
b)不需要记录的日志,就不要记录
首先,关于保存日志的文件,最好单独保存在一个单独的分区,使得系统不会因为日志太多占满而影响程序的正常工作。
其次,记录日志要选择性记录,对于没有用的日志,尽量不要记录,否则,可能因为无用的日志太多,导致有用的日志被覆盖,影响程序bug的分析和审计。
可见,日志虽然不像具体的业务逻辑那么重要,但是,正确地实现日志功能,可以对bug分析和审计提供很大的辅助作用。
6)服务使用的工具或者系统的配置不当
的配置对于系统的稳定也至关重要,如果配置不当,也很容易导致系统被DOS攻击,例如:TOMCAT如果配置成开发模式,很容易导致内存耗尽; 如果连续插入两个同样的主键的值可能导致死锁等。另外,像建立连接的Timeout时间设置不当,也可能导致连接被使用完而不能提供服务。
关于Web服务器和数据库等第三方软件的配置最重要的莫过于默认的用户名和密码,这些用户名和密码是公开的,一些攻击者也会首先尝试这些用户名和密码。如果服务器上没有修改,攻击者可以通过这些用户名和密码控制系统。当然,控制系统之后,DOS攻击也就非常简单。
所以,关于使用第三方工具时,关于配置方面的每一个配置项,都要搞清楚,以免有漏网之鱼损害系统。
7)没有备份,一旦主系统挂掉,没有备份的系统无缝接替
如果系统没有很好的备份机制,一旦系统出问题就会是一个很麻烦的事情。当然,是否需要备份需要根据系统提供服务来定。至于是备份整个系统还是备份整个系统的数据,这个需要根据系统和备份的成本和收益率来权衡。只要做一个在线服务的系统,备份是必须考虑的。
8)存在注入问题,如SQL注入,命令行注入等,一旦被利用,很容易使得攻击者控制系统,当然DOS就更不在话下
一个最典型的SQL注入字符串如下:
aaaa’ or ‘1’=’1’--
这样的注入相对来说还是比较友善一些的。
如果一个非常恶意的攻击者,注入的代码如下:
aaaa’ or ‘1’=’1’;drop tableuser;--
结果会怎么样?
关于数据库,由于可以执行一些系统的命令,如果注入系统的命令,可以使攻击者控制系统,启动一些服务等操作,危害也非常严重。
对于一些输入作为脚本语言或者解释语言的一部分时,一定要谨记,要做好输入验证和特殊字符转义。
9)数据库连接配置不当
一个数据库请求要有合适的超时配置,否则,可能导致阻塞。
在一般的产品线上,数据库是非常关键的组件,一切应用皆需要数据。如果数据库配置不当,超时没有设置为合适的值,在网络不是很好或者数据库系统有些小问题的时候,很有可能导致,数据库操作阻塞。如果阻塞的时间比较长,就可能导致很多请求被堆积在服务端。不但,占用大量内存,还使得请求不能及时得到响应,而导致DOS。
10)访问控制做的不好,也可以让攻击者提升权限控制系统,进而发动DOS攻击
访问控制做的不好的最严重的例子,就是管理员访问的一些操作控制不当。可能有些人认为将管理员的入口,从页面上隐藏或者删除,就可以有效地控制,防止一般人员可以访问这些操作。但是,总是有些好事者,喜欢琢磨一些事情,他们会很有耐心地琢磨出管理员可能的访问的接口。通过组装这些接口,尝试直接访问并且查看效果。如果你只是隐藏或者不显示,这很容易导致问题的出现。一旦攻击者可以进行管理员的操作,后果可想而知。所以,访问控制不能依靠隐藏,而是靠具有严格的、合适粒度的访问控制,保证每一个访问接口都被正确地控制。
11)实现逻辑导致的DOS攻击
举个最典型的例子就是:登录几次失败之后,锁住用户(目前国内仍然有不少网站使用这个策略)。这很有可能导致的后果就是,使用自动发送请求的工具,针对一个网站很多用户发送登录请求,就会导致很多用户被锁住。当真正的用户登录的时候,反而,因为用户被锁住而不能登录。当然,使用Captcha是一个很好的解决。
12)协议级别的攻击
针对协议的攻击有很多,例如,TCP SYN flood攻击,针对ICMP协议的攻击, 这些攻击都有一些特征,可以通过定制规则过滤这些包。也有一些是通过防火墙不能处理的,例如: Beast攻击,是利用低版本的SSL和TLS的实现上的缺陷发动的攻击,这就需要升级使用最新版的协议;还有就是是利用SSL/TLS协议的再协商漏洞,可以使用单机就可以发送DOS攻击,这样的攻击就需要修改,禁止使用再协商机制才可以避免。
总之,导致DOS的原因有很多,必须在编程过程中时刻牢记一些容易导致DOS攻击的原因,在设计和编码的初始阶段就注意预防,才是最有效的方法。希望本文能够对读者关于DOS攻击的预防有所帮助。