浏览器解码顺序和解析顺序for-xss
**数据包处理过程
首先要了解我们在构造xss包的时候发生了什么:
1、在浏览器的地址栏中输入url,发送http请求头和数据;
2、数据包通过网络传输到达远程web,服务器接收到url,分析请求头,根据它找到对应资源,经过后端代码进行处理(过滤,校验),然后给前端返回响应头和数据;
3、浏览器接收到响应的数据后,对数据进行解析(下面要说的事)
浏览器解析顺序
1 浏览器接收到响应数据后,解析器先对HTML之类的文档进行解析,构建成DOM节点树,同时,CSS会被CSS解析器解析生成样式表。
2、 解析html标签过程中遇到<script>标签,则暂停HTML标签解析,控制权转交给JavaScript引擎,执行完后继续解析html,js可以对DOM进行修改。
***dom树
DOM 树(文档对象模型树)是浏览器解析 HTML 时构建的内部数据结构,表示文档的结构和内容。它将 HTML 文档转化为一个树形结构,其中每个节点代表文档中的一个元素、属性或文本内容。解析 HTML 时,浏览器按照 DOM 树的结构来理解和操作页面的内容和元素,这使得 JavaScript 能够访问和修改页面的内容和结构。通过 DOM 树,脚本可以动态地操作页面,使其与用户的交互需求相匹配。
如果在这个时候,如果修改一下,比如说把
<h1>Main Title</h1>用html编码成:<h1>Main Title</h1><h1>MainTitle</h1>
前者对标签名编码,后者对标签内容编码,结果会发现前者没有了html标签的作用,而后者正常显示。由此可以明白HTML解码的时机:它是在浏览器构建完DOM树以后才进行解码的,当解析器对前者进行解析时,无法识别为html标签,所以构建不了DOM节点,后者在顺利构建完DOM树之后对节点内容进行解码。
尾部的script脚本中改变了DOM节点树,通过对<div>操作新增了一个<img>,所以通过调换<script>和img的先后顺序,会使得弹框的顺序不同。

如果 <script> 标签放在 <head> 中且没有使用 defer 或 async 属性,JavaScript 代码会在 DOM 树构建完成之前立即执行。这可能会导致脚本尝试操作尚未构建的 DOM 元素,从而引发错误。
在这种情况下,浏览器会暂停 HTML 的解析,先执行 JavaScript 代码,然后再继续解析 HTML。这种行为可能会导致页面加载变慢。为了避免这种问题,可以将 <script> 标签放在 <body> 的底部,或使用 defer 和 async 属性来优化脚本的加载和执行时机。
所以可以看到我们的解析顺序,就是会收到影响,会使得我们的解析顺序发生改变。
浏览器的解码顺序:
首先要强调是一点是:浏览器的解码顺序和解析顺序是两码事。浏览器一般的解码顺序是先进行html解码,再进行javascript解码,最后再进行url解码,需要注意的是这里的url解码和我们发送到服务器的url解码不同,那个过程是由服务器来完成的,而不是浏览器。
明白了这个顺序,我们就可以理解
<script>
alert('1')
</script>
是无法弹框的,因为script标签内无法解析HTML实体编码。
简单的来说浏览器接受到内容后首先进行html解析,首先将识别到的标签转化为DOM树,而在这一过程中浏览器是无法识别html实体编码的,只有建立起DOM树才能对每个节点的内容进行识别,如果出现html实体编码,则会进行解码。
举个简单的例子,在XSS中如果页面可以通过用户输入的内容构造新标签,此时为了绕过过滤进行html编码。s编码为s,那么形如<img src=0 onerror=alert(1)这种payload是无法正常运行的,因为破坏了标签内的属性名src导致html解析时不会正确识别img标签无法进行DOM树构建,自然也就无法进行html实体解码过程。具体的构建DOM树的过程在下文浏览器的解析流中会具体阐述。
在此基础上,JavaScript DOM API 参与进来,可以对DOM 树进行修改,改变DOM树的结构和内容。而此时,CSS解析器则解析外部CSS 文件以及Style 标签中的样式内容,这些信息将搭配HTML 中的可见指令构建起一个Rendering Tree。
这就清晰的总结了对应的浏览器解析顺序,和解码顺序
因此我们可以看到什么时候我们编码不会被解析。因为我们构建dom树的标签都无法识别。
<!--标签被编码 g实体编码g
--><img src=1 onerror="alert('img标签名被编码')"><!--属性名被编码 s实体编码s
--><img s
rc=1 οnerrοr=alert('scr属性被编码')><!--响应事件名被编码 o实体编码o
--><img src='' o
nerror=alert('响应事件名onclick被编码')>
但是这个可以弹窗,ALERT不属于html内部
<!--响应事件属性值被编码(可以弹窗)! a实体编码a--><img src=1 οnerrοr=alert('响应事件体alert被编码')>
触发js解析
^ebc9f6
在一个页面中可以触发JS解析器的有这么几种
直接嵌入< script> 代码块。
通过< script sr=… > 加载代码。
各种HTML CSS 参数支持JavaScript:URL 触发调用。
CSS expression(…) 语法和某些浏览器的XBL 绑定。
事件处理器(Event handlers),比如 onload, onerror, onclick等等。
定时器,Timer(setTimeout, setInterval)
eval(…) 调用。
xss如何编码绕过?
html实体编码
不可以放在
<script>
中,并且编码不能影响标签和属性,从而影响dom树的构建。
js和unicode编码
这种要触发js解析器[[#^ebc9f6]]
<!--函数名被编码--><a href="javascript:\u0061lert('函数名被编码')">test</a
><!--()被编码--><a href="javascript:alert\u0028'圆括号被编码'\u0029">test</a
><!--'被编码--><a href="javascript:alert(\u0027引号被编码\0027')">test</a>
经过测试发现只有函数名被编码可以正常弹窗。
当编码位置在字符串中时,它只会被解释为正规字符,而不是单引号,双引号或者换行符这些能够打破字符串上下文的字符。这项内容清楚地写在ECMAScript中。因此,Unicode转义序列将永远不会破环字符串上下文,因为它们只能被解释成字符串常量。
<script>
\u0061\u006c\u0065\u0072\u0074(\u0031\u0032)
</script>
<script>
alert("\u0031\u0032");
</script>
Unicode 编码 alert 和 12
上面两段代码只有2会执行 1并不会执行 因为括号内的\u0031\u0032并不会被解释为字符串常亮(因为它们没有用引号闭合)所以必须要闭合才可以。
总结
在讨论过各种解析形式后,最后来讨论这些解析的先后顺序。
当浏览器从网络堆栈中获得一段内容后,触发HTML解析器来对这篇文档进行词法解析。在这一步中字符引用被解码。在词法解析完成后,DOM树就被创建好了,JavaScript解析器会介入来对内联脚本进行解析。在这一步中Unicode转义序列和Hex转义序列被解码。同时,如果浏览器遇到需要URL的上下文,URL解析器也会介入来解码URL内容。在这一步中URL解码操作被完成。由于URL位置不同,URL解析器可能会在JavaScript解析器之前或之后进行解析。考虑如下两种情况
Example A: <a href="UserInput"></a>Example B: <a href="#" onclick="window.open('UserInput')"></a>
在例A中,HTML解析器将首先开始工作,并对UserInput中的字符引用进行解码。然后URL解析器开始对href值进行URL解码。最后,如果URL资源类型是JavaScript,那么JavaScript解析器会进行Unicode转义序列和Hex转义序列的解码。再之后,解码的脚本会被执行。因此,这里涉及三轮解码,顺序是HTML,URL和JavaScript。
在例B中,HTML解析器首先工作。然而接下来,JavaScript解析器开始解析在onclick事件处理器中的值。这是因为在onclick事件处理器中是script的上下文。当这段JavaScript被解析并被执行的时候,它执行的是“window.open()”操作,其中的参数是URL的上下文。在此时,URL解析器开始对UserInput进行URL解码并把结果回传给JavaScript引擎。因此这里一共涉及三轮解码,顺序是HTML,JavaScript和URL。
第一步html解析:j a v a s c r i p t : %
5 c % 7 5 % 3 0 % 3 0 % 3 6
% 3 1 % 5 c % 7 5 % 3 0 % 3
0 % 3 6 % 6 3 % 5 c % 7 5 %
3 0 % 3 0 % 3 6 % 3 5 % 5 c
% 7 5 % 3 0 % 3 0 % 3 7 % 3
2 % 5 c % 7 5 % 3 0 % 3 0 %
3 7 % 3 4 ( 1 5 )
"变为:javascript:%5c%75%30%30%36%31%5c%75%30%30%36%63%5c%75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34(15)经过url解析:javascript:\u0061\u006c\u0065\u0072\u0074(15)javascript:触发了最后的js解析javascript:alert(15)