现代JavaScript前端框架如React、Angular和Vue.js通过自动转义不受信任的内容来保护您的应用程序免受跨站脚本攻击(XSS)的漏洞。尽管这对于大多数使用场景是一个合适且安全的解决方案,但在某些情况下,开发人员可能希望直接渲染HTML,因此需要绕过这种保护。
显然,这非常危险,开发人员有责任确保插入的内容是安全的。为此,至关重要的是要验证恶意用户不能控制插入的原始HTML数据。然而,应用程序中的其他不相关问题可能很快会推翻什么是可控的,什么是不可控的假设,从而导致XSS漏洞。
这篇博客文章将展示绕过框架内置的内容清理功能的危险,并解释攻击者如何利用财务应用程序Firefly III[1]进行攻击。我们将解释客户端路径遍历和故意绕过清理功能的结合如何使您的应用程序也变得脆弱。
绕过内置清理功能[2]
为了本篇博客的目的,我们将以Vue.js[3]为例,该框架被Firefly III所使用。同样的原则也适用于其他JavaScript前端框架,如React和Angular。
Vue.js使用Mustache模板语法,通过双花括号将文本插入元素中:
<template>
<div>{{ userInput }}</div>
</template>
内置的清理功能确保即使userInput
包含恶意的HTML,如<img src=x onerror=alert(1)>
,也不会触发警告框,因为userInput
的值仅作为文本插入。这可以通过检查浏览器开发工具中DOM树可视化的语法高亮来验证。整个img
标签在此处显示为黑色:
可能存在一种情况,开发人员不仅希望动态插入文本,还希望插入原始HTML。为此,可以使用v-html
指令来绕过仅文本的限制:
<template>
<div v-html="userInput"></div>
</template>
如果userInput
包含<img src=x onerror=alert(1)>
,它实际上会作为原始HTML插入,并且会触发警告框。此时DOM树中的语法高亮看起来如下:
这种故意绕过内置清理功能的操作应谨慎使用,并且仅在能够确保用户无法控制插入的值为原始HTML的场景下使用。这不仅适用于Vue.js,也适用于其他JavaScript前端框架。
Sonar的源代码分析为JavaScript提供了400多条规则[4],其中包括针对React[5]、Angular[6]和Vue.js[7]的特定规则。当我们在SonarCloud[8]上分析流行的财务应用程序Firefly III时,触发了其中的一条规则。这个问题迅速引起了我们的注意:
在SonarCloud上查看此问题[9]
在接下来的部分中,我们将解释为什么这是一个不安全的绕过,并描述攻击者如何利用客户端路径遍历(CSPT)来控制作为原始HTML渲染的error_message
值。
Firefly III 清理功能绕过与客户端路径遍历 (CVE-2024-22075)[10]
在检查SonarCloud提出的问题所在文件时,我们注意到error_message
变量是在对/api/v1/webhooks/
端点的Axios请求的catch块中填充的。当Web服务器返回非2xx
状态码时,会进入catch块。在这种情况下,error_message
会被填充为JSON响应中的message
值:
downloadWebhook: function (id) {
axios.get({% mark yellow %}'./api/v1/webhooks/'{% mark %} + {% mark yellow %}id{% mark %}).then(response => {
// ... handle response ...
}).catch(error => {
{% mark yellow %}this.error_message = error.response.data.message;{% mark %}
});
},
传递给downloadWebhook
函数的id
变量被附加到请求的API端点上。这个id
是通过window.location.href
属性从浏览器的当前URL中获取的:
const page = {% mark yellow %}window.location.href{% mark %}.split('/');
const webhookId = page[page.length - 1];
this.downloadWebhook({% mark yellow %}webhookId{% mark %});
因此,当id
为1
时,浏览器发出的请求如下所示:
攻击者如果想要将HTML代码注入到error_message
中,需要使API请求返回非2xx
状态码并控制Web服务器返回的JSON message
值的一部分。
由于传递给downloadWebhook
函数的id
直接从浏览器的URL中获取并附加到请求的API端点上,且没有经过任何清理,攻击者可以通过构造一个恶意URL,使id
遍历到另一个API端点。这种技术称为客户端路径遍历(CSPT)[11].
让我们来看一个例子。通常,浏览器的URL看起来像这样:
http://example.com/webhooks/edit/{% mark yellow %}1{% mark %}
在这个例子中,id
是最后一个斜杠之后的所有内容。因此,id
为1
。客户端JavaScript代码发出的对应API请求如下:
http://example.com/api/v1/webhooks/{% mark yellow %}1{% mark %}
攻击者可以利用这一点,通过构造如下的恶意URL:
http://example.com/webhooks/edit/{% mark yellow %}1#/......someotherendpoint{% mark %}
1#
的开始部分是为了使服务器端端点处理程序响应有效页面。如果攻击者现在诱骗已认证的受害者访问此链接,受害者的浏览器将提取id
,即最后一个斜杠之后的所有内容:
{% mark yellow %}......someotherendpoint{% mark %}
这个id
被附加到请求的API端点上,并且受害者的浏览器会将反斜杠标准化为正斜杠。因此,浏览器会向以下端点发出请求:
http://example.com/{% mark yellow %}some/other/endpoint{% mark %}
攻击者可以利用/reports/default/1/<start>/<end>
端点来控制返回
的JSON message
值的一部分。通过仔细构造参数,攻击者可以让服务器返回如下响应:
此时,由于error_message
通过v-html
指令渲染在页面上,而这个指令可以直接渲染HTML,攻击者插入的HTML会在受害者的浏览器中执行。
在分析期间,SonarCloud标记了v-html
指令的存在并触发了规则6299[12]。开发者应将v-html
替换为安全替代方案,如DOMPurify
,以删除潜在危险的HTML。
结论[14]
绕过现代JavaScript前端框架中内置的清理功能是危险的,并且应非常谨慎地使用。通过将这些清理功能绕过与客户端路径遍历攻击结合,攻击者可能会控制动态渲染的原始HTML数据。在此博客文章中,我们使用Vue.js的v-html
指令和Firefly III应用程序中的CSPT漏洞(CVE-2024-22075[15])演示了这一点。
原文始发于微信公众号(3072):CVE-2024-22075 Firefly III CSPT漏洞分析