今天看道哥的白帽子讲web安全中XSS的防御部分,不太明白,所以就查了相关的服务器编码与浏览器解码,做一下小总结吧。
参考:https://security.yirendai.com/news/share/26 这篇文章真是一场解惑的及时雨
浏览器解析过程
浏览器在解析HTML文档时无论按照什么顺序,主要有三个过程:HTML解析、JS解析和URL解析,每个解析器负责HTML文档中各自对应部分的解析工作。下面以一篇HTML文档解析来简单的讨论下解析器如何协同工作的。
首先浏览器接收到一个HTML文档时,会触发HTML解析器对HTML文档进行词法解析,这一过程完成HTML解码并创建DOM树,接下来JavaScript解析器会介入对内联脚本进行解析,这一过程完成JS的解码工作,如果浏览器遇到需要URL的上下文环境,这时URL解析器也会介入完成URL的解码工作,URL解析器的解码顺序会根据URL所在位置不同,可能在JavaScript解析器之前或之后解析。
深入理解
下面我们结合具体示例来讨论下浏览器的解析原理过程和XSS复合编码的一些内容:
1 | <a href="javascript:alert(1)">test</a> |
针对上述a标签我们分析一下该环境中浏览器的解析顺序,首先HTML解析器开始工作,并对href中的字符做HTML解码,接下来URL解析器对href值进行解码,正常情况下URL值为一个正常的URL链接,URL解析器工作完成后是不需要其他解码的,但是该环境中URL资源类型为JavaScript,因此该环境中最后一步JavaScript解析器还会进行解码操作,最后解析的脚本被执行。
整个解析顺序为3个环节:HTML解码— URL解码— JS解码
我们对href值做一些编码的转换,对照刚才分析的解析过程,思考一下脚本是否会正常执行?
Test1: 对javascript:alert(1);
URL编码
Test2: 对javascript html实体编码;对alert(2); url编码
Test3: 三层复合编码
JS编码:
<a href="javascript:\u0061\u006c\u0065\u0072\u0074(3)">test3</a>
URL编码:
<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)">test3</a>
HTML编码:
<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)">test3</a>
html在线测试:
1 | <body> |
测试结果:test1无法弹窗;test2、test3成功弹框
思考:
Test1: HTML解码,URL解码为:javascript:alert(1); 然后js执行。emmm… 我是像上面这样想的,但是为什么执行的时候是404呢?这就涉及到URL解析中的一个细节,不能对协议进行编码,否则url解析器会认为它无类型,从而javascript没有被解码,自然就不会被执行了。于是404…
Test2: HTML解码javascript;URL解码alert(1); JS解析完成执行操作
Test3: HTML解码为编码第二步,继续HTML解码出javascript,URL解码,JS解码并执行
扩展:
场景分析:
1 | <img src=x onclick="{$value}" > |
如果$value
用户可控,如输入为alert(‘m3lon’);那么如果防御XSS?
如果只进行html实体编码,那浏览器直接html解码—> JS解码执行 肯定不可以的
那如果加上一层JS编码呢?即JS编码—>html编码
浏览器解码顺序为:html解码—>JS解码,按理说也会执行,但是实际上不会,为什么呢?
这里有一个关键点:在js中,单引号,双引号和圆括号等属于控制字符,编码后将识别为文本字符(而不是控制字符)。所以对于防御来说,应该编码这些控制字符。下面这种方式可以解析。
<img src="1" onerror=\u0061\u006c\u0065\u0072\u0074('\u0031')>
总结:
文章一方面浅谈了html解析过程,深入的解析可以看下面第二个链接,时间有限,就先不深入研究了;另一方面重点描述了URL解码与JS解码中的两个关键点:
url的协议名不可以被编码,否则url解码将视为无协议
JS自解码会将js中的控制字符如:单双引号、圆括号等识别为文本字符,只显示,不解析
参考: