在这个例子中,基于DOM的XSS是可能的吗?

时间:2015-05-18 09:57:36

标签: javascript security xss ecmascript-6

我一直在阅读有关基于DOM的XSS的一系列文档,但我仍然无法弄明白。让我们来看看我的例子。

var html = `
    <a class="url" href="${untrustedURL}">
        <img src="${untrustedSource}">
    </a>
    <span class="name" data-value="${untrustedValue}">${untrustedText}</span>
`;
document.querySelector('#user').innerHTML = html;

攻击者如何利用此代码的漏洞?什么是解决方案?

3 个答案:

答案 0 :(得分:3)

通过网址和图片来源,不受信任的值将是,例如:

javascript:evilStuff()

对于链接,代码将在用户单击时运行,对于图像的源,它将在浏览器尝试加载图像时运行。请注意,图像src的技术仅适用于旧版浏览器,现代版本将忽略它。我在链接中看到的另一个问题是,例如,您可以获得指向钓鱼网站的链接!

只有当您在代码中的其他位置使用该值时,数据值属性才会变得容易受到攻击,并且可能有害,否则,我不会在那里看到危险。

至于跨度的内容,如果你不转义HTML字符,几乎任何东西都可以插入其中。脚本标签,iframe,图像等...请注意,您在任何地方插入的所有不安全值都是如此。

恶意的人可以在任何您无法逃脱HTML实体的地方插入任何HTML。

我认为,解决方案始终是逃避/剥离标签和某些值。例如,为了防止用户在动态href中插入危险的URL,您可以应用从字符串开头删除单词javascript:的正则表达式,或检查无效的URL(不同的域,不寻常)字符,格式错误的网址等。)

答案 1 :(得分:3)

虽然我同意@Alfonso的回答中提到的漏洞,但情况实际上更糟:你的不可信变量的所有都容易受到XSS攻击。

例如,

untrustedURL包含以下文字

"><img src="http://example.com" onerror=alert(/xss/) data-x="

这将导致呈现以下内容:

<a class="url" href=""><img src="http://example.com" onerror="alert(/xss/)" data-x="">

将导致JavaScript警报立即显示:

ESS XSS

由于您的代码已经在JavaScript上下文中,因此您需要follow Rule #1 of the OWASP XSS cheat sheet并对数据进行HTML编码。只需简单转换以下字符即可:

 & --> &amp;
 < --> &lt;
 > --> &gt;
 " --> &quot;
 ' --> &#x27;     &apos; not recommended because its not in the HTML spec (See: section 24.4.1) &apos; is in the XML and XHTML specs.
 / --> &#x2F;     forward slash is included as it helps end an HTML entity

请注意,OWASP建议HTML属性值使用规则#2,但是如果引用所有属性,则上述内容就足够了。规则#2适用于所有地方,包括不加引号,因此如果你有混合规则#2将更简单。

我已经阅读了your comment关于你说你应该encode Javascript after escaping HTML entities

是的,这适用于最初来自(例如来自服务器端)的值,但您应该使用服务器端代码使用的语言进行此编码,而不是JavaScript。此外,首先执行JavaScript转义以将服务器端变量转换为JavaScript,然后在JavaScript中使用HTML转义以准备插入DOM。

e.g。 ASP.NET C#中的JavaScript转义:

<script>
var untrustedURL = "<%=HttpUtility.JavaScriptEncodeString(usersUrl)%>";
</script>

See my answer here for greater detail on this

然后你需要使用函数进行HTML编码:

function escapeHTML (unsafe_str) {
    return unsafe_str
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/\"/g, '&quot;')
      .replace(/\'/g, '&#39;')
      .replace(/\//g, '&#x2F;')
}

所以你的代码可能只是

<script>
var untrustedURL = escapeHTML("<%=HttpUtility.JavaScriptEncodeString(usersUrl)%>");
</script>

untrustedURLuntrustedSource

请注意,这些都是应进行验证的特殊情况。您应该在服务器端执行此操作,并确保它们以http://https:////protocol relative URL)开头。白名单方法可确保用户无法输入javascript:方案URL,并且还可以防止输入可能对用户的浏览器,操作系统,设备,配置等唯一的不同方案。仅允许HTTP很多更安全。

答案 2 :(得分:0)

假设${untrustedText}未进行HTML转义,请尝试将其设置为,例如:

<div style="position:fixed;left:0;right:0;top:0;bottom:0;"
  onmousemove="this.style.display='none';alert('XSS');"></div>