zoukankan      html  css  js  c++  java
  • 浏览器的解码与编码

    2020_04_17

    作为一个浏览器,有三个引擎

    1、URL解析引擎

    2、HTML解析引擎

    3、JS 解析引擎

    首先来讲URL解析引擎

    这里拿PHP代码做例子:

    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    </head>
    <body>
    <a href="javascript:alert('<?php echo $_GET['input'];?>');">test</a>
    </body>
    </html>
    

    input=%26lt%5cu4e00%26gt

    该值构造在URL里,浏览器直接发送给服务器,服务器接收之后,先进行一次URL解析,input 内容变成了&ltu4e00&gt,所以对于浏览器从服务器端获取的页面数据来说,此时test对应的标签变成了如下:

    <a href="javascript:alert('&ltu4e00&gt');">test</a>

    这里需要说的是,URL编码/解码在http请求是肯定会发生的,该编码只是为了在http请求中保证数据的传输不会丢失

    接着就开始了HTML 解析

    在HTML解析中,HTML解析器会根据HTML内容来构建DOM树,需要知道在解析的过程中,HTML的解析器只能识别特定的词法规则,才能构建起DOM 树,这一块,HTML不会做解码的工作!

    所以比如:<img src&#x3d;"http://www.example.com"> 中,HTML解析器在构造DOM树的时候首先会匹配<img,然后继续走匹配相应的>,在解析的过程中,HTML解析器只能识别特定的词法规则,所以遇到src&#x3d它是无法识别的,所以这里只是一个单纯的img标签,不存在危险!

    当HTML解析器构建DOM树之后,节点内容就会被开始实体解码,比如上方的&lt &gt,这两个符号被识别为HTML编码,那么就会被解析为<>

    到这里的时候该标签的结果为<a href="javascript:alert('<u4e00>')">test</a>

    这时候JS 解释器 开始进行了

    浏览器为了让不同的解析器来工作处理不同的内容,实际上,在遇到比如<script>,<style> 这样的标签,解析器会自动切换到js解析模式,而src,href等属性后边加入的JavaScript伪URL,也会进入JS的解析模式。而进入该解析模式的时候,该DOM节点已经建立起来了,也就是HTML解析器已经最少解析到这个地方了

    此时<a href="javascript:alert('<u4e00>')">test</a>

    javascript开启JS 解释器,JS会先对内容进行解析,里边有一个转义字符u4e00,前导的 u 表示他是一个Unicode 字符,根据后边的数字,解析为'一',将会被解析为<a href="javascript:alert('<一>')">test</a>

    然后JS 解释器执行alert("<一>"),这句话会交给浏览器渲染,最终弹窗。

    unicode编码还可以在alert函数上使用,比如:<a href="javascript:u0061lert('<一>')">test</a>

    需要注意的是:上边这种直接在字符串外进行专一的方式,只有 Unicode编码方式支持,其他编码方式不支持!

    在一个页面中,可以出发JS 解析器的方式有这么几种

    1、直接嵌入 代码块,比如<script>alert(1);</script>

    2、通过< script src=xxx > 加载代码,比如<script src="javascript:alert(1);"></script>,自己测试失败,猜测旧版本的浏览器应该支持!

    3、各种HTML CSS 参数支持JavaScript:URL 触发调用,自己测试失败!

    4、CSS expression(…) 语法和某些浏览器的XBL绑定,比如<img style="xss:expression(alert(/xss/))" />,自己测试失败!

    5、事件处理器(Event handlers),比如 onload, onerror, onclick等,比如<img/src=x onerror=alert(1)>

    6、定时器,Timer(setTimeout, setInterval),比如<img src=x onerror='setTimeout("ale"+"rt(1)",0)' />

    7、eval(…) 调用,比如eval("<script>alert(1);</script>");

    到这里的话,基本的解析顺序就是 URL 解析器 -> HTML 解析器 -> JS解析器

    继续看下面的例子:

    <p id="1">hello</p>
    <script>document.getElementById("1").innerHTML = "<img src=# onu0065rror=alert(1)>";</script>
    

    这里的解析过程就不一样的,过程为:

    1、HTML解析器构造DOM树p标签

    2、然后碰到<script>标签了,于是HTML解析器就会停下来,让js解析器开始,进行脚本的执行,遇到onu0065rror先会进行解码为onerror,那么它会执行script标签中的内容,实现重构当前的HTML代码,也就是在id为1的元素下的内容修改为<img src=# onerror=alert(1)>

    3、现在的结果就为如下:

    <p id="1"><img src="#" onerror="alert(1)"></p>
    

    4、HTML解析器发现前面有变化,那么就会来到开头,重新进行解析,继续先构建DOM树,发现onerror事件,则js解析器开始执行,先进行解码操作,然后进行alert(1),HTML解析器继续执行,执行最后结束

    那么思考下<img src=# onrror=alert(1)>,如果在onerror的内容中进行HTML编码结果是如何呢?

    比如<script>document.getElementById("1").innerHTML = "<img src=# onu0065rror=alert&#40;1)>";</script>

    不同的地方就是,JS第一次执行了之后结果为如下:
    <p id="1"><img src=# onerror=alert&#40;1)>";</script>

    此时需要使用HTML解析重塑DOM树,那么节点内容中的实体编码就会被解码,然后onerror中触发脚本,JS又会内容进行一次解析,最终alert(1)

    这里与上面不同的只是,HTML解析器重构DOM树的时候,会先对节点的内容HTML解码,然后继续JS,其实就是会先比JS执行快一些吧!

    不知道这样理解对不对,如果有老哥看到这篇文章有问题的话 希望能提出来!

    最后再去了解下大家说的xss有时候说被HTML实体编码了是什么意思?

    首先这里用的PHP代码如下:

    <?php echo htmlspecialchars($_GET['input']);?>
    

    input=<script>

    看下源代码:&lt;script&gt;

    解析过程:

    1、HTML解析器尝试去构建DOM树,但是什么都匹配不了,所以无DOM树,此时的结果还是&lt;script&gt;

    2、发现有HTML实体编码,尝试去进行HTML解码,解码完之后的结果<script>,最后在页面显示

    这里同样在页面上显示相同的内容,但是htmlspecialchars的原因,防止了XSS的产生

    再来看<input type="text" value="<?php echo htmlspecialchars($_GET['input']);?>" />,这段代码是否能够进行绕过?

    自己来看是无解的,因为被实体编码了

    如果开发者用单引号包裹的话,那么是可以进行绕过的,因为htmlspecialchars默认不转义单引号,quotestyle选项为ENT_QUOTES才会过滤单引号

    <input type='text' value='<?php echo htmlspecialchars($_GET['input'])?>'>

    此时payload:' autofocus=autofocus onfocus=alert(1)//可以进行绕过

    参考文章:http://taligarsiel.com/Projects/howbrowserswork1.htm
    参考文章:http://xuelinf.github.io/2016/05/18/编码与解码-浏览器做了什么/

  • 相关阅读:
    git拉取代码命令
    zookeeper(version3.6.3)安装使用《一》
    kafka(version2.1.3)安装<一>
    linux安装jdk
    linux安装支持文件上传下载的命令
    mapstruct 再也不用set不同的属性而劳累了
    RabbitMq确认消费,与重复消费避免使用冥等
    java8之非重入锁StampedLock ,并发的另一种处理方式
    微信Jssdk
    Vue-Router 的params和query传参两种方式
  • 原文地址:https://www.cnblogs.com/zpchcbd/p/12514661.html
Copyright © 2011-2022 走看看