XSS预防和.innerHTML

时间:2015-06-05 08:08:49

标签: javascript encoding xss innerhtml

当我允许用户将数据作为参数插入JS innerHTML函数时,如下所示:

element.innerHTML = “User provided variable”;

我明白为了防止XSS,我必须进行HTML编码,然后对用户输入进行JS编码,因为用户可以插入这样的内容:

<img src=a onerror='alert();'>

只有HTML或仅JS编码无济于事,因为我理解的.innerHTML方法在将输入插入页面之前解码输入。使用HTML + JS编码,我注意到.innerHTML仅解码JS,但HTML编码仍然存在。

但我能够通过双重编码实现相同的目标。

我的问题是:有人可以举例说明为什么我应该进行HTML编码然后进行JS编码,而不是在使用.innerHTML方法时在HTML中进行双重编码?

3 个答案:

答案 0 :(得分:17)

  

有人可以举例说明为什么我应该进行HTML编码   使用.innerHTML时,JS编码,而不是HTML编码   方法

不确定

假设&#34;用户提供了数据&#34;服务器在您的JavaScript中填充,然后您必须使用JS编码才能获得它。

以下是服务器端的伪代码,但前端是JavaScript:

var userProdividedData = "<%=serverVariableSetByUser %>";
element.innerHTML = userProdividedData;

与ASP.NET <%= %>一样,输出服务器端变量而不进行编码。如果用户是好的&#34;并提供值foo,然后这会导致呈现以下JavaScript:

var userProdividedData = "foo";
element.innerHTML = userProdividedData;

到目前为止没有任何问题。

现在说恶意用户提供值"; alert("xss attack!");//。这将呈现为:

var userProdividedData = ""; alert("xss attack!");//";
element.innerHTML = userProdividedData;

这将导致XSS漏洞,其中代码实际上是在上面的第一行中执行的。

为了防止这种情况,正如你所说的JS编码。 OWASP XSS prevention cheat sheet rule #3说:

  

除字母数字字符外,请将所有字符转义为小于   256用\ xHH格式防止切换出数据值   进入脚本上下文或另一个属性。

因此,为了防止这种情况,您的代码将是

var userProdividedData = "<%=JsEncode(serverVariableSetByUser) %>";
element.innerHTML = userProdividedData;

其中JsEncode根据OWASP建议进行编码。

这可以防止上述攻击,因为它现在呈现如下:

var userProdividedData = "\x22\x3b\x20alert\x28\x22xss\x20attack\x21\x22\x29\x3b\x2f\x2f";
element.innerHTML = userProdividedData;

现在您已经针对XSS保护了JavaScript变量分配。

但是,如果恶意用户提供<img src="xx" onerror="alert('xss attack')" />作为值,该怎么办?这对于变量赋值部分来说没问题,因为它只会被转换为与上面相同的十六进制实体。

但行

element.innerHTML = userProdividedData;
当浏览器呈现内部HTML时,

会导致alert('xss attack')被执行。这将是DOM Based XSS攻击。

这就是你需要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;')
}

制作代码

element.innerHTML = escapeHTML(userProdividedData);

或者可以通过JQuery&#39; text()函数完成。

关于评论中的问题的更新

  

我还有一个问题:你提到我们必须JS编码   因为攻击者可以进入"; alert("xss attack!");//。但是,如果我们   会使用HTML编码而不是JS编码,也不会   HTML会对"符号进行编码,因此我们无法进行此攻击   会:var userProdividedData ="&quot;; alert(&quot;xss attack!&quot;);&#x2F;&#x2F;";

我提出的问题意味着以下内容:为什么我们不首先使用HTML编码,而不是使用HTML编码,而不是HTML编码。 ?

好吧,因为他们可以编码<img src="xx" onerror="alert('xss attack')" />所有使用\xHH格式编码的攻击来插入其有效负载 - 这将实现所需的HTML攻击序列,而不使用任何HTML字符编码会影响。

还有一些其他攻击:如果攻击者输入\,那么他们可能会强制浏览器错过结束引用(因为\是JavaScript中的转义字符。)

这将呈现为:

var userProdividedData = "\";

会触发JavaScript错误,因为它不是正确终止的语句。如果应用程序在显着位置呈现,则可能导致拒绝服务。

另外说有两条用户控制的数据:

var userProdividedData = "<%=serverVariableSetByUser1 %>" + ' - ' + "<%=serverVariableSetByUser2 %>";
然后,用户可以在第一个中输入\,在第二个中输入;alert('xss');//。这会将字符串连接更改为一个大的赋值,然后是XSS攻击:

var userProdividedData = "\" + ' - ' + ";alert('xss');//";

由于像这样的边缘情况,建议遵循OWASP指南,因为它们尽可能接近防弹。您可能认为将\添加到HTML编码值列表中可以解决这个问题,但是在以这种方式呈现内容时,还有其他原因使用JS后跟HTML,因为此方法也适用于属性值中的数据:

<a href="javascript:void(0)" onclick="myFunction('<%=JsEncode(serverVariableSetByUser) %>'); return false">

尽管是单引号还是双引号:

<a href='javascript:void(0)' onclick='myFunction("<%=JsEncode(serverVariableSetByUser) %>"); return false'>

甚至没有引用:

<a href=javascript:void(0) onclick=myFunction("<%=JsEncode(serverVariableSetByUser) %>");return false;>

如果HTML编码如评论中提到的实体值:

onclick='var userProdividedData ="&quot;;"'(缩短版)

代码实际上是先通过浏览器的HTML解析器运行,因此userProdividedData将是

";;

而不是

&quot;;

因此当您将其添加到innerHTML电话时,您将再次使用XSS。请注意,<script>块不会通过浏览器的HTML解析器进行处理,但结束</script>代码but除了another story之外。

如上所示,编码为 late 总是明智的。然后,如果您需要在JavaScript上下文之外的任何内容中输出值(例如,实际的警告框不呈现HTML,那么它仍将正确显示)。

也就是说,上面我可以打电话

alert(serverVariableSetByUser);

和设置HTML一样简单

element.innerHTML = escapeHTML(userProdividedData);

在这两种情况下,它都会正确显示而不会破坏输出或导致不良代码执行。

答案 1 :(得分:6)

确保element内容正确编码(并且不会被解析为HTML)的简单方法是使用textContent代替innerHTML

element.textContent = "User provided variable with <img src=a>";

另一种选择是仅在您编码后使用innerHTML(如果有机会,最好在服务器上)使用您想要使用的值。

答案 2 :(得分:2)

我在ASP.NET Webforms应用程序中遇到过这个问题。对此的修复相对简单。

从NuGet Package Manager安装HtmlSanitizationLibrary并在您的应用程序中引用它。在后面的代码中,请按以下方式使用清洁剂类。

例如,如果当前代码看起来像这样,

YourHtmlElement.InnerHtml = "Your HTML content" ;

然后,将其替换为以下内容:

string unsafeHtml = "Your HTML content"; 
YourHtmlElement.InnerHtml = Sanitizer.GetSafeHtml(unsafeHtml);

此修复程序将删除Veracode漏洞并确保该字符串呈现为HTML。在后面的代码中对字符串进行编码会将其呈现为“未编码的字符串”而不是RAW HTML,因为它在渲染开始之前进行了编码。