字符编码及浏览器解析原理

admin 2023年10月7日14:18:50评论22 views字数 4687阅读15分37秒阅读模式

浏览器在解析HTML文档时无论按照什么顺序,主要有三个过程:HTML解析、js解析和url解析,每个解析器负责HTML文档中各自对应部分的解析工作。

 

首先浏览器接收到一个HTML文档时,会触发HTML解析器对HTML文档进行词法解析,这一过程完成HTML解码并创建DOM树,接下来JavaScript解析器会介入对内联脚本进行解析,这一过程完成JS的解码工作,如果浏览器遇到需要URL的上下文环境,这时URL解析器也会介入完成URL的解码工作,URL解析器的解码顺序会根据URL所在位置不同,可能在JavaScript解析器之前或之后解析。

字符编码及浏览器解析原理


基本概念:

HTML字符实体

在呈现HTML页面时,针对某些特殊字符如<>直接使用,浏览器会误以为它们标签的开始或结束,若想正确的在HTML页面呈现特殊字符就需要用到其对应的字符实体。


字符实体是一个预先定义好的转义序列,它定义了一些无法在文本内容中输入的字符或符号。字符实体以&开头+预先定义的实体名称,以分号结束,如"<"的实体名称为&lt;或以&开头+#符号以及字符的十进制数字,如:"<"的实体编号为&#60;字符都是有实体编号的但有些字符没有实体名称。


JavaScript编码

最常见的如"uxxxx"这种写法为Unicode转义序列,表示一个字符,其中xxxx表示一个16进制数字,如"<"Unicode编码为"u003c"

    会触发JavaScript解析器的地方:

  • 直接嵌入<script>代码块

  • 通过<script sr=…>加载代码

  • 各种HTML CSS参数支持JavaScript:URL触发调用

  • CSS expression(…)语法和某些浏览器的XBL绑定

  • 事件处理器(Event handlers),比如onload、onerror、onclick

  • 定时器,Timer(setTimeout, setInterval)

  • eval(…)调用

    比如定时器:

    <script>

    var value = "user_string";

    ...

    setTimeout("do_stuff('"+value+"')", 1000);

    </script>

检查setTimeout语法,等到1秒之后,才会解析do_stuff如果不多做一个转义,就有可能构造成一次注入,比如user_string中插入一个JavaScript编码的构造,截断前边函数,然后构造自己的攻击部分。


实际上,dom操作是js强势介入HTMLCSS的结果,使用dom操作,对dom tree造成了改变,会调用到HTML解析器重新对其解析。


URL解码

%加字符的ASCII编码对应的216进制数字,如"/"对应的URL编码为%2f



深入理解

下面我们结合具体事例来讨论下浏览器的解析原理过程和xss复合编码的一些内容:

第一个a标签:
<a href="javascript:alert(1)">test</a>

针对上述a标签我们分析一下该环境中浏览器的解析顺序,首先HTML解析器开始工作,并对href中的字符做HTML解码,接下来URL解析器对href值进行解码,正常情况下url值为一个正常的url链接,如“https://www.test.com”,那么url解析器工作完成后是不需要其他解码的,但是该环境中url资源类型为JavaScript,因此该环境中最后一步JavaScript解析器还会进行解码操作,最后解析的脚本被执行。


整个解析顺序为3个环节:HTML解码-->URL解码-->js解码

我们对href值做一些编码转换,思考会不会执行xss


  • url编码"javascript:alert(1)"

%6A%61%76%61%73%63%72%69%70%74:%61%6C%65%72%74%28%31%29

字符编码及浏览器解析原理不能执行,url解析过程中有一个细节,不能对协议类型进行任何编码操作,否则url解析器会认为它无类型,冒号也是协议的一部分。这就会导致被编码的"javascript"没有解码,当然不会被url解析器识别了。


  • HTML字符实体编码"javascript"url编码"alert(2)"

HTML编码:

"javascript"="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;"

URL编码:

"alert(2)"=” %61%6C%65%72%74%28%32%29”

字符编码及浏览器解析原理可以执行。因为"javascript"是做的HTML实体编码,HTML解析器工作时,href中的HTML实体就会被解码,接下来url解析器工作解析href属性里的链接时,"javascript"协议在第一步被HTML解码了,这样url解析器是可以识别的,继续解析后面的" %61%6C%65%72%74%28%32%29",最后JavaScript解析器完成解析操作,脚本执行。

 

  • <a href="javascript:alert(3)">test3</a>js编码-->url编码-->HTML编码共3层。

JS编码:

<a href="javascript:u0061u006cu0065u0072u0074(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="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#37;&#53;&#99;&#37;&#55;&#53;&#37;&#51;&#48;&#37;&#51;&#48;&#37;&#51;&#54;&#37;&#51;&#49;&#37;&#53;&#99;&#37;&#55;&#53;&#37;&#51;&#48;&#37;&#51;&#48;&#37;&#51;&#54;&#37;&#54;&#51;&#37;&#53;&#99;&#37;&#55;&#53;&#37;&#51;&#48;&#37;&#51;&#48;&#37;&#51;&#54;&#37;&#51;&#53;&#37;&#53;&#99;&#37;&#55;&#53;&#37;&#51;&#48;&#37;&#51;&#48;&#37;&#51;&#55;&#37;&#51;&#50;&#37;&#53;&#99;&#37;&#55;&#53;&#37;&#51;&#48;&#37;&#51;&#48;&#37;&#51;&#55;&#37;&#51;&#52;&#40;&#51;&#41;">test3</a>

 

可以执行。

 

第二个img标签:

<img src=x onclick="{$value}">

代码如下:

<img src=x onclick="&#92;&#117;&#48;&#48;&#54;&#49;&#92;&#117;&#48;&#48;&#54;&#99;&#92;&#117;&#48;&#48;&#54;&#53;&#92;&#117;&#48;&#48;&#55;&#50;&#92;&#117;&#48;&#48;&#55;&#52;&#40;&#39;&#49;&#39;&#41;">

字符编码及浏览器解析原理

假设onclick属性为用户可控数据:

首先传入的“用户可控”数据处在HTML环境中,然后是onclick环境中,因此浏览器的解析顺序为:HTML解码-->js解码

    HTML解码:

    u0061u006cu0065u0072u0074('1')

    js解码:alert('1')

解析完成,脚本执行。注意像圆括号、双引号、单引号等这些控制字符,在进行JavaScript解析的时候仅会被解码为字符串文本。正常的xss防御应该要对这些控制字符进行Unicode编码。


测试一下DOM的环境,测试代码如下:

    <div id='s'>test</div>

    <script>

    var s = "<img/src=x onerror=alert(1)>";

    document.getElementById('s').innerHTML = s;

    </script>

<img/src=x onerror=alert(1)>的以下编码都可以弹窗:

Unicode编码:

u003Cu0069u006Du0067u002Fu0073u0072u0063u003Du0078u0020u006Fu006Eu0065u0072u0072u006Fu0072u003Du0061u006Cu0065u0072u0074u0028u0031u0029u003E

字符编码及浏览器解析原理

八进制编码:

741511551475716316214375170401571561451621621571627514115414516216450615176

十六进制编码:

x3Cx69x6Dx67x2Fx73x72x63x3Dx78x20x6Fx6Ex65x72x72x6Fx72x3Dx61x6Cx65x72x74x28x31x29x3E

JS事件中使用Location跳转也可以,例如:

<input onfocus=location="javascript:alertu0028u0027teeestu0027u0029" autofocus>

 

场景:

假设alert中的值为用户可控数据,服务端防御xss做了HTML编码。


用户输入的");alert("1,在服务端HTML实体编码之后返回到前端被浏览器解析执行。

&quot;&#41;&#59;&#97;&#108;&#101;&#114;&#116;&#40;&quot;&#49;

字符编码及浏览器解析原理选中部分为用户可控数据。

JavaScript解析时,就变成了alert("test");alert("1")故能正常执行。

故只做HTML防护是不够的,调整防御策略为:js编码-->HTML编码

因为前面说过js解析时会把控制字符解析为字符串文本,无法发挥正常作用。


这仅仅只是一个案例,实际生产环境中需要更多更全面的防御。

 

推荐这两个网址,巩固一下学习的内容哦:

http://test.attacker-domain.com/browserparsing/tests.html

http://test.attacker-domain.com/browserparsing/answers.txt


参考链接:

http://xuelinf.github.io/2016/05/18/%E7%BC%96%E7%A0%81%E4%B8%8E%E8%A7%A3%E7%A0%81-%E6%B5%8F%E8%A7%88%E5%99%A8%E5%81%9A%E4%BA%86%E4%BB%80%E4%B9%88/

https://security.yirendai.com/news/share/26

https://xz.aliyun.com/t/5863

https://www.yuque.com/kkdlong/eiwne5/fpl8ob?language=en-us


原文始发于微信公众号(Medi0cr1ty):字符编码及浏览器解析原理

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年10月7日14:18:50
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   字符编码及浏览器解析原理http://cn-sec.com/archives/1983726.html

发表评论

匿名网友 填写信息