| 即使具有防火墙、应用服务器和硬件安全模块所提供的安全性,安全的Web站点仍需精心的设计和编程。编写安全的应用程序存在困难的直接证据可以从充斥报端的Web站点非法入侵文章中找到。有些高度关注安全性的站点已经遭受了成功的攻击。本文将对如何预防Web站点再次遭受非法入侵提出一些建议。
本文将讨论可导致Web站点不安全的几种常见的编程漏洞,包括密码漏洞、跨站脚本漏洞、不安全的存储漏洞和拒绝服务漏洞。对于每一种漏洞,我们将分别提供一个概要、一个典型攻击的例子、一个现实攻击的帐户以及预防策略。
本文的读者对象为对编写安全的Web应用程序感兴趣的开发人员或架构师。
简介
尽管人们对安全性漏洞的关注度在不断提高,但站点非法入侵案件依然不断发生。美国CSO杂志/美国联邦财政部密勤局/CERT协调中心电子犯罪监视调查显示,2003年(获取数据的最后一年)各种组织和企业中有70%报告遭受了非法入侵。CERT更深入的报告称,当年独立的非法入侵案件估计达137,529起。这就是所谓的“网络犯罪”,它在2004年耗费了 英国4610亿美元的资金。
J2EE为Web应用程序提供了安全机制。使用J2EE 可用的声明性安全是创建安全Web站点的第一步。通过J2EE部署描述符可以指定servlet访问控制,只允许具有特定角色的用户访问某一特定Web页面或某一组页面。使用访问控制时,还必须指定身份验证机制,包括BASIC、CLIENT-CERT、FORM和可选的DIGEST(BEA WebLogic Server不支持)。
BEA WebLogic Server通过身份断言扩展了标准的身份验证机制。有关这些身份验证机制的更多信息,请参阅文档。此外,J2EE还允许指定数据完整性约束,以强制使用SSL/TLS,确保通信安全。例如,J2EE提供的身份传播可使身份跨EJB调用流动。遗憾的是,若不辅以其他攻击补救措施,则即使是那些正确使用了这些J2EE安全特性的应用程序仍易遭受成功的攻击。
关于攻击者
在详述各种Web 攻击以前,有必要探讨一下谁可能参与这种行为。攻击者的技能水平参差不齐,有的是技能超群的工程师,有的是使用他人编写的工具但并未真正了解这些工具之所作所为或其工作机制的“脚本小子”。除了技能差别以外,他们还有着不同的动机。许多攻击者侵入站点是因为他们认为这样很爽、很了不起,或者是因为他们想在同类攻击者中获得声望和地位。另一些攻击者是对站点管理团队感到不满,还有一些是为了赚钱。最老练的攻击者都是非常聪明的,且动机非常明确,并与其他攻击者串通,同时拥有大量的时间来专注于某一攻击。
这些老练的攻击者在攻击站点时首先是进行侦探。然后他们会努力识别所使用软硬件、其版本和补丁级别。他们会通过识别网络布局、IP地址和其他网络信息来补充更多信息。他们基本上是想重新创建Web站点的IT图示。随着侦探活动逐渐揭示所需信息,他们会努力寻找可用于目标系统的已知漏洞。(许多站点都包含了已知漏洞的列表,包括产品供应商主办的站点,如BEA的advisory notifications,以及独立于供应商产品的站点,如US-CERT。)在这一过程中,攻击者可能自始至终都会与其他攻击者串通,以实现信息共享并获得社会地位。
最终攻击者将为发动成功的攻击积累到充足的数据。攻击得逞后,攻击者可能会破坏站点内容,窃取机密数据,为将来躲避检测的访问安装“后门”,甚至会为其他攻击者对该站点或类似站点实施攻击编写工具。
常见的漏洞
许多漏洞都会使Web站点攻击得逞。本节将讨论其中的一些漏洞,并简要介绍针对每一漏洞的攻击以及利用了这些漏洞的典型攻击。本节还将介绍已经在Web站点中发现的漏洞的实际例子,以及防止这些漏洞的技术。
据我所知,本节介绍的漏洞的所有实际例子都已经发生过、已经报告给供应商并已经得到修补。为了对报告负责,将不引用未得到修补的漏洞。此外,所使用的漏洞都经过了挑选,因为它们是为了证明某一特定的论点,而不是为了指责企业的产品。
密码漏洞
概要:密码泄露往往就是因为用户粗心大意(例如,用户可能将密码记在了一个不安全的地方或选用了一个容易被猜到的密码)或密码存储和传输不安全。密码泄露可以发生在服务器上、传输中或客户机上。密码通常还会暴露在网页或电子邮件消息中。电子邮件可能是存储密码最不安全的地方,但也是最常见的密码传送方法之一。即使假定电子邮件在Internet上传输时是安全的,但在收到该电子邮件后,ISP或公司的系统管理员一定有权访问该电子邮件。此外,电子邮件通常都在站点外备份,因此使用备份存储设备的人甚至运送备份磁带的卡车司机都可轻松访问电子邮件。
典型攻击:许多密码漏洞都可以从本机利用。包括从磁盘或内存工件,或者从磁盘备份读取明文密码。发生在服务器环境之外的攻击包括电子邮件探听、浏览器内存探听和最简单的:在回送至屏幕时监视键入的密码(例如,当用户输入密码时,许多站点都将密码显示为星号,而随后的安全问题的回答却以明文键入,并且该回答可用于修改密码)。
例子:最常见的一类密码漏洞是堵塞电子邮件收件箱的数不胜数的“网页仿冒”攻击。网页仿冒是指某一Web站点冒充其他站点来收集用户名、密码和其他机密信息的行为。网页仿冒电子邮件都具有“Important account update required(需要更新重要帐户)”这样的主题。
一个具体例子出现在CA的eTrust EZ Antivirus program, version 7.x中。在该程序中,有一个登录表单要以用户名和密码预填写到后端系统,这使得位于同一台机器上的攻击者能够从浏览器内存中提取密码。(请访问Secunia的站点了解详情。)
预防:避免本地服务器密码漏洞的一个最佳方法就是不将密码存储在该服务器上。一个补救措施是散列密码并存储密码散列,不过近来对散列算法的攻击已使这种方法不像以前认为的那样安全了。当因为密码必须呈现为明文形式使散列不可行时(例如,为连接到远程机器),则应当使用加密。
应尽量避免通过电子邮件发送密码,若非此方法不可时,则应使用临时密码,即必须立即更改的密码。尽管这些技术不足以防止密码被盗,但它们确实缩短了它们可能被盗的时间,并能够增加发现盗用行为的概率。
许多密码方案和扩展都是可以使用的。其中有些还比较新(例如,视网膜扫描等生物测量学),有些则已经比较广为人知。RSA SecurID 是常用密码扩展的一个例子。X.509证书常常用于整体替换密码。使用渐长的另一种方法是一次性密码,在这种情况下,用户使用一个有序的密码表,并且其中的每个密码只能使用一次。
跨站脚本(XSS)漏洞
概要:跨站脚本漏洞常常被称为XSS漏洞,在Web站点未经适当过滤便显示在HTML页面上时会出现这种漏洞。它允许(由用户输入的)任意HTML显示在用户的浏览器中。为了便于理解,下面举一个例子。
示例XSS Web页面仅显示其输入。图1所示为URL为http://myserver/myapp/XSSDemo?userInput=bar时所呈现的一个简单的HTML页面。
图1:未过滤HTML表单的示例输出屏幕
若在文本框中输入“foo”并单击Submit(提交),页面将被刷新,且底部的“bar”将变为“foo”。该页面的源代码为:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head> <title>XSS Vulnerability Sample</title> </head>
<body>
<h1>XSS Vulnerability Sample</h1>
<form method="GET" action="XSS.jsp">
Enter string here:
<input type="text" name="userInput" size=50>
<input type=submit value="Submit">
</form>
<br> <hr> <br>
Output from last command:
<%= request.getParameter("userInput")%>
</body>
</html>
现在来看通过文本框提交以下文本时的情况:
<script>
alert("If you see this you have a potential XSS vulnerability!");
</script>
图2:不过滤输入内容结果是XSS vulnerability
图2 给出了(惊人的)输出。可以看到,浏览器执行了输入的小脚本。
典型攻击:涉及XSS的典型攻击通常都需要称为“social engineering(社会工程)”的什么东西。在这种情况下,该术语意味着说服某人点击您所创建的某一链接,该链接包含指向某一Web站点的提交功能,该站点具有XSS漏洞,该链接通过该漏洞提交JavaScript代码。提交的JavaScript代码通常会从用户的浏览器窃取会话cookie,并将它们提交给攻击者的某一Web站点。攻击者然后可以使用这些会话来冒充受攻击用户,且无需密码。尽管策动这种攻击比较困难,但攻击者却可以很好地文档化和理解它,因此必须谨慎地加以避免。
例子:这可能是最常见的Web漏洞。一般来讲,在编写Web站点时不了解也不积极主动地设法预防XSS漏洞,则该站点几乎总会有XSS漏洞。
需要提醒开发人员的是,一个特别容易被利用的漏洞出现在了Yahoo! Mail中。富有Web编程经验的Yahoo工程师采取了积极的防预措施来预防XSS。特别是其邮件站点在适当的上下文中将“javascript”转换成了“_javascript”,以阻止代码的执行。但是在“javascript”标记中插入制表符时,有一个bug会阻止这种文本替换对代码的执行。对此的详细阐述请访问这里。
预防:为了防止XSS漏洞,在输出到浏览器之前,所有用户输入都必须进行转义。这通常包括将特殊字符转换成HTML换码—例如,将“<”转换成“<”。在Web上可以找到大量关于该主题的文档,例如在CERT协调中心。
不当的错误处理漏洞
概要:如果对错误处理不严加注意,那么在检测到错误时操作的执行可能就会不完全。这往往会导致不正确的安全操作。错误导致漏洞的另一种方式是通过暴露敏感信息。在Java中,敏感信息通常是通过显示栈跟踪和异常消息暴露出来的。其中可能包含程序内部的信息。值得提及的一个特例是,如果显示了错误文本,并且用户能够控制所显示文本的任一部分,则必须对该错误文本进行转义,以防止XSS漏洞。例如,如果不对用户名进行转义,则消息“User 'joe' not found.(未找到用户名同‘joe’。)”就是一个XSS漏洞。
典型攻击:通过了解Web站点,攻击者可以识别并设法利用错误处理不当的环节。确切的利用依赖于漏洞的确切形式。攻击者能够编写工具来帮助各种非法输入搜寻这些漏洞。
需要注意的一个现象是这些漏洞往往会被“意外利用”。也就是说,某一非恶意用户无意中执行了某一不正确的操作,并真想获得一条适当的错误消息,但却部分地或完全地执行了操作。可以想像一下因此引发银行存款余额出现负数等问题的情况。
例子:现有许多有证可查的错误处理漏洞案例。Bugzilla中所出现的就是一个典型,当数据库不可用时,错误页面便打印数据库用户名和密码。若当初用户可直接访问数据库,则用户名和密码可能早已用于旁路Bugzilla的安全设置了(在此了解详情)。
不当错误处理的一个变形出现在了BEA的WebLogic Server中。当用户想修改JNDI树,但又没有相应权限时,它们便收到一条错误消息。但该操作有时也会成功(请参阅Security Advisory了解详情)。该问题是在代码中修复bug时引入的。最初该代码是安全的,用于执行访问检查,若被拒绝则生成一条错误消息,然后执行JNDI修改。有人注意到,当正在被修改的JNDI树为空时会出现一个bug,于是他在访问检查之前在该方法中添加了一个特例。引入这种形式的漏洞是很常见的,这说明在开发的所有阶段中自始至终都需要提高安全警惕。
预防:如前面提到的,应仔细检查所有错误消息的XSS漏洞,并在必要时进行适当的转义。此外,错误检查应在所有操作的早期进行。一旦发现错误就应终止操作。要严防吞没异常。
不安全的存储漏洞
概要:当包含机密数据的磁盘上或内存中工件保护不当时,可能会被攻击者获得并利用。这通常涉及不安全的密码、缓存和配置。
典型攻击:攻击通常发生在访问磁盘上或内存中工件的服务器上。这可能由服务器上的合法用户策动(大多数网络犯罪都是由内部知情人士策动的),也可能在攻击者通过OS漏洞获得服务器访问权时实施。在客户机上,进程的内存通常可以通过核心转储或调试器来访问。用户的cookie也存储在磁盘上,并且通常也是可访问的。
例子:phpAnyVote,一个调查/表决程序,存在一个值得关注的存储问题。phpAnyVote允许人们对特定问题进行表决;每个用户只能表决一次。这种单票制是通过将用户姓名存储在浏览器的一个cookie中,然后确保该用户以前未曾进行表决来实现的。知识渊博的用户能够修改cookie值,从而冒充其他用户并进行多次表决。一篇SecurityFocus文章更详细地描述了这一主题。
预防:必要时使用加密和签名。签名可确保数据不被篡改,加密可确保机密性并防止篡改。在phpAnyVote例子中,若使用秘密密钥签署用户名或加密用户名,就可以确保用户无法轻易修改它了。特别是在服务器上,要设法利用OS安全性(例如,保护对文件的访问)。一般来讲,应检查所有工件的安全要求并适当应用保护措施。
注入缺陷漏洞
概要:若未经适当验证、正常化或转义并传递给后端程序(如数据库),用户输入可能会允许攻击者执行任意操作。这非常类似于XSS漏洞,不过在XSS中,用户输入传递给浏览器,而在这种情况下,它传递给后端程序。
典型攻击:这种攻击最常见的例子是SQL注入。用Google搜索“sql injection flaw vulnerability”(sql注入缺陷漏洞)将返回近33,000个结果。当将非转义用户输入传递给SQL调用时将发生SQL注入,从而允许用户输入包含任意的SQL命令。想像一下请求搜索字符串,然后在数据库中对其进行搜索的Web站点的情况。了解数据库及其语法对于成功执行该攻击是必需的。
例子:众多SQL注入缺陷中有一个发生在了Microsoft SQL Server中。SQL Server提供了几个存储过程,其中有两个允许SQL注入在某些数据库配置下发生。该漏洞使进行任意的SQL查询和任意OS命令的执行成为可能。更多细节,请参阅US-CERT文章。
预防:和XSS漏洞的情况一样,在处理用户数据时一定要小心。应当对数据进行正常化(例如,删除%XX和\0xx换码)并检查其有效性。无效输入可能含有非法字符,如嵌入的空值,或者非法路径组件,如“../”。一旦发现,非法输入应在限制过多并可能拒绝某些合法用户输入的一边生成error.Err,而不应在限制不足并可能允许某些注入缺陷漏洞的一边生成。
拒绝服务(DOS)漏洞
概要:拒绝服务(DOS)漏洞将Web站点呈现为不可访问或不可用。其发生方式多种多样,但一般都包括攻击导致站点崩溃、拒绝连接或执行速度奇慢而导致无法使用的攻击。DOS攻击有两种形式。分布式拒绝服务(DDOS)漏洞需要许多计算机的运行,而基本的DOS攻击仅需一台或少数几台计算机。
典型攻击:典型DDOS攻击力图用超量的活动充斥网络。这些攻击防不胜防。即使Web站点具有惊人的健壮性,但在通信量大到一定程度时,总会产生薄弱环节——若非站点,可能就是路由器、防火墙、ISP、名称服务器等。
例子:IBM Lotus Domino服务器有一个漏洞具有基本DOS攻击的典型特征。在该攻击中,发送到该服务器的某些不完整请求会导致该服务器挂起,并需要重启。一个用户就可以轻而易举地使该服务器崩溃。
一个更需要引起注意的基本DOS攻击被称为“smurf”攻击。该攻击依赖于Internet控制消息协议(Internet Control Message Protocol,ICMP)的“echo”命令。这是“ping”程序所使用的命令。echo命令将响应发送地址作为参数。ICMP不仅允许指定一台机器,还允许指定一个子网,在这种情况下,它将以该子网中的所有机器作为发送目的地。smurf攻击就是通过将echo命令发送给用于指定答复地址子网的主机来进行的。要接收echo命令的每一台主机都将生成多个响应(该子网上的一台机器一个)。这就使单个的攻击机器能够生成大量的网络通信量,因而使目标网络的活动终止。
预防:平台软件必须起到第一道防线的作用。BEA WebLogic Server有几个选项就是用于控制如何抵御DOS攻击的。这些选项的说明文档位于lockdown document中。搜索“denial of service”可以找到其确切位置。还要确保平台其他组件(包括Web服务器、防火墙和数据库)的配置可实现最大限度的保护。
第二道防线是慎密的应用程序处理。要确保所有读自用户输入流(例如,用户输入的文件、表单域、套接字)的代码经过慎密的错误检查。大多数基本DOS攻击都是系统中的bug(通常是不当的错误处理)。在处理用户输入时小心谨慎可以大大提高应用程序的健壮性。
结束语
本文论述了许多安全性漏洞,并介绍了避免这些漏洞的方法。如这些漏洞所示,安全问题遍布于Web站点的方方面面——从HTML到后端服务器。若要开发安全的Web站点,就要确保从需求过程的开始讨论安全问题,并贯穿设计、实施和部署全过程。不要到事后再考虑安全问题。如果Web站点具有影响安全的配置选项,一定要确保对其进行恰当的配置。要保护好磁盘上和内存中的数据。千万不要信任客户。始终要把客户当成攻击者,并确保验证了传入的所有数据。最后一点,可能也是最重要的,就是要创建、文档化和实施适当的安全过程。 |