jQuery安全漏洞深度解析:CVE-2020-11022与CVE-2020-11023技术细节

本文详细分析了jQuery 3.5.0中修复的两个安全漏洞CVE-2020-11022和CVE-2020-11023的技术细节。通过三个具体的PoC案例,深入探讨了.html()方法内部字符串处理机制导致的XSS漏洞成因,包括htmlPrefilter正则替换和标签包装机制的安全问题,并给出了升级和防护方案。

CVE-2020-11022/CVE-2020-11023:jQuery 3.5.0安全修复细节

jQuery 3.5.0于上月发布。该版本包含了我报告的两个被标记为“安全修复”的漏洞。

相关链接

本文将对这两个漏洞的技术细节进行解析。

问题概述

满足以下特征的应用程序会受到影响:

  1. 允许用户输入任意HTML(但会经过消毒处理)
  2. 使用jQuery动态插入消毒后的HTML

以下代码是一个示例:

1
2
3
4
5
6
7
<div id="div"></div>
<script>
// 经过消毒的安全HTML
sanitizedHTML = '<p title="foo">bar</p>';
// 将消毒后的HTML插入<div>
$('#div').html(sanitizedHTML);
</script>

在此场景下,如果消毒处理得当,通常认为XSS不会发生,因为只是插入了消毒后的安全HTML。然而,实际上.html()方法在内部进行了特殊的字符串处理,这导致了XSS漏洞。

PoC示例

存在多种攻击向量,以下展示三个基本的PoC:

PoC 1

1
<style><style /><img src=x onerror=alert(1)>

PoC 2(仅影响jQuery 3.x):

1
<img alt="<x" title="/><img src=x onerror=alert(1)>">

PoC 3

1
<option><style></option></select><img src=x onerror=alert(1)></style>

这些HTML看起来不会执行JavaScript,因为恶意代码位于属性或style元素内。但如果通过jQuery的.html()方法插入,JavaScript会被意外执行。

测试地址:https://vulnerabledoma.in/jquery_htmlPrefilter_xss.html

CVE-2020-11023:根本原因(PoC 1和2)

PoC 1和2有相同的根本原因。在.html()方法内部,传入的HTML字符串会经过$.htmlPrefilter()方法处理。该方法使用以下正则表达式将自闭合标签(如<tagname />)替换为<tagname></tagname>

1
2
3
4
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi
htmlPrefilter: function( html ) {
  return html.replace( rxhtmlTag, "<$1></$2>" );
}

PoC 1的HTML经过此替换后变为:

1
<style><style ></style><img src=x onerror=alert(1)>

替换导致<img>标签从style元素中跳出,触发onerror事件。

jQuery 3.x使用了修改后的正则表达式:

1
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi

这一变化引入了PoC 2的攻击向量,仅影响jQuery 3.x。

修复方案(PoC 1和2)

jQuery团队将$.htmlPrefilter()方法替换为一个恒等函数,不再对HTML字符串进行修改。

但此修复未解决所有XSS问题,.html()内部的另一字符串处理机制导致了PoC 3的问题。

CVE-2020-11022:根本原因(PoC 3)

.html()方法内部,如果传入的HTML字符串以特定标签(如option)开头,jQuery会尝试用其他标签包装它,以应对某些浏览器(如MSIE9)的解析问题。

PoC 3的HTML经过包装后变为:

1
<select multiple='multiple'><option><style></option></select><img src=x onerror=alert(1)></style></select>

由于<select>元素的解析规则,<style>标签被忽略,内部的</select>被识别为实际闭合标签,导致后续的<img>标签跳出并触发XSS。

修复方案(PoC 3)

jQuery团队将包装处理仅应用于MSIE9,因为该浏览器不受此漏洞影响。

更新建议

如果您的应用程序通过jQuery函数插入消毒后的HTML,应升级至jQuery 3.5.0或更高版本。若无法升级,建议使用DOMPurify(XSS消毒库)进行HTML消毒,并启用SAFE_FOR_JQUERY选项:

1
2
3
4
5
<script>
unsafeHtml = '<img alt="<x" title="/><img src=x onerror=alert(1)">';
var sanitizedHtml = DOMPurify.sanitize( unsafeHtml, { SAFE_FOR_JQUERY: true } );
$('#div').html( sanitizedHtml );
</script>

注意:DOMPurify的SAFE_FOR_JQUERY选项在2.0.8版本前存在绕过漏洞,请确保使用2.0.8或更高版本。

结语

本研究始于@PwnFunction的XSS挑战(https://xss.pwnfunction.com/challenges/ww3/)。部分漏洞此前已被知晓,但PoC 2向量未被公开披露。感谢jQuery团队的快速响应和修复,以及@PwnFunction提供的挑战机会。

希望本文有助于提升您的Web应用程序安全性或发现潜在漏洞。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计