HTML 与 javascript 自解码机制

作者: 我是奋斗哥 | 来源:发表于2017-01-09 05:13 被阅读283次

    关于这个自解码机制,我们直接以一个例子(样例0)来进行说明:

    <input type="button" id="exec_btn" value="exec" onclick="document.write ('<img src=@ onerror=alert(123) />')" />
    

    我们假设document.write里的值是用户可控的输入,点击后,document.write出现一段 img HTMLonerror里的 JavaScript 会执行。此时陷阱来了,我们现在提供一段HtmlEncode函数如下(样例A):

    <script>
    
    function HtmlEncode(str) {
    
        var s = "";
    
        if (str.length == 0) return "";
    
        s = str.replace(/&/g, "&");
    
        s = s.replace(/</g, "<");
    
        s = s.replace(/>/g, ">");
    
        s = s.replace(/\"/g, """);
    
        return s;
    
    }
    
    </script>
    
    <input type="button" id="exec_btn" value="exec" onclick="document.write (HtmlEncode('<img src=@ onerror=alert(123) />'))" />
    

    我们知道HtmlEncode('<img src=@ onerror=alert(123) />')后的结果是:

    <img src=@ onerror=alert(123) />

    这个样例 A 点击后会执行 alert(123) 吗?下面这个呢(样例 B)?

    <input type="button" id="exec_btn" value="exec" onclick="document.write ('<img src=@ onerror=alert(123) />')" />
    

    在样例 A 和样例 B 中,document.write 的值似乎是一样的?实际结果是样例 A 点击不会执行 alert(123),而是在页面上完整地输出<img src=@ onerror=alert(123) />,而样例 B 点击后会执行alert(123)

    我们要告诉大家的是,点击样例B时,document.write的值实际上不再是:<img src=@ onerror=alert(123) />

    而是:
    <img src=@ onerror=alert(123) />

    我们可以这样论证:

    <input type="button" id="exec_btn" value="exec" onclick="x='<img src=@ onerror=alert(123) />';alert(x);document.write(x)" />
    

    看弹出的x值就知道了,如下图所示。

    proof

    出现这个结果的原因如下:

    onclick里的这段 JavaScript 出现在 HTML 标签内,意味着这里的JavaScript 可以进行 HTML 形式的编码,这种编码有以下两种。

    1. 进制编码:&#xH;(十六进制格式)、&#D;(十进制格式),最后的分号(;)可以不要。
    2. HTML 实体编码:即上面的那个 HtmlEncode

    在 JavaScript 执行之前,HTML 形式的编码会自动解码。所以样例 0 与样例 B 的意义是一样的,而样例 A 就不一样了。下面我们继续完善这些例子。

    上面的用户输入是出现在 HTML 里的情况,如果用户输入出现在<script>里的 JavaScript 中,情况会怎样,代码如下:

    <input type="button" id="exec_btn" value="exec" />
    <script>
    function $(id){return document.getElementById(id);};
    $('exec_btn').onclick = function(){
          document.write("<img src=@ onerror=alert(123) />");
          //document.write("<img src=@ onerror=alert(123) />");
    };
    </script>
    

    这样是可以执行alert(123)的,如果用户输入的是下面的内容:
    <img src=@ onerror=alert(123) />

    结果与样例 B 一样:这段 HTML 编码的内容在 JavaScript 执行之前自动解码吗?答案是不会,原因是用户输入的这段内容上下文环境是 JavaScript,不是HTML(可以认为<script>标签里的内容和 HTML 环境毫无关系),此时用户输入的这段内容要遵守的是 JavaScript 法则,即 JavaScript 编码,具体有如下几种形式。

    1. Unicode 形式:\uH (十六进制)。
    2. 普通十六进制:\xH
    3. 纯转义:** ' " < > **这样在特殊字符之前加 ** \ ** 进行转义。

    比如,用户输入被转义成如下形式:
    \<img src\=@ onerror=alert\(123\) \/\>

    在 JavaScript 执行之前,这样的转义会自动去转义,alert(123) 照样执行。同样,下面这样的 JavaScript 编码也毫无意义:

    <img src=@ onerror=alert(123) />
    -->
    \u003c\u0069\u006d\u0067\u0020\u0073\u0072\u0063\u003d\u0040\u0020\u006f\u006e\u0065\u0072\u0072\u006f\u0072\u003d\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0032\u0033\u0029\u0020\u002f\u003e
    
    \x3c\x69\x6d\x67\x20\x73\x72\x63\x3d\x40\x20\x6f\x6e\x65\x72\x72\x6f\x72\x3d\x61\x6c\x65\x72\x74\x28\x31\x32\x33\x29\x20\x2f\x3e
    

    在 JavaScript 执行之前,这样的编码会自动解码。

    通过这几个样例,我们可以知道在 HTML 中与在 JavaScript 中自动解码的差异。

    参考《Web 前端黑客技术揭秘》

    相关文章

      网友评论

        本文标题:HTML 与 javascript 自解码机制

        本文链接:https://www.haomeiwen.com/subject/zkvcbttx.html