如何对浏览器解析和XSS的深度探究

这篇文章将为大家详细讲解有关如何对浏览器解析和XSS的深度探究,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

巴州网站制作公司哪家好,找成都创新互联!从网页设计、网站建设、微信开发、APP开发、响应式网站等网站项目制作,到程序开发,运营维护。成都创新互联于2013年开始到现在10年的时间,我们拥有了丰富的建站经验和运维经验,来保证我们的工作的顺利进行。专注于网站建设就选成都创新互联

一、需要了解的一些基本知识

   为什么要进行编码?

   主要是因为某些数据不适合传输。原因多种多样,如 Size 过大,包含隐私数据,另外重要的一点就是有些字符会引起歧义。

对于 URL: &用于分割多个参数,倘若有某个参数键值为 name=v&lue,就会因为 name 参数的值 v&lue 中携带了&而造成歧义。因此需要对&进行 URL 编码。url编码后,服务端会把紧跟在“%”后的字节当成普通的字节,就是不会把它当成各个参数或键值对的分隔符。

对于 HTML: 当浏览器遇到<会识别为元素定义的开始,>会识别为元素的结束。倘若有

,由于标签的属性值携带了>,同样会造成歧义。因此需要属性值的>需要 进行 HTML 编码,即使用字符实体。

二、三种编码

2.1HTML 编码(字符实体)

字符实体是一个预先定义好的转义序列。 字符实体两种表示方法:

1、 字符实体以&开头+预先定义的实体名称+;分号结束,如“<”的实体名称为&lt;

2、 字符实体还可以以&开头+#符号+字符在 ASCII 对应的十进制数字+;分号结束,如<的实体编号为&#60;

字符都是有实体编号的,但有些字符是没有实体名称

显示结果 描述           实体名称           实体编号           

空格&nbsp;&#160;
小于号&lt;&#60;
大于号&gt;&#62;
&和号&amp;&#38;
"引号&quot;&#34;
'撇号 &apos; (IE不支持)&#39;
分(cent)&cent;&#162;
£镑(pound)&pound;&#163;
¥元(yen)&yen;&#165;
欧元(euro)&euro;&#8364;
§小节&sect;&#167;
©版权(copyright)&copy;&#169;
®注册商标&reg;&#174;
商标&trade;&#8482;
×乘号&times;&#215;
÷除号&divide;&#247;

2.2 JavaScript 编码

最常用的,如\uXXXX 这种写法的Unicode 转义序列,表示一个字符,其中 XXXX 表示一个 16 进制数字,如<的Unicode 编码为\u003c。

2.3 URL 编码

RFC3986 文档规定,URL 中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4 个特殊字 符以及所有保留字符。 RFC3986 中指定了以下字符为保留字符:! * ' ( ) ; : @ & = + $ , / ? # [ ]

编码方式 %加字符在 ASCII 码表中的十六进制值。例如,/在 ASCII 码表中十六进制为 0x2f,那么它对应的 URL 编码为%2f。

JavaScript 中提供了 3 个函数用来对 URL 编码以得到合法的 URL:

1、 escape()

2、 encodeURI()

3、 encodeURIComponent()

三、浏览器解码规则

如何对浏览器解析和XSS的深度探究

浏览器无论什么情况都会遵守一个这样的解码规则:

1、 HTML 解析器对 HTML 文档进行解析,完成 HTML 解码并且创建 DOM 树

2、 JavaScript 或者 CSS 解析器对内联脚本进行解析,完成 JS、CSS 解码

3、 URL 解码会根据 URL 所在的顺序不同而在 JS 解码前或者解码后

3.1HTML 解析器

3.1.1HTML 中有五类元素:

1、 空元素(Voidelements),有 area、base、br、col、command、embed、hr、img、input、 keygen、link、meta、param、source、track、wbr

2、 原始文本元素(Raw textelements),有这样字符实体并不会被解码,也就不会执行 JS。

3.1.4 RCDATA

在 HTML 中,属于RCDATAElements的标签有两个:textarea、title。

RCDATA Elements 类型的标签可以包含文本内容和字符实体。

解析器解析到 textarea、title标签的数据部分时,状态会进入 RCDATA State。

前面我们提到,处于 RCDATA State 状态时,字符实体是会被解析器解码的。

示例:

<和>被编码为实体&#60;和&#62;。 解析器解析到它们时会进行解码,最终得到。但是里面的 JS 同样还是不会被执 行,原因还是因为解码字符实体状态机不会进入标签打开状态(TagOpen State),因此里面的

不能弹窗,Raw text elements 类型标签下的所有字符实体编码都不会被 HTML 解码

能弹窗,在 XML 中,&#40;会被解析成(,在 XML 中实体会自动转义,除了 包含的实体

3.2 JavaScript 解析器

形如 \uXXXX 这样的 Unicode 字符转义序列或 Hex 编码是否能被解码需要看情况。 首先,JavaScript 中有三个地方可以出现 Unicode 字符转义序列:

1、字符串中(in String)

Unicode 转义序列出现在字符串中时,它只会被解释为普通字符,而不会破坏字符串的上下文。

例如,

被编码转义的部分为 10,是字符串,会被正常解码,JS 代码也会被执行。

2、标识符中(in identifier names)

若 Unicode 转义序列存在于标识符中,即变量名(如函数名等…),它会被进行解码。

例如,

被编码转义的部分为 alert 字符,是函数名,属于在标识符中的情况,因此会被正常解码,JS 代码也会被执行。

3、控制字符中(in control characters)

若 Unicode 转义序列存在于控制字符中,那么它会被解码但不会被解释为控制字符,而会被解释为标识符或字符串字符的一部分。 控制字符即'、"、()等。

例如,,(进行了 Unicode 编码,那么解码后它不再是作为控制字符,而是作为标识符的一部分alert(。

因此函数的括号之类的控制字符进行Unicode 转义后是不能被正常解释的。

总结:Unicode 序列不能出现在控制字符中,否则不能被解释。

示例 1:

被编码部分为 alert(11)。

该例子中的 JS 不会被执行,因为控制字符被编码了。

示例 2:

被编码部分为 alert 及括号内为12。

该例子中 JS 不会被执行,原因在于括号内被编码的部分不能被正常解释,即使反编码之后为数字,但是仍然按照字符串来处理(这里的12为字符串12,并不是int整数)。要么使用 ASCII 数字,要么加""或''使其变为字符串,作为字符串也只能作为普通字符。

示例 3:

被编码处为'。

该例的 JS 不会执行,因为控制字符被编码了,解码后的'将变为字符串的一部分,而不再解释为控制字符。因此该例中字符串是不完整的,因为没有'来结束字符串。

示例 4:

该例的 JS 会被执行,因为被编码的部分处于字符串内,只会被解释为普通字符,不会突破字符串上下文。

示例 5:

此例无法执行。我们以浏览器的视角来看:首先读到<开始读取标签,然后读到 onerror 调用 JS 解析器。 在JS中,单引号,双引号和圆括号等属于控制字符,编码后将无法识别。所以对于防御来说,应该编码这些控制字符。

下面这种方式可以解析:

可以结合上面的 HTML 编码 按照解析顺序反过去,先 JS 编码然后 HTML 解码:

浏览器读到了<标签开始构造语法树,然后 HTML 解码,解码之后发现 onerror 于是进行 一个 JS 解码,成功弹窗

延伸:

开发人员单纯的设置 HTML 实体编码为防御 xss 的手段,但是用户输入点在 alert 中

如果用户正常输入的话凡是存在< ," 等都能被转码

攻击者可以通过语句 ");alert("test,在服务端被转码:

弹窗两次,是因为浏览器进行 HTML 解码发现存在两个 alert()

所以对于这种情况,正确防御 XSS 的方法:

应该是先 JavaScript 编码然后再进行 HTML 编码用户输入 ");alert("test 后在服务端先 JavaScript 编码然后再进行 HTML 编码到浏览器端:首先经过第一步 HTML 解码后变为\u0022\u0029\u003B\u0061\u006C\u0065\u0072\u0074\u0028\u0022\u0074\u0065\u0073\u0074。JavaScript 解析器工作,变为");alert("test ,刚才已经讲过 JavaScript 解析时只有标识符名称不会被当做字符串,控制字符仅会被解析为标示符名称或者字符串,因此 \u0022 被解释成双引号文本,\u0028 和\u0029 被解释成为圆括号文本,不会变为控制 字符被解析执行。

在这里采用的先 JS 编码后 HTML 编码中只弹窗了一次。

3.3 URL 解析器

通用 URI 的格式如下:

[协议名]://[用户名]:[密码]@[主机名]:[端口]/[路径]?[查询参数]#[片段 ID]

如何对浏览器解析和XSS的深度探究

URL 解析器也被建模为状态机,文档输入流中的字符可以将其导向不同的状态。

首先,要注意的是 URL 的 Scheme 部分(协议部分)必须为 ASCII 字符,即不能被任何编码,否则 URL 解析器的状态机将进入 No Scheme 状态。

示例1:

URL 编码部分的是javascript:alert(1)。

JS 不会被执行,因为作为Scheme 部分的"javascript"这个字符串被编码(其中javascript是一种伪协议),导致 URL 解析 器状态机进入 No Scheme 状态。

URL 中的:也不能被以任何方式编码,否则 URL 解析器的状态机也将进入 No Scheme 状态。

由于:被 URL 编码为%3a,导致 URL 状态机进入 NoScheme 状态,JS 代码不能执行。

示例2:

"javascript"这个字符串被实体化编码,:没有被编码,alert(2)被 URL编码。 成功执行 首先,在 HTML 解析器中我们谈到过,HTML状态机处于属性值状态(Attribute Value State)时,字符实体时会被解码的,此处在 href 属性中,所以被实体化编码的 "javascript"字符串会被解码。其次,HTML 解析是在URL解析之前的,所以在进行 URL 解析之前,Scheme 部分的"javascript"字符串已被解码,而并不再是被实体编码的状态。

四、解析顺序

首先浏览器接收到一个 HTML 文档时,会触发 HTML 解析器对 HTML 文档进行词法解析,这一过程完成 HTML 解码并创建 DOM 树。

接下来 JavaScript 解析器会介入对内联脚本进行解析,这一过程完成 JS 的解码工作。

如果浏览器遇到需要 URL 的上下文环境,这时 URL 解析器也会介入完成 URL 的解码工 作,URL 解析器的解码顺序会根据 URL 所在位置不同,可能在 JavaScript 解析器之前或之后解析。

总之HTML 解析总是第一步。URL 解析和 JavaScript 解析,它们的解析顺序要根据情况而定。

示例 1:

该例子中,首先由 HTML 解析器对UserInput 部分进行字符实体解码;

接着 URL 解析器对UserInput 进行 URL decode;

如果 URL 的 Scheme 部分为 javascript 的话,JavaScript 解析器会再对 UserInput 进行解 码。

所以解析顺序是:HTML 解析->URL解析->JavaScript 解析。

示例 2:

该例子中,首先由 HTML 解析器对UserInput 部分进行字符实体解码;

接着由 JavaScript 解析器会再对 onclick 部分的 JS 进行解析并执行 JS;

执行 JS 后window.open('UserInput')函数的参数会传入 URL,所以再由 URL 解析器对 UserInput 部分进行解码。

因此解析顺序为:HTML 解析->JavaScript解析->URL 解析。

示例 3:

该例子中,首先还是由 HTML 解析器对 UserInput 部分进行字符实体解码;

接着由 URL 解析器解析 href 的属性值;

然后由于Scheme为javascript,所以由 JavaScript 解析;

解析执行 JS 后window.open('UserInput')函数传入 URL,所以再由 URL 解析器解析。

所以解析顺序为:HTML 解析->URL解析->JavaScript 解析->URL 解析。

综合实例:

首先 HTML 解析器进行解析,解析到href 属性的值时,状态机进入属性值状态(Attribute Value State),该状态会解码字符实体;

接着由 URL 解析器进行解析并解码;

再接着由于 Scheme 为javascript,因此由 JavaScript 解析器解析并解码,加上编码部分是函 数名,属于标识符,因此可以正常解码解释;

经过三轮解析解码后得到结果:

关于如何对浏览器解析和XSS的深度探究就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。


本文题目:如何对浏览器解析和XSS的深度探究
转载来源:http://scjbc.cn/article/igioho.html

其他资讯