英文原文:DOM Based Cross Site Scripting or XSS of the Third Kind

翻译原文:http://www.oschina.net/translate/dom-based-xss-of-third-kind

我要收藏小胖胖_要减肥 推荐于 2天前 (共 18 段, 翻译完成于 02-19)

参与翻译(2人):缪斯的情人, 小胖胖_要减肥


摘要

我们都听说过跨站脚本(xss),对吗?它利用恶意的数据(通常是使用javascript代码填充到html中)嵌入到你的应用程序的HTML文本中,然后执行注入的javascript代码。好吧,错了。还有一种和这个描述不太相符的XSS,至少在一些基本性质上不一样。上面描述的XSS攻击要么是“非持久”/“反射”(即恶意数据嵌入到页面后会紧跟请求立刻返回到浏览器)要么是“持久化”/“存储型”(在这种情况下恶意数据一段时间后也能返回)。但是还存在第三种XSS攻击-这种类型的攻击不依赖于起初发送到服务端的恶意数据!虽然这似乎与定义和常识有些矛盾,事实上,对于这类攻击有两个很好的描述例子。我们讨论的这个技术被称为“DOM Based XSS(基于dom的xss)”。对于攻击来说没什么新颖的,当然,在这篇文章中这个创新属于一个不同的“味道”,这个“味道”还是蛮有趣和重要的。

应用程序开发者和用户需要了解基于DOM的XSS,由于它代表了web应用程序的一种威胁,比标准的XSS有了不同的先决条件。同样地,互联网上很多web应用程序易受基于DOM的XSS攻击,但是当测试(标准的)XSS时,它却被标明为“非脆弱的”。开发人员和网站维护人员(或者审计员)需要熟悉相关技术来检测基于DOM的xss漏洞,以及使用相关技术来防护该漏洞的攻击,这些和适用的标准xss有些不同。

介绍

假定读者具有xss的一些基础知识 ([1], [2], [3], [4], [8])。XSS典型分类是“非持久型”和“持久型”([3], “反射型” 和 “存储型” 相应定义在 [4])。“非持久型”意味着恶意(javascript)程序脚本主要是在受害者请求HTTP后得到一个即刻的响应时执行。“持久型”意味着恶意程序脚本被存在系统中,或许以后在提供给受害者的一个易受攻击的HTML页面里嵌入攻击代码。正如前面摘要里提到的,这个分类假设XSS基本属性拥有恶意程序脚本从浏览器转移到服务器并且在相同的浏览器返回(在非持久型xss)或者任何(持久型xss)浏览器。这篇文章指出这是一个误解,虽然在自然情况下没有这么多反例,少量存在的XSS攻击不依赖于嵌入的服务器响应恶意程序脚本,最重要的是因为它影响检测和防护的方法。这在文档里都有讨论。

例子和讨论

在描述基本方案前,先强调下这里一些技术概论已经得到公众的证明 (比如 [5], [6][7]),同样地,下面的也不是一些新技术(尽管可能有些陌生技术)。

前提是易受攻击的网站有一个HTML页面采用不安全的方式从document.locationdocument.URL 或 document.referrer获取数据(或者任何其他攻击者可以修改的对象).

注意这些读者不熟悉的javascript对象:当javascript在浏览器执行时,浏览器提供给javascript代码几个DOM对象。文档对象首先在这些对象之中,并且它代表着大多数浏览器呈现的页面的属性。这个文档对象包含很多子对象,例如location,URL和referrer。这些对象根据浏览器的显示填充浏览器。因此, document.URL 和 document.location是由页面的URL按照浏览器的解析填充的。注意这些对象不是提取自HTML的body-它们不会出现在数据页面。文档对象包含一个body对象,它代表对于HTML的解析。

你常常会发现在一个应用程序的HTML页面里包含解析URL(通过访问document.URL 或者 document.location)和执行一些客户端逻辑的javascript代码,下面的例子就是对这样一个逻辑的说明。

[2]有类似的例子(本质上和场景[7]讲到的一样),考虑到例如下面的HTML页面(这个内容来自于http://www.vulnerable.site/welcome.html):

<HTML>
<TITLE>Welcome!</TITLE>
Hi
<SCRIPT>
var pos=document.URL.indexOf("name=")+5;
document.write(document.URL.substring(pos,document.URL.length));
</SCRIPT>
<BR>
Welcome to our system
…
</HTML>

通常这个页面作为用户欢迎页面, 例如:

http://www.vulnerable.site/welcome.html?name=Joe

然而,如下的一个请求:

http://www.vulnerable.site/welcome.html?name=

<script>alert(document.cookie)</script>

将产生xss条件。让我们看看为什么:受害者的浏览器接收到这个链接,发送HTTP请求到www.vulnerable.site并且接受到上面的HTML页。受害者的浏览器开始解析这个HTML为DOM,DOM包含一个对象叫document,document里面有个URL属性,这个属性里填充着当前页面的URL。当解析器到达javascript代码,它会执行它并且修改你的HTML页面。倘若代码中引用了document.URL,那么,这部分字符串将会在解析时嵌入到HTML中,然后立即解析,同时,javascript代码会找到(alert(…))并且在同一个页面执行它,这就产生了xss的条件。

注意:

1. 恶意程序脚本在任何时候不会嵌入到处于自然状态下的HTML页面(这和其他种类的xss不太一样)。

2.这个攻击只有在浏览器没有修改URL字符时起作用。 当url不是直接在地址栏输入,Mozilla.会自动转换在document.URL中字符<和>(转化为%3C 和 %3E),因此在就不会受到上面示例那样的攻击了,在IE6下没有转换<和>,因此他很容易受到攻击。

当然,直接嵌入到HTML只是攻击的一个挂载点,有很多脚本不需要依赖<和>漏洞,因此Mozilla通常也是无法阻止这些攻击的。

绕过标准检测和防护的技术

在上面的例子中,可能仍然存在争论,恶意脚本没有到达服务器(在HTTP请求的查询部分),也就能像其他xss攻击一样阻止它了。但是我们还是能“照顾”好它免受打击的,看下面的攻击:

http://www.vulnerable.site/welcome.html#name=<script>alert(document.cookie)<script>

注意文件名后面的数字符号(#),它告诉浏览器所有它后面的东西都是个片段,也就是不作为查询的一部分。IE(6.0)和Mozilla不会把这个片段发送到服务器,因此服务端将看到同样的http://www.vulnerable.site/welcome.html,这样这个恶意脚本就不会被服务端看到。我们了解到这个逃避技术主要是利用浏览器不向服务器发送恶意脚本。

有时,完全隐藏恶意脚本很难做到:在[5] 和 [6],username是恶意脚本的一部分,URL看起来像http://username@host/,浏览器在这样的情况下,发送一个包含username的授权头,因此,恶意脚本就到达了服务器(Base64 编码-IDS/IPS需要解编码这个数据后才能观察到攻击)。当然,以防xss攻击条件的产生,服务器可以不请求嵌入这段脚本。

明显地,在恶意脚本可以完全隐藏的情况下,在线检查(IDS)和防护(IPS,web应用程序防火墙)产品就无法完全阻挡攻击了,假设易受攻击的脚本确实可以通过一个已知的location调用。即使恶意脚本被发送到服务器,在很多情况下都可以通过巧妙地伪装躲避检测,如,假设有个受保护的特殊参数(像上面的name参数),那么做一个细微的变化都有可能引起成功的攻击:

http://www.vulnerable.site/welcome.html?notname=<script>(document.cookie)</script>

一个更严格的安全策略是需要发送时带有name参数(避免上面使用name和#的小技巧)。我们仍可以使用下面发送:

http://www.vulnerable.site/welcome.html?notname=

<script>alert(document.cookie)<script>&name=Joe

如果策略约束了参数名称(如,foobar),那么下面攻击仍可以成功:

http://www.vulnerable.site/welcome.html?foobar=

name=<script>alert(document.cookie)<script>&name=Joe

注意foobar参数必须放在首位,恶意脚本包含在它的值里面。

在章节[7]中更好的从攻击者的角度做了讲述,由于document.location被嵌入HTML页面(javascript代码没有过滤特殊参数),所以攻击者可以完全隐藏恶意脚本如下:

/attachment.cgi?id=&action=

foobar#<script>alert(document.cookie)</script>

即使恶意脚本被服务器检查,防护也只限于保证它的请求中没有拒绝的信息,或者响应里没有被错误文本替换的。重新看一下[5] 和 [6]章,如果授权头部被一个中间保护系统移除了,只要原来的页面返回了那就没啥影响。同样滴,任何企图在服务器清理这些数据的,要么移除攻击字符,要么对他们进行编码,对于这种攻击都是无效的。

document.referrer这种情况下,恶意脚本通过Referer头发送到服务器。然而,如果用户的浏览器或者其他中间装置消除了这个头,那么攻击就不会起作用了——那就可以完全忽略这个攻击了。

一概而论,传统的方法:

1. HTML 在服务端编码输出数据

2. 在服务端移除/编码恶意输入数据

做好基于DOM的xss的防范。

至于通过故障注入方式的自动漏洞评估将不会起作用,因为一般产品使用的技术通常是根据响应页面是否存在注入数据(而不是在浏览器执行客户端代码来观察运行效果)给定评估结果。然而,如果一个产品可以静态的分析页面的javascript,那么有可能它能指出可疑的匹配(看下面)。当然,如果产品可以执行javascript,或者模拟执行,那么就可以检查出攻击。

使用浏览器手动的漏洞评估将能起到作用,因为浏览器执行了客户端的代码。当然,漏洞评估的产品可能会采取这种技术,执行客户端代码进而发现运行时的问题。

有效防御

1. 避免客户端文档的重写,重定向,或者其他的使用客户端数据的敏感操作。这个效果可以通过动态页面实现(服务端).

2.分析和硬化客户端代码。涉及到DOM对象的可能会对用户产生影响的应当做检查,包括(不限这些):

  • document.URL
  • document.URLUnencoded
  • document.location (很多其他属性)
  • document.referrer
  • window.location (很多其他属性)

注意一个document对象的属性或者一个window对象的属性可能有多种引用方式-明确的(像window.location),暗含的(像location),或者通过一个窗口操作的调用(像handle_to_some_window.location)。

特别注意场景中DOM修改的地方,不管是明确的还是暗含的,不管是通过原始的访问HTML或者是访问DOM本身,例如(这不是个详尽的清单,浏览器扩展多种多样):

  • 原生的HTML, 如:
    • document.write(…)
    • document.writeln(…)
    • document.body.innerHtml=…
  • 直接修改DOM (包括 DHTML 时间), 如:
    • document.forms[0].action=… (and various other collections)
    • document.attachEvent(…)
    • document.create…(…)
    • document.execCommand(…)
    • document.body. … (accessing the DOM through the body object)
    • window.attachEvent(…)
  • 替换文档的URL, 如:
    • document.location=… (and assigning to location’s href, host and hostname)
    • document.location.hostname=…
    • document.location.replace(…)
    • document.location.assign(…)
    • document.URL=…
    • window.navigate(…)
  • 打开/修改一个窗口, 如:
    • document.open(…)
    • window.open(…)
    • window.location.href=… (and assigning to location’s href, host and hostname)
  • 直接执行脚本, 如:
    • eval(…)
    • window.execScript(…)
    • window.setInterval(…)
    • window.setTimeout(…)

继续上面的例子,一个有效的防御可以使用下面的代码替换原始脚本,它验证了写入HTML的字符串只能有数字字母组成

  <SCRIPT>
  var pos=document.URL.indexOf("name=")+5;
  var name=document.URL.substring(pos,document.URL.length);
  if (name.match(/^[a-zA-Z0-9]$/))
  {
       document.write(name);
  }
  else
  {
        window.alert("Security error");
  }
  </SCRIPT>

这样的功能可以通过一个通用类库提供(即一组执行输入验证的javascript函数),其缺点是安全逻辑暴露给了攻击者—它被嵌入在HTML代码里。这让它更容易理解和攻击了。在上面例子中,情形很简单,在复杂的场景里安全检查不尽完美,可以用这样的方式来玩玩。

3. 在一个非常严格的IPS策略中,例如,welcome.html只希望接受一个名字为“name”的参数,且其内容是受检查的,任何不符合规则的结果(包括过多的参数或者无参数)都不发送给原始的页面,同样地任何其他不符合的(像一个安全认证头或者Referer头包含有问题的数据),原始的内容都不会被发送。在某些情况下,即使这样这也不能保证阻止一个攻击。

注意重定向漏洞

上面讨论了关于XSS,然而,在很多情况下,仅仅使用客户端脚本重定向浏览器到另外的位置被认为是自身的一个缺陷。在这种情况下上述技术和检测仍然适用。

结论

虽然大多数XSS攻击的确依赖于在服务器上嵌入用户数据到响应的HTML页,但也有些xss攻击不依赖于服务端嵌入数据,这对于讨论检测和阻止XSS有重要的意义。当目前为止,几乎所有公布的检测和防护技术都是假设XSS是服务端接收到用户输入的恶意数据然后嵌入到HTML页面。由于这些假设对于本文中描述的XSS攻击都没有效果,很多技术也就不能成功的检测和防护这种类型的攻击。

XSS依赖于服务端嵌入用户数据的攻击被分为“非持久型”(“反射型”)和“持久型”(“存储型”)。因此建议第三种不依赖于服务端嵌入的XSS攻击命名为“DOM Based XSS”.

这里有一个标准XSS和“DOM Based XSS“的比较:

标准XSS

基于DOM 的 XSS

根源

不安全的客户端输入导致嵌入到HTML页面

不安全的引用和通过服务器提供的页面使用不受约束的DOM对象

所属

Web 开发者 (CGI)

Web 开发者 (HTML)

页面

只针对动态页面 (CGI script)

一般是静态页面 (HTML), 但是不一定.

漏洞检测

  • 手工注入
  • 自动注入
  • 代码重写 (需要进入页面源)
  • 手工注入
  • 代码重写(可以远程实现!)

攻击检测

  • Web 服务器日志
  • 在线检查工具(IDS, IPS, web 应用防火墙)

如果躲避方法可用 - 没有服务器可以检测到

有效防护措施

  • 服务端数据验证
  • 攻击防护工具 (IPS, application firewalls)

客户端数据验证 (Javascript)

  • 替换服务端逻辑

参考文献

注: 下面的链接在写这篇文章时更新的 (July 4th, 2005). 有一些材料是仍在更新的,因此可能被更新以反映本文观点。

[1] “CERT Advisory CA-2000-02 - Malicious HTML Tags Embedded in Client Web Requests”, CERT, February 2nd, 2000

http://www.cert.org/advisories/CA-2000-02.html

[2] “Cross Site Scripting Explained”, Amit Klein, June 2002

http://crypto.stanford.edu/cs155/CSS.pdf

[3] “Cross-Site Scripting”, Web Application Security Consortium, February 23rd, 2004

http://www.webappsec.org/projects/threat/classes/cross-site_scripting.shtml

[4] “Cross Site Scripting (XSS) Flaws”, The OWASP Foundation, updated 2004 http://www.owasp.org/documentation/topten/a4.html

[5] “Thor Larholm security advisory TL#001 (IIS allows universal CrossSiteScripting)”, Thor Larholm, April 10th, 2002

http://www.cgisecurity.com/archive/webservers/iis_xss_4_5_and_5.1.txt

(see also Microsoft Security Bulletin MS02-018 http://www.microsoft.com/technet/security/bulletin/MS02-018.mspx)

[6] “ISA Server Error Page Cross Site Scripting”, Brett Moore, July 16th, 2003 http://www.security-assessment.com/Advisories/ISA%20XSS%20Advisory.pdf

(see also Microsoft Security Bulletin MS03-028 http://www.microsoft.com/technet/security/bulletin/MS03-028.mspx and a more elaborate description in “Microsoft ISA Server HTTP error handler XSS”, Thor Larholm, July 16th, 2003 http://www.securityfocus.com/archive/1/329273)

[7] “Bugzilla Bug 272620 - XSS vulnerability in internal error messages”, reported by Michael Krax, December 23rd, 2004

https://bugzilla.mozilla.org/show_bug.cgi?id=272620

[8] “The Cross Site Scripting FAQ”, Robert Auger, May 2002 (revised August 2003)

http://www.cgisecurity.com/articles/xss-faq.shtml

Amit Klein 是著名的web安全应用研究员,Klein写了许多篇关于不同的web应用技术的研究性论文,从HTTP到XML,SOAP和web服务,涵盖了许多主题--HTTP请求走私,不安全的索引,XPATH盲注,HTTP分拆响应,.NET web应用安全,跨站脚本攻击,cookie篡改等。他的作品已经发表在Dr. Dobb's Journal, SC Magazine, SC Magazine和IT Audit journal上面,并且被应邀参加SANS和CERT会议,并被许多许多学术课程参考和使用。

Klein 是WASC的成员(Web Application Security Consortium)

本文的副本可以点击这里:http://www.webappsec.org/articles/ 

关于网络应用安全联盟准则(the Web Application Security Consortium's Article Guidelines)的信息可以参考这里:http://www.webappsec.org/projects/articles/guidelines.shtml 

这个文档的许可证能够在这里找到:http://www.webappsec.org/projects/articles/license.shtml