web安全 – DOM based XSS 防御


在javascript执行上下文中,可以访问和设置HTML, HTML属性, URL 和CSS,因此这些我们称为子上下文。

1.先进行HTML编码再进行javascript编码,将不受信任的数据插入执行上下文中的HTML子上下文之前。

有几种方法和属性可用于在javascript中直接呈现HTML内容。这些方法构成了执行上下文中的HTML子上下文。
如果这些方法提供了不受信任的输入,则可能会导致XSS漏洞。

xss漏洞

element.innerHTML = "<HTML> Tags and markup";
element.outerHTML = "<HTML> Tags and markup";
document.write("<HTML> Tags and markup");
document.writeln("<HTML> Tags and markup");

HTML 编码和javascript编码

var ESAPI = require('node-esapi');
element.innerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
element.outerHTML = "<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>";
document.write("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");
document.writeln("<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForHTML(untrustedData))%>");

2. 进行javascript编码,在将不受信任的数据插入HTML属性子上下文之前。

当在DOM执行上下文中时,只需要对不执行代码的HTML属性(事件处理程序,CSS和URL属性以为的属性)进行javascript编码。

javascript编码

var ESAPI = require('node-esapi');
var x = document.createElement("input");
x.setAttribute("name", "company_name");
x.setAttribute("value", '<%=ESAPI.encoder().encodeForJavascript(companyName)%>');
var form1 = document.forms[0];
form1.appendChild(x);

3. 将不可信的数据插入事件处理程序和javascript子上下文时

将动态数据插入javascirpt代码中尤其危险,javascript编码对javascript编码数据具有不同的语义。在许多情况下,
javascript编码不会阻止执行上下文中的攻击,因此建议是避免在这种情况下包含不受信任的数据。

  • setAttribute(name_string, value_string)方法很危险,因为它隐式地将value_string强制转化为name_string的DOM属性数据类型。
    其他将代码作为字符串类型的方法也有类似的问题(setTimeout, setInterval, new Function, eval 等)。

无效的javascript编码

var x = document.createElement("a");
x.href="#";
// In the line of code below, the encoded data on the right (the second argument to setAttribute)
// is an example of untrusted data that was properly JavaScript encoded but still executes.
x.setAttribute("onclick", "/u0061/u006c/u0065/u0072/u0074/u0028/u0032/u0032/u0029");
var y = document.createTextNode("Click To Test");
x.appendChild(y);
document.body.appendChild(x);

在上面的例子中,属性名称是一个javascript事件处理程序,因此属性值被隐式地转换为javascript代码。因此在上述情况下
javascript编码并不能缓解基于DOM的XSS。

有效的javascript编码

<!-- Does NOT work  -->
<a id="bb" href="#" onclick="/u0061/u006c/u0065/u0072/u0074/u0028/u0031/u0029"> Test Me</a>

使用Element.setAttribute(…)设置Dom属性的替代方法是直接设置属性,直接设置事件处理程序属性将允许javascript编码来
缓解基于DOM的XSS,但将不受信任的数据放入命令执行上下文中总是很危险的设计。

//The following does NOT work because the event handler is being set to a string.
//"alert(7)" is JavaScript encoded.
document.getElementById("bb").onclick = "/u0061/u006c/u0065/u0072/u0074/u0028/u0037/u0029";

//The following does NOT work because the event handler is being set to a string.
document.getElementById("bb").onmouseover = "testIt";

//The following does NOT work because of the encoded "(" and ")".
//"alert(77)" is JavaScript encoded.
document.getElementById("bb").onmouseover = /u0061/u006c/u0065/u0072/u0074/u0028/u0037/u0037/u0029;

//The following does NOT work because of the encoded ";".
//"testIt;testIt" is JavaScript encoded.
document.getElementById("bb").onmouseover = /u0074/u0065/u0073/u0074/u0049/u0074/u003b/u0074/u0065/u0073
                                            /u0074/u0049/u0074;

//The following DOES WORK because the encoded value is a valid variable name or function reference.
//"testIt" is JavaScript encoded
document.getElementById("bb").onmouseover = /u0074/u0065/u0073/u0074/u0049/u0074;

function testIt() {
   alert("I was called.");
}

javascript基于国际标准,因此javascript编码除了支持替代字符串表示(字符串编码)外,还支持编程结构和变量中的国际字符。

 for(var /u0062=0; /u0062 < 10; /u0062++){
     /u0064/u006f/u0063/u0075/u006d/u0065/u006e/u0074
     ./u0077/u0072/u0069/u0074/u0065/u006c/u006e
     ("/u0048/u0065/u006c/u006c/u006f/u0020/u0057/u006f/u0072/u006c/u0064");
 }
 /u0077/u0069/u006e/u0064/u006f/u0077
 ./u0065/u0076/u0061/u006c
 /u0064/u006f/u0063/u0075/u006d/u0065/u006e/u0074
 ./u0077/u0072/u0069/u0074/u0065(111111111);
 var s = "/u0065/u0076/u0061/u006c";
 var t = "/u0061/u006c/u0065/u0072/u0074/u0028/u0031/u0031/u0029";
 window[s](t);

4. javascript编码,在将不可信任的数据插入css属性子上下文时

从CSS上下文执行javascript需要将 javascript:attackCode()传递给CSS url()方法或调用CSS expression() 方法传递
javascipt代码。目前从执行上下文调用expression()函数已被禁用,为了减轻CSS url()方法的影响,请确保对传递给CSS
url()方法的数据进行URL编码。

URL编码与javascript编码

var ESAPI = require('node-esapi');
document.body.style.backgroundImage = "url(<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForURL(companyName))%>)";

5. 先进行URL编码,再进行javascript编码,再将不受信任的数据插入URL属性子上下文时

URL编码和javascript编码

var ESAPI = require('node-esapi');
var x = document.createElement("a");
x.setAttribute("href", '<%=ESAPI.encoder().encodeForJavascript(ESAPI.encoder().encodeForURL(userRelativePath))%>');
var y = document.createTextElement("Click Me To Test");
x.appendChild(y);
document.body.appendChild(x);

6. 使用安全的javascript函数或属性填充DOM

使用不受信任的数据填充DOM最基本的安全方法是使用安全赋值属性textContent。

<script>
element.textContent = untrustedData;  //does not execute code
</script>

7. 修复DOM based XSS漏洞

修复基于DOM的XSS漏洞的最佳方法是使用正确的输出方法(接收器)。

<b>Current URL:</b> <span id="contentholder"></span>
...
<script>
document.getElementById("contentholder").textContent = document.baseURI;
</script>

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/289854.html

(0)
上一篇 2022年9月16日
下一篇 2022年9月16日

相关推荐

发表回复

登录后才能评论