跳转至

基于DOM的漏洞

什么是DOM

文档对象模型(DOM)是网页浏览器对页面上各个元素的分层表示方式。网站可以使用 JavaScript 来操作 DOM 中的节点和对象,以及它们的属性。DOM 操作本身并不是一个问题,实际上,它是现代网站运作方式的一部分。然而,那些处理数据的方式不够安全的 JavaScript 代码可能会引发各种攻击。当网站中包含这样的 JavaScript 代码时,就会存在基于 DOM 的漏洞——因为这些代码会接收由攻击者控制的值,并将其传递给某个危险的函数。

污染流漏洞

许多基于 DOM 的漏洞可以追溯到客户端代码处理可控制数据的方式上存在问题。

Sources

“源”是 JavaScript 中的一个属性,它存储的数据可能是攻击者所控制的。例如, location.search 这个属性就从查询字符串中读取数据,而查询字符串对于攻击者来说相对容易控制。实际上,任何可以被攻击者控制的属性都可能是源。这包括引用的 URL(由 document.referrer 字符串表示)、用户的 Cookie(由 document.cookie 字符串表示),以及网络消息等。

Note

任何能被攻击者控制的源数据都可以被称为source

Sinks

“ sink”是一种可能具有危险性的 JavaScript 函数或 DOM 对象,如果接收到攻击者控制的数据,就可能导致不良后果。例如, eval() 函数就是一个“ sink”,因为它会处理传递给它的 JavaScript 参数。而 document.body.innerHTML 则是一种 HTML“ sink”,因为它可能允许攻击者注入恶意 HTML 代码,并执行任意的 JavaScript 程序。

从根本上来说,基于 DOM 的漏洞出现在网站在传输数据从源端到目标端时,而目标端在处理这些数据时采用了不安全的做法,这种情况通常发生在客户端的会话上下文中。

最常见的来源是 URL,通常是通过 location 对象来访问的。攻击者可以构造链接,将受害者引向包含恶意代码的脆弱页面,而该恶意代码可以存在于 URL 的查询字符串或片段部分中。请参考以下代码:

JavaScript
goto = location.hash.slice(1)
if (goto.startsWith('https:')) {
  location = goto;
}

这段代码容易受到基于 DOM 的重定向攻击,因为 location.hash 这个源字符串的处理方式并不安全。如果 URL 中包含以 https: 开头的哈希片段,那么这段代码就可以提取 location.hash 属性的值,并将其设置为 window 对象的 location 属性。攻击者可以通过构造如下的 URL 来利用这一漏洞:

Text Only
https://www.innocent-website.com/example#https://www.evil-user.net

当受害者访问这个 URL 时,JavaScript 会将 location 属性的值设置为 https://www.evil-user.net ,从而自动将受害者重定向到恶意网站。这种行为很容易被利用来实施网络钓鱼攻击等恶意行为。

Common sources

以下是最常见的那些可以用来利用各种污染流漏洞的源程序:

Text Only
document.URL
document.documentURI
document.URLUnencoded
document.baseURI
location
document.cookie
document.referrer
window.name
history.pushState
history.replaceState
localStorage
sessionStorage
IndexedDB (mozIndexedDB, webkitIndexedDB, msIndexedDB)
Database

哪些 sink 接收器会导致基于 DOM 的漏洞

基于 DOM 的漏洞 sink 示例
DOM XSS document.write()
Open redirection window.location
Cookie manipulation document.cookie
JavaScript injection eval()
Document-domain manipulation document.domain
WebSocket-URL poisoning WebSocket()
Link manipulation someElement.src
Web-message manipulation postMessage()
Ajax request-header manipulation setRequestHeader()
Local file-path manipulation FileReader.readAsText()
Client-side SQL injection ExecuteSql()
HTML5-storage manipulation sessionStorage.setItem()
Client-side XPath injection document.evaluate()
Client-side JSON injection JSON.parse()
DOM-data manipulation someElement.setAttribute()
Denial of service RegExp()

如何防止基于 DOM 的污染流漏洞

实际上,并没有什么单一的举措可以完全消除基于 DOM 的攻击威胁。不过,一般来说,避免基于 DOM 的漏洞的最佳方法就是不让来自任何不可信来源的数据动态地改变传递给目标节点的数据内容。

如果应用程序所需的功能意味着这种行为是必要的,那么就必须在中端代码中实现相应的防御措施。在许多情况下,可以通过白名单机制来验证相关数据,只允许已知安全的内容被使用。在其他情况下,则需要对数据进行清洗或编码处理。这可能是一项复杂的任务,根据数据要插入的上下文不同,可能需要结合 JavaScript 转义、HTML 编码以及 URL 编码等方法来完成。