浏览器解码过程分析
前言
在学习xss漏洞的过程中我发现一个问题,当我想绕过过滤机制时,可以采用编码的方式进行绕过这种方法,但是并不是每一种编码格式都能绕过,需要不停的尝试才行,这样过于浪费时间。后来我发现浏览器与服务器数据传输过程中有好几种编码格式,不同的编码格式有着不同的解析引擎,作为一个浏览器,在解析一篇HTML文档时主要有三个处理过程:HTML解析,URL解析和JavaScript解析。每个解析器负责解码和解析HTML文档中它所对应的部分,其执行的先后顺序往往决定了输出的结果。
一、HTML解析
-
浏览器接收到页面数据,于是开始进行HTML 解析,构造DOM树。构造的过程与语言的编译过程是相似的,接收文档,先进行词法分析,然后语法分析,构建解析树。
-
一个HTML解析器作为一个状态机,它从输入流中获取字符并按照转换规则转换到另一种状态。在解析过程中,任何时候它只要遇到一个’<‘符号(后面没有跟’/'符
-
号)就会进入“标签开始状态(Tag open state)”。然后转变到“标签名状态(Tag name state)”,“前属性名状态(before attribute name state)”…最后进入“数据状态
-
(Data state)”并释放当前标签的token。当解析器处于“数据状态(Data state)”时,它会继续解析,每当发现一个完整的标签,就会释放出一个token。
-
这里有三种情况可以容纳字符实体,“数据状态中的字符引用”,“RCDATA状态中的字符引用”和“属性值状态中的字符引用”。在这些状态中HTML字符实体将会从“&#…”形式解码,对应的解码字符会被放入数据缓冲区中。例如,在问题4中,“<”和“>”字符被编码为“<”和“>”。当解析器解析完“
”并处于“数据状态”时,这两个字符将会被解析。当解析器遇到“&”字符,它会知道这是“数据状态的字符引用”,因此会消耗一个字符引用(例如“<”)并释放出对应字符的token。在这个例子中,对应字符指的是“<”和“>”。读者可能会想:这是不是意味着“<”和“>”的token将会被理解为标签的开始和结束,然后其中的脚本会被执行?答案是脚本并不会被执行。原因是解析器在解析这个字符引用后不会转换到“标签开始状态”。正因为如此,就不会建立新标签。因此,我们能够利用字符实体编码这个行为来转义用户输入的数据从而确保用户输入的数据只能被解析成“数据”。
什么是字符实体(character entities)?
字符实体是一个转义序列,它定义了一般无法在文本内容中输入的单个字符或符号。一个字符实体以一个&符号开始,后面跟着一个预定义的实体的名称,或是一个#符号以及字符的十进制数字。
字符实体类似于如下所示:
&entity_name;
或
&#entity_number;
如需显示小于(>)号,我们必须这样写<
或<
或<
注意:
-
使用实体名而不是编号的好处是,名称易于记忆。不过坏处是,浏览器也许并不支持所有实体名称(对实体编号的支持却很好),某些字符没有实体名称,但可以有实体编号。
-
实体名称对大小写敏感!
什么是HTML字符实体(HTML character entities)?
在HTML中,某些字符是预留的,预留字符必须被替换为字符实体,一些在键盘上找不到的字符也可以使用字符实体来替换。例如在HTML中不能使用“<”或“>”,这是因为浏览器可能误认为它们是标签的开始或结束。如果希望正确地显示预留字符,就需要在HTML中使用对应的字符实体。
可以容纳字符实体的三种情况:
- 数据状态中的字符引用
- RCDATA状态中的字符引用
- 属性值状态中的字符引用
在这三种情况中 HTML字符实体将会从“&#…”形式解码,对应的解码字符会被放入数据缓冲区中
什么是字符引用?
字符引用包括“字符值引用”和“字符实体引用”。在上述HTML例子中,‘<’ 对应的字符值引用为<
,对应的字符实体引用为<
字符实体引用也被叫做“实体引用”或“实体”。)
RCDATA的概念
要了解什么是RCDATA,我们先要了解另一个概念。在HTML中有五类元素:
-
空元素(Void elements),如
<area>,<br>,<base>
等等 -
原始文本元素(Raw text elements),有
<script>
和<style>
-
RCDATA元素(RCDATA elements),有
<textarea>
和<title>
-
外部元素(Foreign elements),例如MathML命名空间或者SVG命名空间的元素
-
基本元素(Normal elements),即除了以上4种元素以外的元素
五类元素的区别如下:
-
空元素,不能容纳任何内容(因为它们没有闭合标签,没有内容能够放在开始标签和闭合标签中间)。
-
原始