0x0前言
之前一直对于反射型和DOM型XSS的区别分不清楚,没有好好深入理解,短浅的将DOM型XSS归为反射型的一种。最近因为要写一下靶场,所以特别深入了一下,发现他们最大的区别就是反射型是经过后端的,它经过后端处理后返回至前端,而DOM型则是通过JS直接操作DOM树来完成的,它不经过后端。正是因为不经过后端,而大部分的过滤操作都是在后端进行,前端往往被忽略,所以在大型厂商它存在的概率甚至比反射型还大。
例如某知名安全平台就出现过一个DOM型xss漏洞:
“灯下黑”挖出国内知名安全平台某BUF的xss漏洞点击浏览
0x1 DOM树
在网页中有许多标签,当网页返回至浏览器时浏览器会为页面创建一个顶级的Document object文档对象,接着生成各个子文档对象,每个标签对应一个文档对象,每个文档对象包含属性、方法和事件。可以通过JS脚本对文档对象进行编辑从而修改页面的元素。也就是说,JS可以通过DOM来动态修改页面内容。所以部分网页为了减少请求,直接通过JS直接获取链接中的参数并将其插入的网页中。
可能触发DOM型XSS的属性:
document.referer属性
window.name属性
location属性
innerHTML属性
documen.write属性
······
0x2 缺陷场景innerHTML
该网页脚本通过location.search直接获取URL中的查询部分,并通过innerHTML操作DOM动态的将其插入到网页当中。以下是代码:
let param=decodeURI(location.search); //返回URL中的查询部分(?之后的内容)
param=param.substring(1,s.length); //返回整个查询内容
let code=""; //定义变量url
if(param.indexOf("invite=")>-1){ //判断URL是否为空
var pos=param.indexOf("invite=")+7; //过滤掉"url="字符
code=param.substring(pos,param.length); //得到地址栏里的url参数
}else{
code="邀请码为空";
}
document.getElementById("invited").innerHTML = "<div style='padding:9px 15px'>"+code+"</div>";
接下来我们输入我们熟悉的payload:
<script>alert(1)</script>
结果竟然发现没有弹窗?
查看一下DOM树,确实插入成功了,但是却没有执行,这是什么问题呢?
原来,浏览器将源代码解析的时候是从上到下进行的,当浏览器执行到我们innerHTML的时候,我们对上面的元素插入的JS,浏览器将不会再解析执行。
那么我们就没有其他办法了吗?其实是有的,我们可以利用img中的onerror来达到触发的效果。
payload:
<img src=x onerror="alert(/xss/)">
0x3 防御方法
DOM型XSS主要是由客户端的脚本通过DOM动态地输出数据到页面而不是依赖于将数据提交给服务器端,而从客户端获得DOM中的数据在本地执行,因而仅从服务器端是无法防御的。
(1) 避免客户端文档重写、重定向或其他敏感操作,同时避免使用客户端数据,这些操作尽量在服务器端使用动态页面来实现;
(2) 如果业务需求确实需要使用直接修改DOM和创建HTML文件的相关函数或方法,则需要在输出变量到页面时先进行编码转义。
function htmlspecialchars(str) {
str = str.replace(/&/g, '&');
str = str.replace(/</g, '<');
str = str.replace(/>/g, '>');
str = str.replace(/"/g, '"');
str = str.replace(/'/g, ''');
return str;
}