freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

安全敏感变量和内置浏览器API克星 | DOM Clobbering技术防御详解
2024-03-27 02:04:58

写在前面的话

本文将给大家介绍一种名为DOM Clobbering的技术,并为经验丰富的安全研究人员和开发人员提供针对DOM Clobbering漏洞的安全开发指南。

关于DOM Clobbering

DOM Clobbering是一种无JavaScript注入攻击,威胁行为者可以通过在网页HTML代码中插入一段非 <script>标签代码,并利用命名属性访问方法将其转换成可执行代码,从而混淆Web应用程序客户端的JavaScript代码。

DOM Clobbering漏洞来源于JavaScript变量和命名HTML标签之间的命名冲突,例如带有id或name属性的标签等等。

DOM中的命名属性

JavaScript脚本代码处理网页内容的方法之一是通过文档对象模型(DOM),即呈现网页的树状结构表示。一般来说,DOM树元素可以在JavaScript中通过文档对象的对象选择器方法访问,比如说通过document.getElementById(x)来定位id为x的 元素。

然而,这并非唯一的方法,因为我们也可以通过document和全局window对象的属性来实现相同的效果,例如document.x或window.x,即我们所说的“命名属性访问”。

相应的,Web浏览器会基于元素命名属性自动地将HTML元素映射到JavaScript对象,例如HTML标签属性id和name等。

需要注意的是,所有的document属性都可以被DOM Clobbering覆盖,受DOM Clobbering影响的window属性如下图所示:

漏洞代码样例

当一个未定义变量和一个HTML标签拥有相同的名称时,浏览器将变量的内容替换为映射标签类型的DOM对象。

示例代码一:

1. var s = document.createElement('script');
2. let config = window.globalConfig || {href: 'script.js'};
3. s.src = config.href;
4. document.body.appendChild(s);

上面的代码段存在DOM Clobbering漏洞,该代码段加载了一个脚本,这个脚本的URL存储在一个全局配置对象中,例如window.globalConfig。具体来说,该代码首先会创建一个script标签(第1行),然后检索全局配置对象并将其存储至一个本地变量config中(第2行)。如果配置对象不存在,它将使用一个最小化配置,例如{href: script.js'}(第2行)。接下来,程序会将新创建的脚本标签的src属性设置为配置对象的href属性(第3行),并将新脚本添加到DOM树中,从而实现脚本代码的执行(第4行)。

漏洞就出在第二行的赋值操作,因为威胁行为者可以控制window.globalConfig的值,并通过注入一个包含id="globalConfig"的HTML标签来选择脚本src属性的值,比如说:

<a id="globalConfig" href="malicious.js">

在解析这种类型的标签代码时,浏览器往往会根据命名属性访问的要求,将锚点标签元素映射到window.globalConfig属性。升级到任意代码执行则发生在上述的第三行代码处,该行代码会读取window.globalConfig对象的href属性,而该属性不再包含具有全局配置的对象,反而包含了威胁行为者控制的锚点标签,其href属性值为malicious.js。

需要注意的是,威胁行为者可以通过其他的方法来滥用“命名属性访问”这种方法,即不通过HTML节点覆盖变量,而是覆盖浏览器API。比如说,如果威胁行为者在DOM中插入一个id=getElementbyId的标签,那么document.getElementbyId这个API将不再引用内置的API来查找DOM树中的元素,而是在DOM树中反射id为getElementbyId的DOM元素。这种行为就是由所谓的“命名属性可见性算法”所造成的。

示例代码二:

1. document.conf = {};
2. const queryParams = new URLSearchParams(window.location.search);
3. if(isTrustedOrigin(queryParams.get('next'))){
4.   document.conf.src = queryParams.get('next');
5. }
6. // [...]
7. let next = document.conf.src || 'https://benign1.com/index.html';
8. window.location.href = next;
9. // [...]
10. function isTrustedOrigin(url){ 
11.  let targetOrigin = new URL(url).origin;
12.  let trustedOrigins= [
13.    new URL('https://benign1.com').origin, 
14.    new URL('https://benign2.com').origin
15.  ];
16.  if(trustedOrigins.indexOf(targetOrigin) !== -1) return true;
17.  return false;
18. }

上面的代码段可以读取查询参数的值,如果它属于受信任域,它会将其全局存储在document.conf.src中(第1至4行)。然后,它会将页面重定向到document.conf.src或默认值(第6行)。

该脚本存在DOM Clobbering漏洞,是因为它忽略了对document的赋值是可以被DOM Clobbering覆盖掉的。比如说,如果威胁行为者注入了下列代码:

<img name="conf" src="javascript:alert(1)">

那么document.conf将会指向一个img标签,因此document.conf.src就变成了一个威胁行为者控制的JavaScript Payload,当其被分配到顶部窗口位置时,将导致XSS(第8行)。

DOM Clobbering的代码模式

常见的DOM Clobbering漏洞代码模式如下图所示:

最常见的错误就是模式A和模式E,在这两种模式中,开发人员通过Windowobject引用了未定义的变量,然后在敏感指令中使用了结果。最不常见但也更复杂的错误则是模式F、G和H,其中漏洞源于跨两个不同脚本标签的指令位置。

其他常见的错误是模式B和C,在这里,开发人员将自定义的和本地document以及window属性视为受信任的值,然后将其用于了敏感操作中。

安全编码模式指南

显式变量声明

如上图所示,导致DOM Clobbering的一个关键因素是在未定义主要变量、预期变量或属性时,使用了||运算符并依赖于特定的默认值,那么在这些变量未定义时,开发人员可以使用var声明并通过默认值来初始化这些变量,并通过命名属性可见性算法来防止命名属性覆盖它们,这种方法可以解决上述的模式A、D、E、F和H。

严格的类型检查

导致DOM Clobbering的另一个常见错误时将DOM属性(如document和window属性)视为安全和可信任的值(例如模式B、C和G)。相反,开发人员应该将信任边界扩展到这些属性,在安全敏感指令中使用它们之前验证它们的类型,比如说通过利用instanceof和typeof运算符进行类型验证。

不要用document处理全局变量

document的属性总是可以被DOM Clobbering覆盖的,甚至在它们被分配了值之后就立即被覆盖,比如说模式C。因此,开发人员应该避免使用document来存储和检索全局值。相反,我们可以在全局上下文中用const或var声明变量,或者使用globalThis对象来实现相同的目的。

命名空间隔离

另一种解决方案是将JavaScript代码定义的变量的命名空间与用户生成标签中的命名属性隔离开。比如说,源代码版本控制应用程序的markdown转HTML工具通常就会在用户生成标签的id和name属性值前面加上特定的字符串,那么根据这种方式,我们就可以通过MutationObserver API监视DOM树中的运行时变化,并在将所有动态插入的标签添加到DOM树之前为其加上前缀,从而修复上述所有易受攻击的模式。

安全防御建议

1、采用安全的编码模式;

2、HTML代码清洗;

3、采用内容安全策略(CSP);

4、固定对象属性(通过Object.freeze()方法);

5、禁用DOM Clobbering;

参考资料

https://html.spec.whatwg.org/multipage/window-object.html#named-access-on-the-window-object

https://www.w3.org/TR/WD-DOM/introduction.html

https://www.w3.org/TR/selectors-4/

https://developer.mozilla.org/en-US/docs/Web/API/Document

https://html.spec.whatwg.org/multipage/window-object.html#named-access-on-the-window-object

https://html.spec.whatwg.org/multipage/dom.html#dom-tree-accessors

https://portswigger.net/research/dom-clobbering-strikes-back

https://fastmail.blog/advanced/sanitising-html-the-dom-clobbering-issue/

https://link.springer.com/chapter/10.1007/978-3-319-66399-9_7

https://webidl.spec.whatwg.org/#legacy-platform-object-abstract-ops

参考链接

https://domclob.xyz/domc_wiki/

# web安全 # DOM # 白皮书 # 安全开发 # 网络安全指南
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录