对浏览器解析机制的理解

2019年10月19日 0 作者 y1nhui

在研究绕过xss的相关waf时看到了部分文章使用svg标签,好奇下查询了,结果再次看了一遍浏览器解析机制,写下这篇文章。

0x000 关于浏览器解析机制的概略以及部分概念

  在解析一个html文段时,浏览器解析部分为:html解析、url解析、JavaScript解析
[html解析器细则](https://html.spec.whatwg.org/multipage/parsing.html "html解析器细则")
[url解析器细则](https://url.spec.whatwg.org/ "url解析器细则:")

#### REDATA:
在html中有五类元素:
1. 空元素(Void elements),如<area,<br,<base等等

  1. 原始文本元素(Raw text elements),有<script和<style

  2. RCDATA元素(RCDATA elements),有<textarea和<title

  3. 外部元素(Foreign elements),例如MathML命名空间或者SVG命名空间的元素

  4. 基本元素(Normal elements),即除了以上4种元素以外的元素

五类元素区别如下:
1. 空元素,不能容纳任何内容(因为它们没有闭合标签,没有内容能够放在开始标签和闭合标签中间)。

  1. 原始文本元素,可以容纳文本。

  2. RCDATA元素,可以容纳文本和字符引用。

  3. 外部元素,可以容纳文本、字符引用、CDATA段、其他元素和注释

  4. 基本元素,可以容纳文本、字符引用、其他元素和注释

0x001 HTML解析

  html解析器是一个状态机模型。html解析时,当从输入流中获取字符并按照规则转换,并且当遇到"<"(且后面无/)时会进入“标签开始状态”,之后便是“标签名状态”,“前属性名状态”等,最后会进入“数据状态”,并释放当前标签的标记。当解析器处于“数据状态”时,它会继续解析,每当发现一个完整的标签,就会释放出一个标记。
  在html解析时共有三种情况可以容纳字符实体:“数据状态中的字符引用”、“RCDATA状态中的字符引用”与“属性值状态中的字符引用”。在这些状态中HTML字符实体将会从“&#…”形式解码,对应的解码字符会被放入数据缓冲区中。需要注意,通过HTMl解析出的"<"与">"不会使html解析器进入“标签名状态”,故如果想通过 类似&lt;div>&lt;这样的方法创建xss是无效的。会产生如图的情况:

  对RCDATA有个特殊的情况。在浏览器解析RCDATA元素的过程中,解析器会进入“RCDATA状态”。在这个状态中,如果遇到“<”字符,它会转换到“RCDATA小于号状态”。如果“<”字符后没有紧跟着“/”和对应的标签名,解析器会转换回“RCDATA状态”。这意味着在RCDATA元素标签的内容中(例如<textarea或<title的内容中),唯一能够被解析器认做是标签的就是“</textarea”或者“</title”。当然,这要看开始标签是哪一个。因此,在“<textarea”和“<title”的内容中不会创建标签,就不会有脚本能够执行。
  同时需要说明的是,所有的&lt;script>都属于原始文本元素,在其内字符引用并不会被解析与解码。

0x002 URL解析

  URL解析器也是一个状态机模型,从输入流中进来的字符可以引导URL解析器转换到不同的状态。URL资源类型必须是ASCII字母(U+0041-U+005A || U+0061-U+007A),不然就会进入“无类型”状态。如,你不能对协议类型进行任何的编码操作,不然URL解析器会认为它无类型。

0x003 JavaScript解析

  JavaScript解析同以上解析器不同,JavaScript语言是一种无关内容的语言,有对应的语法描述它。
当JavaScript解析时遇到Unicode编码时,一般为三种情况:在字符串中,在标识符名称中和在控制字符中。
在字符串中的时候,JavaScript会讲之解释为正规字符,而不是’>之类的可以打破字符串上下的字符。而当Unicode转义序列出现在标识符名称中时,它会被解码并解释为标识符名称的一部分,例如函数名,属性名等等。当用Unicode转义序列来表示一个控制字符时,例如单引号、双引号、圆括号等等,它们将不会被解释成控制字符,而仅仅被解码并解析为标识符名称或者字符串常量。
  因而只有当Unicode字符处于标识符名称中时才会不被当成字符串,也只有在这里,才能被正常解析。

0x004 解析流

  解析方式大概为以上,而浏览器运作的方式则是:收到内容→html解析同时建立DOM树→JavaScript解析并且遭遇url时进行url解析。
  至于url解析与JavaScript解析谁先,则是看先遇到哪一个。如:
&lt;a href=&quot;xxxx&quot;>&lt;/a>这个就是先html解析后遇到“xxx”这个url,开始url解析,若url资源类型为JavaScript,则JavaScript解析器会进行Unicode转义序列和Hex转义序列的解码。
&lt;a href=# onclick=&quot;window.open('xxx')&quot;>&lt;/a>这个则是在html解析后先进行JavaScript解析,当windows.open执行时,xxx这个url才会被解析。