看面试题的时候看到有问到过浏览器的自解码机制,这里学习一下。
浏览器的自解码机制
浏览器在解析html文档时,有三个过程:HTML解析、CSS解析、JavaScript解析和URL解析。
- HTML/SVG/XHTML 解析。解析这三种文件会产生一个DOM Tree。
- CSS 解析,解析CSS会产生CSS规则树。
HTML自解码
HTML有两种编码方式:进制编码和实体编码。
进制编码:
- html 10进制编码:alert =
alert
- html 16进制编码:alert =
alert
实体编码:html实体编码是将一些特殊的字符进行编码。例如:(=>(
JavaScript自解码
再html文档中,JavaScript代码会被JavaScript解释器自动解码,有三种编码方式:Unicode,十进制,十六进制。
1 | <img src="1" onerror=\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0029> |
对于上面这个,浏览器并不执行JavaScript代码,这是因为JavaScript解释器认为上面的JavaScript代码都是文本字符,所以不解析。
在JavaScript中,单引号,双引号和圆括号等属于控制字符,编码后将无法识别。所以对于防御来说,应该编码这些控制字符。
下面这种方式可以解析:
1 | <img src="1" onerror=\u0061\u006c\u0065\u0072\u0074('\u0031')> |
从浏览器解析过程中可以知道浏览器先进行HTML自解码,所以可以使用多种编码:
1 | <img src="1" onerror=\u0061\u006c\u0065\u0072\u0074('\u0031')> |
JavaScript自解码
对于下面的这个例子:
1 | <a href="javascript:alert(1)">test</a> |
其中alert(1)
是在JavaScript环境中的,所以可以被JavaScript自解码。
JavaScript编码后:
1 | <a href="javascript:\u0061\u006c\u0065\u0072\u0074(3)">test</a> |
又由于是在href中,href属性会调用url解码,所以可以进行url解码,但是协议名不可以被编码。
URL编码后:
1 | <a href="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(3)">test</a> |
最后再html编码:
1 | <a href="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(3)">test</a> |
所以这里浏览器进行解码的过程是:
- 先进行HTML解码
- 由于这里是href属性,里面带一个URL链接,所以再进行URL解码
- 最后进行js解码。
对于下面这个例子:
1 | <a onclick="window.open('url1')" href="javascript:window.open(url2)"> |
url1的解码顺序:HTML解码->js解码->URL解码
url2的解码顺序:HTML解码->URL解码->js解码->URL解码
参考
XSS基础——浏览器自解码机制:https://whip1ash.cn/2018/07/01/HTML-Javscript-self-decode/