点击蓝字
关注我们
始于理论,源于实践,终于实战
老付话安全,每天一点点
激情永无限,进步看得见
概念回顾:
反射型XSS:应用程序从HTTP请求中接收数据,并这个数据有以响应的方式发给了浏览器,浏览器接收到后其中的脚本被执行了。但是这个脚本在应用程序中不做任何操作,原原本本的又发回给浏览器了。从而造成用户的数据泄露。
存储型XSS:应用程序接收来的数据存储到了数据库中,在后续的其他用户请求响应中,把这部分数据返回给了用户。(反射型是自作自受,存储型是干扰别人。但是目的都是一样的,获取用户信息,如密码、cookie等。)
DOM型XSS
开始之前,我们先了解一下什么是DOM
通过 HTML DOM,可访问 JavaScript HTML 文档的所有元素。当网页被加载时,浏览器会创建页面的文档对象模型DOM。这个模型是一个树形结构,以HTML元素为根,在分散为各个层级的元素,如head元素、body元素等,它们在往下一层一层的往下分。这就好比我们写论文时的word文档的目录,有一级标题、二级、三级标题一样。
DOM XSS 是一种不涉及服务端的纯前端漏洞,通过浏览器端解析造成攻击。在浏览器端解析修改DOM树,由于前端代码在浏览器相当于‘公开’的,DOM XSS这类漏洞容易被分析发现。而且DOM XSS 重要的优势是它可以绕过waf。攻击者构造一个URL,诱发用户点击,用户点击后,URL可以利用DOM XSS漏洞获取用户的cookie信息。
DOM XSS 漏洞通常出现在 JavaScript 从非法伪造的 URL获取数据并将其传递给支持动态代码执行的接收器(如 eval() 或 innerHTML)时。能够执行恶意 JavaScript,危险发生。
为什么数据传递给支持动态代码执行的接收器就会发送危险,上边不是说是纯前端漏洞吗?
前面我们说DOM树是网页加载时在浏览器中创建的,我们可以按F12查看一下DOM树元素架构就会明白了。
OM XSS 的核心在于,攻击者能够通过修改浏览器端的 DOM 树来注入恶意脚本。由于前端代码在浏览器中是公开的,攻击者可以分析并利用这些代码中的漏洞。例如:
1、URL 参数注入:攻击者通过构造恶意 URL 参数,诱使用户点击。当用户访问带有恶意参数的页面时,这些参数被嵌入到页面的 DOM 中并执行。漏洞点形式可能如//www.example.com?name=x&sex=y。通过let param = window.location.search; a.innerHtml = param这样的代码可以从URL获取的参数直接赋值给innerHTML等接收器,就可能导致XSS漏洞。
2、跳转DOM攻击:在JavaScript语法中,如登录页、退出页、中间页等页面的跳转操作相关代码中可能存在漏洞。随着APP开发的热门,web唤起APP的操作增多,跳转协议多种多样(例如webview://,myappbridge://等),仅用http和https判断URL是否合法已经不够,所以由跳转产生的DOM - XSS漏洞逐渐增多。攻击者可能利用这种跳转相关的代码逻辑漏洞,将恶意脚本注入到可执行的地方。
3、缓存DOM攻击:在缓存前端数据时,会将数据存于sessionStorage、localStorage、cookie中。由于sessionStorage在页面刷新时就失效,所以可以使用localStorage和cookie。如果发现可以设置Cookie的地方,结合读取Cookie的页面就可能进行XSS攻击。Cookie通常存放少量缓存信息(如用户头像URL、用户名等),localStorage通常存放大量需重复加载的数据(如搜索历史记录、缓存JS代码等),这些值被修改后,大部分开发者不会校验其合法性,这就给攻击者可乘之机,可能被用来注入恶意脚本进而利用DOM - XSS漏洞。
4、postMessage导致的DOMXSS攻击,postMessage是一种HTML5 Web API,用于安全地实现跨源通信。如果没有对消息来源和内容进行严格验证,攻击者可能通过构造恶意消息来触发基于DOM的XSS漏洞,当接收消息的一方将消息内容不恰当的处理(如直接使用innerHTML等方式显示消息内容)时,恶意脚本就可能被执行。
5、window.name:window.name 与其他window对象不同,它在窗口刷新后会保留。例如通过iframe设置name的值,当页面刷新跳转到其他网站时,如果这个网站没有对window.name 进行设置,那么当前window.name 的值仍然是之前设置的值。攻击者可以利用这一特性,在window.name 中注入恶意脚本,当目标网站处理window.name 的值不当时(如直接将其作为innerHTML的内容),就可能触发基于DOM的XSS漏洞。
js脚本从url获得数据并将其传递到支持动态代码执行的接收器是一个怎样的执行过程?
1、数据获取:JavaScript脚本需要从URL获取数据。一般通过AJAX请求或Fetch API来实现。
2、数据处理:获取到的数据可能需要进行处理,例如解析JSON、过滤或转换。
3、动态代码执行:如果接收器支持动态代码执行,数据可能会被传递给一个函数或方法,该函数或方法会执行动态生成的代码。如eval函数。(安全起见一般使用funcation函数构建)。
为什么DOM 是不涉及服务端的纯前端技术,而是通过浏览器端解析形成的DOM树?
DOM 是浏览器端根据接收到的 HTML 文档构建的。这个过程发生在浏览器接收到服务器响应之后。当用户在浏览器一个网页时,浏览器会向服务器发送一个 HTTP 请求。服务器处理这个请求,并返回一个包含 HTML 内容的 HTTP 响应。浏览器接收到这个响应后,开始解析 HTML 文档,并根据其内容构建 DOM 树。DOM 树是浏览器用来表示和操作 HTML 文档的编程接口。它是一个节点树,其中每个节点代表 HTML 文档中的一个元素、属性或文本片段。浏览器使用 DOM 树来呈现网页,并允许 JavaScript 代码动态地修改网页内容和结构。
常见的动态代码接收器有哪些?
-
eval()函数:可以将字符串作为JavaScript代码执行。
-
new Function()构造函数:可以创建一个新的函数,其参数和函数体都是字符串。
-
setTimeout()和setInterval()函数:可以接受字符串形式的代码,并在指定的时间后执行。
-
innerHTML属性:可以将字符串插入到DOM中,如果字符串中包含脚本标签,这些脚本将会被执行。
-
document.write() :JavaScript 中用于将文本写入 HTML 文档的方法。可以直接在文档中插入字符串,用于动态生成内容。document.write() 只能在页面加载过程中使用,如果在页面加载完成后调用,它会覆盖整个文档内容。
-
document.writeln() 与 document.write() 类似,它会在写入的字符串末尾添加一个换行符(n)。它也只能在页面加载过程中使用。
-
document.domain :用于设置或获取当前文档的域名的一个属性。它通常用于跨域通信,通过设置相同的 document.domain ,不同子域的页面可以相互通信。设置 document.domain 可能会带来安全风险。
-
Element.innerHTML 用于获取或设置指定 DOM 元素的 HTML 内容。通过设置 innerHTML,可以动态地修改元素的内容,包括插入新的 HTML 标签。
-
Element.outerHTML 用于获取或设置指定 DOM 元素及其内容的 HTML 字符串。与 innerHTML 不同,outerHTML 包括元素本身及其所有子元素。通过设置 outerHTML,可以完全替换元素及其内容。
-
Element.insertAdjacentHTML() 用于将指定的 HTML 字符串插入到 DOM 元素的指定位置的方法。它有四个可选的位置参数:
'beforebegin':在元素之前插入。
'afterbegin':在元素的第一个子元素之前插入。
'beforeend':在元素的最后一个子元素之后插入。
'afterend':在元素之后插入。
-
Element.onevent :是一种事件处理程序的写法,其中 event 是事件的名称(如 onclick、onmouseover 等)。通过设置 onevent 属性,可以为 DOM 元素绑定事件处理函数。例如,someDOMElement.onclick = function() { alert('Clicked!'); }; 会在元素被点击时触发相应的函数。
-
window.location:提供当前文档的 URL 信息,并且可以用来导航到新的页面。它包含多个属性和方法,例如:window.location.href 获取或设置当前页面的完整 URL;window.location.reload() 重新加载当前页面。
-
document.cookie:用于读取和写入浏览器中的 cookie。
-
WebSocket():用于创建一个 WebSocket 连接。它允许在客户端和服务器之间进行双向通信。
-
element.src:用于获取或设置 HTML 元素(如 <img><scrip>等)的 src 属性。
-
postMessage():用于在不同窗口或 iframe 之间安全地发送消息的方法
-
setRequestHeader():是 XMLHttpRequest 对象的一个方法,用于设置 HTTP 请求头。
-
FileReader.readAsText(): 是 FileReader 对象的一个方法,用于将文件内容读取为文本。
-
ExecuteSql():Web SQL Database API 中的一个方法,用于执行 SQL 语句。
-
sessionStorage.setItem()是 sessionStorage 对象的一个方法,用于在浏览器会话期间存储数据。
-
document.evaluate()用于在文档中执行 XPath 查询的方法
-
JSON.parse()用于将 JSON 字符串解析为 JavaScript 对象。
-
element.setAttribute()用于设置 HTML 元素的属性的方法。
-
RegExp():用于创建正则表达式对象的构造函数
END
老付
欢迎扫码
关注我们
网络安全
原文始发于微信公众号(老付话安全):如何利用基于 HTML DOM跨站脚本漏洞
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论