标签:
跨站点脚本编制可能是一个危险的安全性问题,在设计安全的基于 Web 的应用程序时应该考虑这一点。本文中,描述了这种问题的本质、它是如何起作用的,并概述了一些推荐的修正策略。
当今的大多数网站都对 Web 页面添加了动态内容,从而使用户能获得更愉快的体验。动态内容是由某些服务器进程生成的内容,它可以根据用户的设置和需要在提交时表现出不同的行为和产生不同的显示。动态网站存在着一个称为“跨站点脚本编制”(也称为“XSS”)的威胁,而这是静态网站所没有的。
“一个网页可以包含由服务器生成的、并且由客户机浏览器解释的文本和 HTML 标记。只生成静态页面的网站能完全控制浏览器用户如何解释这些页面。而生成动态页面的网站不能完全控制客户机如何解释其输出。问题的核心是,如果不可信的内容被引入到动态页面中,则无论是网站还是客户机都没有足够的信息识别这种情况的发生并采取保护措施。
跨站点脚本编制正不断受到攻击者的广泛青睐,因为在网站上很容易找到这种安全性问题。商业站点上每月都会发现跨站点脚本编制的攻击,并且每月都会发布解释这种威胁的报告。如果不加注意,则您网站的安全运行的能力以及您公司的声誉都可能成为这些攻击的牺牲品。
跨站点脚本编制的威胁
跨站点脚本编制将服务器应用程序置于危险之中,这些危险包括(但不限于)以下几种情况:
A 当用户查看基于攻击者提供的内容而动态生成的页面时,他们会不知不觉地执行恶意脚本。
B 在用户的会话 cookie 失效之前,攻击者就能接管用户会话。
C 攻击者可以将用户连接到攻击者选择的恶意服务器上。
D 攻击者诱导用户访问由攻击者提供的 URL,从而导致在用户的浏览器中执行攻击者选择的脚本或 HTML。通过使用这种技术,攻击者可以使用访问过此 URL 的用户的特权来采取行动,诸如对底层 SQL 数据库发出查询并查看其结果,以及使用目标系统上已知的有问题的实现。
发动攻击
当攻击者知道某一网站上的应用程序易受跨站点脚本编制攻击后,他就可以规划攻击。攻击者最常用的技术是使用受害者的特权在受害者的系统上插入 JavaScript、VBScript、ActiveX、HTML 或 Flash 并执行。一旦激活了攻击,就可能发生从截获帐户、更改用户设置、窃取和篡改 cookie 到虚假广告在内的任何事情。
样本攻击方案
以下方案用图说明了一些比较典型的攻击。但是,我们无法列出有关弱点的所有变体情况。要了解有关已记录在案的攻击,以及作为供应商或作为用户如何自卫的更多信息,请参阅 参考资料一节。
借助恶意链接的脚本编制
在本方案中,攻击者将一个专门精心制作的电子邮件消息发送给受害者,这个消息包含如下所示的恶意链接脚本:
<A HREF=http://legitimateSite.com/registration.cgi?clientprofile=<SCRIPT>malicious code</SCRIPT>>Click here</A>
当没有对此产生怀疑的用户点击该链接时,URL 被发送到包含恶意代码的 legitimateSite.com
。如果合法服务器将一个包含 clientprofile
值的页面发回给用户,则在客户机 Web 浏览器上就会执行恶意代码,如 图 1 所示。
图1 通过电子邮件攻击
窃取用户cookie
如果网站的任一部分使用了 cookie,则从该网站的用户处窃取这些 cookie 是有可能的。本方案中,攻击者使包含恶意脚本的页面成为易受攻击站点的一部分。显示该页面时,恶意脚本就运行,它收集用户的 cookie,并向攻击者的网站发送包含收集到的 cookie 的请求。通过使用这种技术,攻击者可以获得诸如密码、信用卡号以及用户输入的任意信息等敏感数据,如 图 2 所示。
图2 窃取cookie和截获帐户
发送未经授权的请求
在本方案中,当用户执行邮件消息中的恶意链接时,就会不知不觉地执行攻击者编写的脚本。因为恶意脚本执行时所在的上下文看上去源自合法服务器,所以攻击者对所检索的文档有完全的访问权,并可以将包含在页面中的数据发回他们自己的站点。如果嵌入的脚本代码具有额外的与合法服务器交互的能力,并且交互时不会警告受害者,则攻击者可以开发和利用合法 Web 服务器上不同页面中张贴的那些数据,如 图 3 所示。
图3 发送未经授权的请求
避免攻击
如上所述,当攻击者能够使合法 Web 服务器将一个包含攻击者选择的恶意脚本的页面发送到受害用户的 Web 浏览器时,就实现了跨站点脚本编制攻击。然后攻击者就可以使用源自合法 Web 服务器的合法脚本的特权运行恶意脚本。
既然我们知道了攻击的基本知识,那么做些什么才能保护我们自己避免这一脆弱性呢?
通过确保动态生成的页面不包含不期望的标记,网站开发人员可以防止他们的站点被滥用。
从 Web 用户的角度而言,要降低因为这一脆弱性而遭受攻击的风险,有两种选择。第一种选择是在 Web 浏览器中禁用脚本编制语言,以及禁用支持 HTML 的电子邮件客户机,这种选择提供了最大程度的保护,但存在着禁用功能的副作用。第二种选择是只执行主网站的链接进行查看,这将显著降低用户暴露给攻击者的风险,同时仍能保留功能。
但是,在 Web 用户可以采用的任何解决方案中,没有一种是彻底的解决方案。最终,还是应当由 Web 页面开发人员作出决定来修改他们的页面以消除这几类问题。通过适当过滤和验证所接收的输入以及适当编码或过滤返回给用户的输出,可以实现这一点。
过滤
这种方法的基本原理是决不相信用户输入,并总是过滤 HTML 规范中定义的元字符(“特殊”字符)。对包括链接参数在内的每个输入字段都验证是否为脚本标记。当发现这样的输入时,根据上下文来拒绝它,这样可以防止向用户提供恶意的 HTML。
这种方法所带来的复杂性是许多 Web 浏览器都会尝试纠正 HTML 中常见的错误。其结果是,依照规范,当有些字符不是特殊字符时,他们有时也会将这些字符视为特殊字符。因此,要注意可能保证把额外字符包括到特殊字符列表中的个别情况,这一点很重要。Web 开发人员必须检查他们的应用程序,并确定哪些字符会影响他们的 Web 应用程序。
对输入端进行过滤的效率比较低,因为通过除了 HTTP 以外的其它方法也可以将动态内容输入到网站数据库中。本例中,Web 服务器可能从未将这些数据视为数据输入过程的一部分,因此这些数据元素仍然可能是受污染的。另外,建议就在数据作为动态页面的一部分呈现之前,将过滤作为数据输出过程的一部分来完成。正确执行后,这种方法确保过滤了所有动态内容。
编码
当 Web 服务器充分确保了对生成的页面进行了正确编码以防止脚本的无意执行时,可以避免跨站点脚本编制的攻击。
ISO-8859-1 规范中的每个字符都可以使用其数字项值进行编码。服务器端的编码是一个过程,其中所有动态内容都将经过一个编码函数,这时,脚本编制标记将被替代为所选择的字符集中的代码。
一般而言,推荐进行编码,因为它不要求您决定什么样的字符可以合法地输入,而什么样的字符需要通过编码函数的检查。遗憾的是,对所有不可信数据编码是资源密集型的工作,而且可能对某些 Web 服务器产生性能方面的影响。
哪种策略适合我?
基于 CGI 的 Web 应用程序或支持浏览器中字段编辑检查的应用程序很可能适合于过滤策略,通过将现有的字段编辑检查扩展至包括检查跨站点脚本编制的弱点即可。请注意,虽然浏览器端的字段编辑检查节省了与服务器通信的几个来回,但它适用于诚实的用户,而且需要完整的代码遍历以保证检查了所有的输入字段来满足修正建议的要求。但是,内部设计有服务器端验证的 Web 应用程序可以选择适应两种策略中的任一种,或同时适应这两种策略。
要使过滤策略正确工作,Web 开发人员需要确保的是,依照其应用程序的需要,过滤用的元字符列表是最新的。相反,编码策略不需要进行上述维护工作,而且它对现有应用程序代码以及应用程序功能的影响也较小。基于这些原因,看来编码策略是受欢迎的实现选择。下一节将描述样本编码实现。
样本编码
对 Web 服务器而言,确保正确编码所生成的页面的简单而又有效的方法是:将动态内容中的每个字符都传递通过一个编码函数,在该函数中,动态内容中的脚本编制标记被替代为所选定的字符集中的代码。这个任务最适合于定制标记库。
定制标签库的基础知识
定制标记库由一个或多个 Java 语言类(称为标记处理程序)以及 XML 标记库描述文件(TLD)组成,后者描述新的标记名和那些标记的有效属性。标记处理程序和 TLD 确定在请求时,从 JSP 页面内如何解释和处理这些标记及其属性和主体。在封装复杂操作时,定制标记库提供了一种比 Java bean 更灵活的体系结构。
定制的合适标签库
除了将我们的定制标记库命名为 XSS
之外,还有什么更好的叫法吗?标记库是插入到 servlet 容器的软件组件。servlet 容器创建标记处理程序,对它们初始化并依次调用 doStartTag()
、 doEndTag()
和 release()
方法。
通过这些交互,我们的 XSS 定制标记库就能应用“定制”操作,这种操作编码在 JSP 页面上找到的动态数据。实现定制标记很简单,其步骤如下所示:
.tld
)。 taglib
伪指令添加到使用这些标记的 JSP 文件中。 doStartTag()
或 doEndTag()
方法的标记处理程序。
TLD(标记库描述符)
标记库描述符是一个 XML 文件,其元素描述了特殊的标记库。 清单 1 显示了我们的 XSS
定制标记库的 tld 文件。标记元素定义了 encode
操作,包括属性 property
。 tagclass
元素定义标记处理程序类 EncodeTag
。
<?xml version="1.0" encoding="UTF-8"?> DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"> <taglib> <tlibversion>1.0</tlibversion> <jspversion>1.1</jspversion> <tag> <name>encode</name> <tagclass>dw.demo.xss.EncodeTag</tagclass> <bodycontent>empty</bodycontent> <attribute> <name>property</name> <required>true</required> </attribute> </tag> <taglib> |
taglib 伪指令
taglib 伪指令识别标记库描述符,并定义使后继标记与库相关联的标记前缀。在使用 XSS
定制标记库的 JSP 中出现的样本 taglib 伪指令如下所示:
<%@ taglib uri="/WEB-INF/tlds/xss.tld" prefix="xss" %> |
标记处理程序是 Web 容器中的对象,在执行 JSP 页面时它帮助对操作求值。 EncodeTag
类是用于编码操作的标记处理程序。它的 doStartTag
方法将动态内容编码为 ISO-8859-1 字符集,该方法显示在 清单 2中。
清单2 编码动态内容
public int doStartTag() throws JspException { StringBuffer sbuf = new StringBuffer(); char[] chars = property.toCharArray(); for (int i = 0; i < chars.length; i++) { sbuf.append("&#" + (int) chars[i]); } try{ pageContext.getOut().print(sbuf.toString()); } catch (IOException ex) { throw new JspException(ex.getMessage()); } return SKIP_BODY; } |
部署
XSS
定制标记库是 Web 应用程序的一部分,它作为附加文件打包到 Web 应用程序的 WAR 文件中,如下所示:
应用
以下方案说明了如何使用定制标记库。假设有一个接收文章的虚拟网站,其中有一个评论您所订阅文章的页面。动态内容,即打算提供给您的文章条目,是在 JSP 文件内使用 <%= expression %>
语法准备的。
让我们假设攻击者成功地将一个包含恶意脚本的页面填入到订阅成员使用的网站上。这个成功攻击的效果,就是当在用户浏览器上执行该页面时,会显示一个弹出窗口,如 图 4 中所示。
图4 编码前
在下一个方案中,这个虚拟网站确保生成的页面是通过使用 XSS
定制标记库正确编码的,并且能避免攻击。不可信的数据被保留下来用于在浏览器中可视查看,如 图 5 所示。
图5 编码后
结语
本文中,我们讨论了攻击者如何使用跨站点脚本编制作为对网站发动攻击的技术。我们还演示了当网站使用简单的定制标记库正确编码动态内容时,可以消除大多数攻击。可以“按现状”使用 XSS
定制标记库,或更为有效地更改该定制标记库使之适合您的 Web 应用程序需要,保护您的 Web 应用程序避免受到这种新出现的威胁。
标签:
原文地址:http://www.cnblogs.com/xinaixia/p/5852422.html