「第三篇」服务器端应用安全
批注
[……] 表示他人、自己、网络批注
参考资料来源于
* 书中批注
* 优快云
* GitHub
* Google
* 维基百科
* YouTube
* MDN Web Docs
由于编写过程中无法记录所有的URL
所以如需原文,请自行查询
{……} 重点内容
*……* 表示先前提到的内容,不赘述
「第三篇」服务器端应用安全
「0.6本书结构」
就常见的服务器端应用安全问题进行了阐述
这些问题往往能引起非常严重的后果,在网站的安全建设之初需要优先解决这些问题,避免留下任何隐患
「第十三章」应用层拒绝服务攻击
「13.1DDOS简介」
DDOS又称为分布式拒绝服务,全称是Distributed Denial of Service
DDOS本是利用合理的请求造成资源过载,导致服务不可用
服务器的负荷过载,不能正常工作了,这种情况就是拒绝服务
分布式拒绝服务攻击,将正常请求放大了若干倍,通过若干个网络节点同时发起攻击,以达成规模效应
这些网络节点往往是黑客们所控制的肉鸡,数量达到一定规模后,就形成了一个僵尸网络,大型的僵尸网络,甚至达到了数万、数十万台的规模
如此规模的僵尸网络发起的DDOS攻击,几乎是不可阻挡的
常见的DDOS攻击
SYN flood
UDP flood
ICMP
flood
...
其中SYN flood是一种最为经典的DDOS攻击,其发现于1996年,但至今仍然保持着非常强大的生命力
SYN flood如此猖獗是因为它利用了TCP协议设计中的缺陷,而TCP/IP协议是整个互联网的基础,牵一发而动全身,如今想要修复这样的缺陷几乎成为不可能的事情
在正常情况下,TCP三次握手过程如下
* 客户端向服务器端发送一个SYN包,包含客户端使用的端又号和初始序列号x
* 服务器端收到客户端发送来的SYN包后,向客户端发送一个SYN和ACK都置位的TCP报文,包含确认号X+1和服务器端的初始序列号y
* 客户端收到服务器端返回的SYN+ACK报文后,向服务器端返回一个确认号为y+i、序号为x+1的ACK报文,一个标准的TCP连接完成
而SYN flood在攻击时,首先伪造大量的源IP地址,分别向服务器端发送大量的SYN包,此时服务器端会返回SYN/ACK包,因为源地址是伪造的,所以伪造的IP并不会应答,服务器端没有收到伪造IP的回应,会重试3~5次并且等待一个SYN Time(—般为30秒至2分钟),如果超时则丢弃这个连接,攻击者大量发送这种伪造源地址的SYN请求,服务器端将会消耗非常多的资源(CPU和内存)来处理这种半连接,同时还 要不断地对这些IP进行SYN+ACK重试。最后的结果是服务器无暇理睬正常的连接请求,导致拒绝服务
对抗SYN flood的主要措施有SYN Cookie/SYN Proxy、safereset等算法
SYN Cookie的主要思想是为每一个IP地址分配一个Cookie,并统计每个IP地址的访问频率
如果在短时间内收到大量的来自同一个IP地址的数据包,则认为受到攻击,之后来自这个IP地址的包将被丢弃
在很多对抗DDOS的产品中,一般会综合使用各种算法,结合一些DDOS攻击的特征,对流量进行清洗
对抗DDOS的网络设备可以串联或者并联在网络出又处
但DDOS仍然是业界的一个难题,当攻击流量超过了网络设备,甚至带宽的最大负荷时,网络仍将瘫痪
一般来说,大型网站之所以看起来比较能抗DDOS攻击,是因为大型网站的带宽比较充足,集群内服务器的数量也比较多
但一个集群的资源毕竟是有限的,在实际的攻击中,DDOS的流量甚至可以达到数G到几十G,遇到这种情况,只能与网络运营商合作,共同完成DDOS攻击的响应
DDOS的攻击与防御是一个复杂的课题,而本书重点是Web安全,因此对网络层的DDOS攻防在此不做深入讨论,有兴趣的朋友可以自行查阅一些相关资料
「13.2应用层DDOS」
应用层DDOS,不同于网络层DDOS,由于发生在应用层,因此TCP三次握手已经完成,连接已经建立,所以发起攻击的IP地址也都是真实的
但应用层DDOS有时甚至比网络层DDOS攻击更为可怕,因为今天几乎所有的商业Anti-DDOS设备,只在对抗网络层DDOS时效果较好,而对应用层DDOS攻击却缺乏有效的对抗手段
13.2.1CC攻击
CC攻击的前身是一个叫fatboy的攻击程序,当时黑客为了挑战绿盟的一款反DDOS设备开发了它
绿盟是中国著名的安全公司之一,它有一款叫黑洞(Collapasar)的反DDOS设备,能够有效地清洗SYN Flood等有害流量
而黑客则挑衅式地将fatboy所实现的攻击方式命名为ChallengeCollapasar(简称CC),意指在黑洞的防御下,仍然能有效完成拒绝服务攻击
CC攻击的原理非常简单,就是对一些消耗资源较大的应用页面不断发起正常的请求,以达到消耗服务端资源的目的
在Web应用中,查询数据库、读/写硬盘文件等操作,相对都会消耗比较多的资源
在互联网中充斥着各种搜索引擎、信息收集等系统的爬虫(spider),爬虫把小网站直接爬死的情况时有发生,这与应用层DDOS攻击的结果很像,由此看来,应用层DDOS攻击与正常业务的界线比较模糊
应用层DDOS攻击还可以通过以下方式完成,在黑客入侵了一个流量很大的网站后,通过篡改页面,将巨大的用户流量分流到目标网站
应用层DDOS攻击是针对服务器性能的一种攻击,那么许多优化服务器性能的方法,都或多或少地能缓解此种攻击
比如将使用频率高的数据放在memcache中,相对于查询数据库所消耗的资源来说,查询memcache所消耗的资源可以忽略不计
但很多性能优化的方案并非是为了对抗应用层DDOS攻击而设计的,因此攻击者想要找到一个资源消耗大的页面并不困难
比如当memcache查询没有命中时,服务器必然会查询数据库,从而增大服务器资源的消耗,攻击者只需要找到这样的页面即可,同时攻击者除了触发读数据操作外,还可以触发写数据操作,写数据的行为一般都会导致服务器操作数据库
13.2.2限制请求频率
最常见的针对应用层DDOS攻击的防御措施,是在应用中针对每个客户端做一个请求频率的限制
从架构上看,代码需要放在业务逻辑之前,才能起到保护后端应用的目的,可以看做是一个基层的安全模
13.2.3限制?不可靠!
然而这种防御方法并不完美,因为它在客户端的判断依据上并不是永远可靠的
这个方案中有两个因素用以定位一个客户端,一个是IP地址,另一个是Cookie
但用户的IP地址可能会发生改变,而Cookie又可能会被清空,如果IP地址和Cookie同时都发生了变化,那么就无法再定位到同一个客户端了
使用代理服务器是一个常见的做法
在实际的攻击中,大量使用代理服务器或傀儡机来隐藏攻击者的真实IP地址,已经成为一种成熟的攻击模式
攻击者使用这些方法可不断地变换IP地址,就可以绕过服务器对单个IP地址请求频率的限制了
代理猎手是一个常用的搜索代理服务器的工具
而AccessDiver则已经自动化地实现了这种变换IP地址的攻击,它可以批量导入代理服务器地址,然后通过代理服务器在线暴力破解用户名和密码
攻击者使用的这些混淆信息的手段,都给对抗应用层DDOS攻击带来了很大的困难
应用层DDOS攻击并非一个无法解决的难题,一般来说,我们可以从以下几个方面着手
* 应用代码要做好性能优化。合理地使用memcache就是一个很好的优化方案,将数据库的压力尽 可能转移到内存中
此外还需要及时地释放资源,比如及时关闭数据库连接,减少空连接等消耗
* 在网络架构上做好优化。善于利用负载均衡分流,避免用户流量集中在单台服务器上
同时可以充分利用好CDN和镜像站点的分流作用,缓解主站的压力
* 也是最重要的一点,实现一些对抗手段,比如限制每个IP地址的请求频率
「13.3验证码」
验证码是互联网中常用的技术之一,它的英文简称是CAPTCHA(Completely Automated Public Turing Test to Tell Computers and Humans Apart,全自动区分计算机和人类的图灵测试)
在很多时候,如果可以忽略对用户体验的影响,那么引入验证码这一手段能够有效地阻止自动化的重放行为
CAPTCHA发明的初衷,是为了识别人与机器
但验证码如果设计得过于复杂,那么人也很难辨识出来,所以验证码是一把双刃剑
有验证码,就会有验证码破解技术
除了直接利用图像相关算法识别验证码外,还可以利用Web实现上可能存在的漏洞破解验证码
因为验证码的验证过程,是比对用户提交的明文和服务器端Session里保存的验证码明文是否一致
所以曾经有验证码系统出现过这样的漏洞,因为验证码消耗掉后SessionID未更新
还有的验证码实现方式,是提前将所有的验证码图片生成好,以哈希过的字符串作为验证码图片的文件名
在使用验证码时,则直接从图片服务器返回已经生成好的验证码,这种设计原本的想法是为了提高性能
但这种一一对应的验证码文件名会存在一个缺陷,攻击者可以事先采用枚举的方式,遍历所有的验证码图片,并建立验证码到明文之间的——对应关系,从而形成一张彩虹表,这也会导致验证码形同虚设
修补的方式是验证码的文件名需要随机化,满足不可预测性原则
随着技术的发展,直接通过算法破解验证码的方法也变得越来越成熟
通过一些图像处理技术,可以将验证码逐步变化成可识别的图片
对此有兴趣的朋友,可以查阅moonblue333所写的如何识别高级的验证码
http://secinn.appspot.com/pstzine/read?issue=2&articleid=9
「13.4防御应用层DDOS」
验证码不是万能的,很多时候为了给用户一个最好的体验而不能使用验证码
且验证码不宜使用过于频繁,所以我们还需要有更好的方案
验证码的核心思想是识别人与机器,那么顺着这个思路,在人机识别方面,我们是否还能再做一些事情呢?答案是肯定的
在一般情况下,服务器端应用可以通过判断HTTP头中的User-Agent字段来识别客户端
但从安全性来看这种方法并不可靠,因为HTTP头中的User-Agent是可以被客户端篡改的,所以不能信任
一种比较可靠的方法是让客户端解析一段JavaScript,并给出正确的运行结果
因为大部分的自动化脚本都是直接构造HTTP包完成的,并非在一个浏览器环境中发起的请求
因此一段需要计算的JavaScript,可以判断出客户端到底是不是浏览器
类似的,发送一个flash让客户端解析,也可以起到同样的作用
但需要注意的是,这种方法并不是万能的,有的自动化脚本是内嵌在浏览器中的内挂,就无法检测出来了
除了人机识别外,还可以在Web Server这一层做些防御,其好处是请求尚未到达后端的应用程序里,因此可以起到一个保护的作用
在Apache的配置文件中,有一些参数可以缓解DDOS攻击
比如调小Timeout、KeepAliveTimeout值,增加MaxClients值
但需要注意的是,这些参数的调整可能会影响到正常应用,因此需要视实际情况而定
在Apache的官方文档中对此给出了一些指导——Apache提供的模块接又为我们扩展Apache、设计防御措施提供了可能
目前已经有一些开源的Module全部或部分实现了针对应用层DDOS攻击的保护
mod_qos是Apache的一个Module,它可以帮助缓解应用层DDOS攻击
比如mod_qos的下面这些配置就非常有价值
mod_qos功能强大,它还有更多的配置,有兴趣的朋友可以通过官方网站获得更多的信息
http://httpd.apache.org/docs/trunk/misc/security_tips.html#dos
除了mod_qos外,还有专用于对抗应用层DDOS的mod_evasive也有类似的效果
http://opensource.adnovum.ch/mod_pos
mod_qos从思路上仍然是限制单个IP地址的访问频率,因此在面对单个IP地址或者IP地址较少的情况下,比较有用
Yahoo为我们提供了一个解决思路
因为发起应用层DDOS攻击的IP地址都是真实的,所以在实际情况中,攻击者的IP地址其实也不可能无限制增长
假设攻击者有1000个IP地址发起攻击,如果请求了10000次,则平均每个IP地址请求同一页面达到10次,攻击如果持续下去,单个IP地址的请求也将变多,但无论如何变,都是在这1000个IP地址的范围内做轮询
为此Yahoo实现了一套算法,根据IP地址和Cookie等信息,可以计算客户端的请求频率并进行拦截
Yahoo设计的这套系统也是为Web Server开发的一个模块,但在整体架构上会有一台master服务器集中计算所有IP地址的请求频率,并同步策略到每台Webserver上
Yahoo为此申请了一个专利(Detecting system abuse),因此我们可以查阅此专利的公开信息,以了解更多的详细信息
http://patft.uspto.gov/netacgi/nph-Parser?Sectl-POT2&Sect2=HITOFF&p=1&u=%2Fnetahtml%2FPTO%2Fsearch-bool.html&r=2&f=G&col=AND&d=PTXT&sl=Yahoo.ASNM.&s2=abuse.TI.&OS=AN/Yahoo+AND+TTL/&RS=AN/Yahoo+AND+TTL/abuse
Yahoo设计的这套防御体系,经过实践检验,可以有效对抗应用层DDOS攻击和一些类似的资源滥用攻击
但Yahoo并未将其开源,因此对于一些研发能力较强的互联网公司来说,可以根据专利中的描述,实现一套类似的系统
「13.5资源消耗攻击」
除了CC攻击外,攻击者还可能利用一些Web Server的漏洞或设计缺陷,直接造成拒绝服务
13.5.1Slowloris攻击
Slowloris是在2009年由著名的Web安全专家RSnake提出的一种攻击方法,其原理是以极低的速度往服务器发送HTTP请求
http://ha.ckers.org/slowloris/
由于Web Server对于并发的连接数都有一定的上限,因此若是恶意地占用住这些连接不释放,那么Web Server的所有连接都将被恶意连接占用,从而无法接受新的请求,导致拒绝服务
要保持住这个连接,RSnake构造了一个畸形的HTTP请求,准确地说,是一个不完整的HTTP请求
在正常的HTTP包头中,是以两个CLRF表示HTTP Headers部分结束的
由于Web Server只收到了一个\r\n,因此将认为HTTP Headers部分没有结束,并保持此连接不释放,继续等待完整的请求
此时客户端再发送任意HTTP头,保持住连接即可
{此类拒绝服务攻击的本质,实际上是对有限资源的无限制滥用}
在Slowloris案例中,有限的资源是连接数
这是一个有上限的值,比如在Apache中这个值由 MaxClients定义
如果恶意客户端可以无限制地将连接数占满,就完成了对有限资源的恶意消耗,导致拒绝服务
在Slowloris发布之前,也曾经有人意识到这个问题,但是Apache官方否认Slowloris的攻击方式是一个漏洞,他们认为这是Web Server的一种特性,通过调整参数能够缓解此类问题,给出的回应是参考文档中调整配置参数的部分
http://httpd.apache.org/docs/trunk/misc/security_tips.html#dos
13.5.2HTTP POST DOS
Wong Onn Chee和Tom Brennan演示了一种类似于Slowloris效果的攻击方法,作者称之为HTTP POST D.O.S.
http://www.owasap.org/images/4/43/Layer_7_DDOS.pdf
其原理是在发送HTTP POST包时,指定一个非常大的Content-Length值,然后以很低的速度发包,比如10~100s发一个字节,保持住这个连接不断开,这样当客户端连接数多了以后,占用住了Web Server的所有可用连接,从而导致DOS
这种攻击的本质也是针对Apache的MaxClients限制的
要解决此类问题,可以使用Web应用防火墙,或者一个定制的Web Server安全模块
凡是资源有限制的地方,都可能发生资源滥用,从而导致拒绝服务,也就是一种资源耗尽攻击
出于可用性和物理条件的限制,内存、进程数、存储空间等资源都不可能无限制地增长,因此如果未对不可信任的资源使用者进行配额的限制,就有可能造成拒绝服务
内存泄漏是程序员经常需要解决的一种bug,而在安全领域中,内存泄漏则被认为是一种能够造成拒绝服务攻击的方式
13.5.3Server Limit DOS
Cookie也能造成一种拒绝服务,安全研究者称之为Server Limit DOS,并曾在安全研究者的博客文章中描述过这种攻击
http://hi.baidu.com/aullik5/blog/item/6947261e7eaeaac0a7866913.html
Web Server对HTTP包头都有长度限制,以Apache举例,默认是8192字节,也就是说,Apache所能接受的最大HTTP包头大小为8192字节(这里指的是Request Header,如果是Request Body,则默认的大小限制是2GB)
如果客户端发送的HTTP包头超过这个大小,服务器就会返回一个4xx错误
假如攻击者通过XSS攻击,恶意地往客户端写入了一个超长的Cookie,则该客户端在清空Cookie之前,将无法再访问该Cookie所在域的任何页面
这是因为Cookie也是放在HTTP包头里发送的,而Web Server默认会认为这是一个超长的非正常请求,从而导致客户端的拒绝服务
要解决此问题,需要调整Apache配置参数LimitRequestFieldSize,这个参数设置为0时,对HTTP包头的大小没有限制
http://httpd.apache.org/docs/2.0/mod/core.html#limitrequestfieldsize
拒绝服务攻击的本质实际上就是一种资源耗尽攻击,因此在设计系统时,需要考虑到各种可能出现的场景,避免出现有限资源被恶意滥用的情况,这对安全设计提出了更高的要求
「13.6ReDDOS」
当正则表达式写得不好时,就有可能被恶意输入利用,消耗大量资源,从而造成DOS,这种攻击被称为ReDOS
ReDOS是一种代码实现上的缺陷
我们知道正则表达式是基于NFA(Nondeterministic Finite Automaton)的,它是—个状态机,每个状态和输入符号都可能有许多不同的下一个状态,正则解析引擎将遍历所有可能的路径直到最后,由于每个状态都有若干个下一个状态,因此决策算法将逐个尝试每个下一个状态,直到找到一个匹配的
当用户恶意构造输入时,这些有缺陷的正则表达式就会消耗大量的系统资源(比如CPU和内存),从而导致整台服务器的性能下降,表现的结果是系统速度很慢,有的进程或服务失去响应,与拒绝服务的后果是一样的
http://www.computerbytesman.com/redos/
ReDOS可能会成为一个埋藏在系统中的炸弹
虽然正则表达式的解析算法有可能实现得更好一些,但是流行语言为了提供增强型的解析引擎,仍然使用了naive algorithm,从而使得在很多平台和开发语言内置的正则解析引擎中都存在类似的问题
http://swtch.com/~rsc/regexp/regexp1.html
在今天的互联网中,正则表达式可能存在于任何地方,但只要任何一个环节存在有缺陷的正则表达式,就都有可能导致一次ReDOS
在检查应用安全时,一定不能忽略ReDOS可能造成的影响
在本节中提到的几种存在缺陷的正则表达式和测试用例,可以加入安全评估的流程中
「13.7总结」
在解决应用层拒绝服务攻击时,可以采用验证码,但验证码并不是最好的解决方案,Yahoo的专利为我们提供了更宽广的思路