【问题标题】:Escaping HTML strings with jQuery使用 jQuery 转义 HTML 字符串
【发布时间】:2010-09-06 16:36:09
【问题描述】:

有谁知道从jQuery 中的字符串中转义 HTML 的简单方法?我需要能够传递任意字符串并将其正确转义以显示在 HTML 页面中(防止 JavaScript/HTML 注入攻击)。我确信可以扩展 jQuery 来做到这一点,但我目前对框架的了解还不够。

【问题讨论】:

标签: javascript jquery string escaping


【解决方案1】:

还有the solution from mustache.js

var entityMap = {
  '&': '&',
  '<': '&lt;',
  '>': '&gt;',
  '"': '&quot;',
  "'": '&#39;',
  '/': '&#x2F;',
  '`': '&#x60;',
  '=': '&#x3D;'
};

function escapeHtml (string) {
  return String(string).replace(/[&<>"'`=\/]/g, function (s) {
    return entityMap[s];
  });
}

【讨论】:

  • 很抱歉打扰了,但无论如何这可以逆转吗?我不知道正则表达式,所以我需要帮助
【解决方案2】:

由于您使用的是jQuery,因此您只需设置元素的text 属性:

// before:
// <div class="someClass">text</div>
var someHtmlString = "<script>alert('hi!');</script>";

// set a DIV's text:
$("div.someClass").text(someHtmlString);
// after: 
// <div class="someClass">&lt;script&gt;alert('hi!');&lt;/script&gt;</div>

// get the text in a string:
var escaped = $("<div>").text(someHtmlString).html();
// value: 
// &lt;script&gt;alert('hi!');&lt;/script&gt;

【讨论】:

  • 安全吗? linkedin.com/pulse/…
  • @paaacman 使用 jQuery 使用 .text().attr() 设置属性是安全的,但是像在该示例中那样构建 HTML 字符串肯定会遇到问题。
【解决方案3】:
$('<div/>').text('This is fun & stuff').html(); // "This is fun &amp; stuff"

来源:http://debuggable.com/posts/encode-html-entities-with-jquery:480f4dd6-13cc-4ce9-8071-4710cbdd56cb

【讨论】:

  • 如上述答案中所述,此解决方案不保证保留空白。
【解决方案4】:

如果您要转义 HTML,我认为只有三个是真正必要的:

html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");

根据您的用例,您可能还需要执行"&amp;quot; 之类的操作。如果列表足够大,我会使用一个数组:

var escaped = html;
var findReplace = [[/&/g, "&amp;"], [/</g, "&lt;"], [/>/g, "&gt;"], [/"/g, "&quot;"]]
for(var item in findReplace)
    escaped = escaped.replace(findReplace[item][0], findReplace[item][1]);

encodeURIComponent() 只会对 URL 进行转义,而不是 HTML。

【讨论】:

  • 如果相关的 HTML 已经转义了实体,这个正则表达式会产生奇怪的结果。例如,转义“Tom & Jerry”将产生“Tom &amp; Jerry”
  • 请使用var在本地声明item;无论如何,在遍历数组时根本不要使用for … in 循环!请改用普通的for 循环。哦,它是encodeURIComponent,而不是escapeURIComponent
  • 如果您使用标签属性,那么您还需要转义引号和/或双引号。 htmlspecialchars 的 PHP 文档包含一个有用的转换列表。 php.net/htmlspecialchars
  • 只是对新人的善意提醒,如果您打算在您的网站上的某处使用非英语字符,请不要使用它......显然这不会因为带有重音符号的字符,如 ' é' : &amp;eacute;这是一个html实体列表,供参考:w3schools.com/tags/ref_entities.asp
  • @Ryan:虽然值得指出的是,该解决方案不能正确处理已编码的字符串,但同样适用于本页上的大多数(可能是所有)解决方案也毫无价值。跨度>
【解决方案5】:

下划线很容易使用:

_.escape(string) 

Underscore 是一个实用库,提供了很多原生 js 不提供的功能。还有lodash,它与下划线的 API 相同,但经过重写以提高性能。

【讨论】:

  • 倒数是_.unescape(string)
【解决方案6】:

我写了一个很小的函数来做到这一点。它只会转义"&amp;&lt;&gt;(但通常这就是你所需要的)。它比早期提出的解决方案稍微优雅一些​​,因为它只使用 one .replace() 来完成所有转换。 (编辑 2:降低了代码复杂度,使函数变得更小更整洁,如果您对原始代码感到好奇,请参阅此答案的结尾。)

function escapeHtml(text) {
    'use strict';
    return text.replace(/[\"&<>]/g, function (a) {
        return { '"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;' }[a];
    });
}

这是纯 Javascript,没有使用 jQuery。

也转义 /'

编辑以回应mklement的评论。

上面的函数可以很容易地扩展为包含任何字符。要指定更多要转义的字符,只需将它们插入到正则表达式的字符类中(即在/[...]/g 内)和作为chr 对象中的条目。 (编辑 2: 也以同样的方式缩短了这个函数。)

function escapeHtml(text) {
    'use strict';
    return text.replace(/[\"&'\/<>]/g, function (a) {
        return {
            '"': '&quot;', '&': '&amp;', "'": '&#39;',
            '/': '&#47;',  '<': '&lt;',  '>': '&gt;'
        }[a];
    });
}

注意上面使用&amp;#39; 表示撇号(符号实体&amp;apos; 可能已被使用——它是在XML 中定义的,但最初并未包含在HTML 规范中,因此可能并非所有浏览器都支持. 见:Wikipedia article on HTML character encodings)。我还记得在某处读到使用十进制实体比使用十六进制更广泛地支持,但我现在似乎无法找到它的来源。 (而且不可能有很多浏览器不支持十六进制实体。)

注意:/' 添加到转义字符列表中并不是很有用,因为它们在 HTML 中没有任何特殊含义,也不需要 被转义。

escapeHtml函数

编辑 2: 原始函数使用变量 (chr) 来存储 .replace() 回调所需的对象。这个变量还需要一个额外的匿名函数来限定它,使函数(不必要地)更大更复杂。

var escapeHtml = (function () {
    'use strict';
    var chr = { '"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;' };
    return function (text) {
        return text.replace(/[\"&<>]/g, function (a) { return chr[a]; });
    };
}());

我还没有测试过这两个版本中哪个更快。如果您这样做,请随时在此处添加相关信息和链接。

【讨论】:

    【解决方案7】:

    我意识到我参加这个聚会有多晚了,但我有一个不需要 jQuery 的非常简单的解决方案。

    escaped = new Option(unescaped).innerHTML;
    

    编辑:这不会转义引号。唯一需要转义引号的情况是内容将被内联粘贴到 HTML 字符串中的属性。我很难想象这样做会是好的设计。

    编辑 3:对于最快的解决方案,请查看 Saram 的上述答案。这个是最短的。

    【讨论】:

      【解决方案8】:

      这是一个干净、清晰的 JavaScript 函数。它将诸如“一些

      function escapeHtmlEntities (str) {
        if (typeof jQuery !== 'undefined') {
          // Create an empty div to use as a container,
          // then put the raw text in and get the HTML
          // equivalent out.
          return jQuery('<div/>').text(str).html();
        }
      
        // No jQuery, so use string replace.
        return str
          .replace(/&/g, '&amp;')
          .replace(/>/g, '&gt;')
          .replace(/</g, '&lt;')
          .replace(/"/g, '&quot;')
          .replace(/'/g, '&apos;');
      }
      

      【讨论】:

        【解决方案9】:

        经过最后的测试,我可以推荐最快和完全跨浏览器兼容native javaScript(DOM)解决方案:

        function HTMLescape(html){
            return document.createElement('div')
                .appendChild(document.createTextNode(html))
                .parentNode
                .innerHTML
        }
        

        如果你重复多次,你可以用一次准备好的变量来做:

        //prepare variables
        var DOMtext = document.createTextNode("test");
        var DOMnative = document.createElement("span");
        DOMnative.appendChild(DOMtext);
        
        //main work for each case
        function HTMLescape(html){
          DOMtext.nodeValue = html;
          return DOMnative.innerHTML
        }
        

        看看我最后的表现comparison (stack question)。

        【讨论】:

        • 是否需要使用两个节点?一个怎么样:var p = document.createElement('p'); p.textContent = html; return p.innerHTML;
        • @DanDascalescu:根据MDN的说法,textContent功能仅支持Chrome 1+、Firefox 2、IE9、Opera 9.64和Safari 3(后两者注释为“可能更早”) .因此,它将打破 OP“完全跨浏览器兼容”的主张。
        • p.innerText = html; return p.innerHTML
        【解决方案10】:

        试试Underscore.string lib,它适用于 jQuery。

        _.str.escapeHTML('<div>Blah blah blah</div>')
        

        输出:

        '&lt;div&gt;Blah blah blah&lt;/div&gt;'
        

        【讨论】:

        • 主下划线库现在有一个_.escape() 实用函数。
        【解决方案11】:

        escape()unescape() 旨在编码/解码 URL 的字符串,而不是 HTML。

        其实我是用下面的sn-p来做这个不需要任何框架的:

        var escapedHtml = html.replace(/&/g, '&amp;')
                              .replace(/>/g, '&gt;')
                              .replace(/</g, '&lt;')
                              .replace(/"/g, '&quot;')
                              .replace(/'/g, '&apos;');
        

        【讨论】:

        • 如果您要使用"s,那么您至少需要添加' 和`` 来加入战斗。这些只是 html 元素中的字符串标签数据真正需要的。对于 html 数据本身(外部标签),只需要前 3 个。
        【解决方案12】:

        我增强了 mustache.js 示例,将 escapeHTML() 方法添加到字符串对象。

        var __entityMap = {
            "&": "&amp;",
            "<": "&lt;",
            ">": "&gt;",
            '"': '&quot;',
            "'": '&#39;',
            "/": '&#x2F;'
        };
        
        String.prototype.escapeHTML = function() {
            return String(this).replace(/[&<>"'\/]/g, function (s) {
                return __entityMap[s];
            });
        }
        

        这样就很容易使用"Some &lt;text&gt;, more Text&amp;Text".escapeHTML()

        【讨论】:

        • 有用,但我也将 __entityMap 移到函数本地范围内。并将所有这些包装到if (typeof String.prototype.escapeHTML !== 'function'){...}
        【解决方案13】:

        如果你有underscore.js,使用_.escape(比上面贴的jQuery方法更高效):

        _.escape('Curly, Larry & Moe'); // returns: Curly, Larry &amp; Moe
        

        【讨论】:

          【解决方案14】:

          如果您要走正则表达式路线,则上面的 tghw 示例中存在错误。

          <!-- WON'T WORK -  item[0] is an index, not an item -->
          
          var escaped = html; 
          var findReplace = [[/&/g, "&amp;"], [/</g, "&lt;"], [/>/g,"&gt;"], [/"/g,
          "&quot;"]]
          
          for(var item in findReplace) {
               escaped = escaped.replace(item[0], item[1]);   
          }
          
          
          <!-- WORKS - findReplace[item[]] correctly references contents -->
          
          var escaped = html;
          var findReplace = [[/&/g, "&amp;"], [/</g, "&lt;"], [/>/g, "&gt;"], [/"/g, "&quot;"]]
          
          for(var item in findReplace) {
               escaped = escaped.replace(findReplace[item[0]], findReplace[item[1]]);
          }
          

          【讨论】:

          • 我认为应该是 for(var item in findReplace) { escaped = escaped.replace(findReplace[item][0], findReplace[item][1]); }
          【解决方案15】:

          这是一个很好的安全示例...

          function escapeHtml(str) {
              if (typeof(str) == "string"){
                  try{
                      var newStr = "";
                      var nextCode = 0;
                      for (var i = 0;i < str.length;i++){
                          nextCode = str.charCodeAt(i);
                          if (nextCode > 0 && nextCode < 128){
                              newStr += "&#"+nextCode+";";
                          }
                          else{
                              newStr += "?";
                          }
                       }
                       return newStr;
                  }
                  catch(err){
                  }
              }
              else{
                  return str;
              }
          }
          

          【讨论】:

          • 你在那里抑制了哪些类型的异常?
          【解决方案16】:

          您可以使用 vanilla js 轻松完成。

          只需在文档中添加一个文本节点。 它会被浏览器转义。

          var escaped = document.createTextNode("<HTML TO/ESCAPE/>")
          document.getElementById("[PARENT_NODE]").appendChild(escaped)
          

          【讨论】:

            【解决方案17】:

            2 个不需要 JQUERY 的简单方法...

            您可以像这样编码字符串中的所有字符

            function encode(e){return e.replace(/[^]/g,function(e){return"&#"+e.charCodeAt(0)+";"})}
            

            或者只是瞄准主角来担心&amp;、换行符、&lt;&gt;"'之类的:

            function encode(r){
            return r.replace(/[\x26\x0A\<>'"]/g,function(r){return"&#"+r.charCodeAt(0)+";"})
            }
            
            var myString='Encode HTML entities!\n"Safe" escape <script></'+'script> & other tags!';
            
            test.value=encode(myString);
            
            testing.innerHTML=encode(myString);
            
            /*************
            * \x26 is &ampersand (it has to be first),
            * \x0A is newline,
            *************/
            <p><b>What JavaScript Generated:</b></p>
            
            <textarea id=test rows="3" cols="55"></textarea>
            
            <p><b>What It Renders Too In HTML:</b></p>
            
            <div id="testing">www.WHAK.com</div>

            【讨论】:

              【解决方案18】:
              (function(undefined){
                  var charsToReplace = {
                      '&': '&amp;',
                      '<': '&lt;',
                      '>': '&gt;'
                  };
              
                  var replaceReg = new RegExp("[" + Object.keys(charsToReplace).join("") + "]", "g");
                  var replaceFn = function(tag){ return charsToReplace[tag] || tag; };
              
                  var replaceRegF = function(replaceMap) {
                      return (new RegExp("[" + Object.keys(charsToReplace).concat(Object.keys(replaceMap)).join("") + "]", "gi"));
                  };
                  var replaceFnF = function(replaceMap) {
                      return function(tag){ return replaceMap[tag] || charsToReplace[tag] || tag; };
                  };
              
                  String.prototype.htmlEscape = function(replaceMap) {
                      if (replaceMap === undefined) return this.replace(replaceReg, replaceFn);
                      return this.replace(replaceRegF(replaceMap), replaceFnF(replaceMap));
                  };
              })();
              

              没有全局变量,一些内存优化。 用法:

              "some<tag>and&symbol©".htmlEscape({'©': '&copy;'})
              

              结果是:

              "some&lt;tag&gt;and&amp;symbol&copy;"
              

              【讨论】:

                【解决方案19】:

                纯 JavaScript 转义示例:

                function escapeHtml(text) {
                    var div = document.createElement('div');
                    div.innerText = text;
                    return div.innerHTML;
                }
                
                escapeHtml("<script>alert('hi!');</script>")
                // "&lt;script&gt;alert('hi!');&lt;/script&gt;"
                

                【讨论】:

                • 不鼓励仅使用代码的答案,因为它们没有说明如何解决问题。请更新您的答案以解释 这如何改进其他已接受和赞成的答案这个问题已经有。此外,这个问题已有 9 年历史,最近有未回答问题的用户会更加感谢您的努力。请查看How do I write a good answer
                • @FluffyKitten 这是一篇写得很好的博客文章,介绍了此类功能的优缺点,详细解释了您想知道的一切:) shebang.brandonmintern.com/…
                • @db306 答案被标记为低质量,因为纯代码答案不符合 Stack Overflow 准则 - 请参阅 How to write a good answer。我的评论是在审查过程中添加的,以解释改进它所需的内容,即需要更新答案以解释代码的作用以及它如何改进现有答案。其他评论者对此表示赞同。向 cmets 添加外部链接仍然不符合 SO 准则。相反,安德鲁需要在他的回答中直接包含相关信息。
                • 请注意,brandonmintern DOT com 已过期,现在已停放。新的shebang地址是shebang.mintern.net/foolproof-html-escaping-in-javascript/。
                【解决方案20】:

                ES6 一班solution from mustache.js

                const escapeHTML = str => (str+'').replace(/[&<>"'`=\/]/g, s => ({'&': '&amp;','<': '&lt;','>': '&gt;','"': '&quot;',"'": '&#39;','/': '&#x2F;','`': '&#x60;','=': '&#x3D;'})[s]);
                

                【讨论】:

                  【解决方案21】:
                  function htmlEscape(str) {
                      var stringval="";
                      $.each(str, function (i, element) {
                          alert(element);
                          stringval += element
                              .replace(/&/g, '&amp;')
                              .replace(/"/g, '&quot;')
                              .replace(/'/g, '&#39;')
                              .replace(/</g, '&lt;')
                              .replace(/>/g, '&gt;')
                              .replace(' ', '-')
                              .replace('?', '-')
                              .replace(':', '-')
                              .replace('|', '-')
                              .replace('.', '-');
                      });
                      alert(stringval);
                      return String(stringval);
                  }
                  

                  【讨论】:

                    【解决方案22】:
                    function htmlDecode(t){
                       if (t) return $('<div />').html(t).text();
                    }
                    

                    像魅力一样工作

                    【讨论】:

                    • text 去掉 html 标签,但是 $('
                      ').html(t).html();作品
                    【解决方案23】:

                    速度优化版本:

                    function escapeHtml(s) {
                       let out = "";
                       let p2 = 0;
                       for (let p = 0; p < s.length; p++) {
                          let r;
                          switch (s.charCodeAt(p)) {
                             case 34: r = "&quot;"; break;  // "
                             case 38: r = "&amp;" ; break;  // &
                             case 39: r = "&#39;" ; break;  // '
                             case 60: r = '&lt;'  ; break;  // <
                             case 62: r = '&gt;'  ; break;  // >
                             default: continue;
                          }
                          if (p2 < p) {
                             out += s.substring(p2, p);
                          }
                          out += r;
                          p2 = p + 1;
                       }
                       if (p2 == 0) {
                          return s;
                       }
                       if (p2 < s.length) {
                          out += s.substring(p2);
                       }
                       return out;
                    }
                    
                    const s = "Hello <World>!";
                    document.write(escapeHtml(s));
                    console.log(escapeHtml(s));

                    【讨论】:

                      【解决方案24】:

                      用于转义 html 特价商品 (UTF-8)

                      function htmlEscape(str) {
                        return str
                            .replace(/&/g, '&amp;')
                            .replace(/"/g, '&quot;')
                            .replace(/'/g, '&#39;')
                            .replace(/</g, '&lt;')
                            .replace(/>/g, '&gt;')
                            .replace(/\//g, '&#x2F;')
                            .replace(/=/g,  '&#x3D;')
                            .replace(/`/g, '&#x60;');
                      }
                      

                      对于 unescape html specials (UTF-8)

                      function htmlUnescape(str) {
                        return str
                            .replace(/&amp;/g, '&')
                            .replace(/&quot;/g, '"')
                            .replace(/&#39;/g, "'")
                            .replace(/&lt;/g, '<')
                            .replace(/&gt;/g, '>')
                            .replace(/&#x2F/g, '/')
                            .replace(/&#x3D;/g, '=')
                            .replace(/&#x60;/g, '`');
                      }
                      

                      【讨论】:

                        【解决方案25】:

                        如果您将此信息保存在数据库中,使用客户端脚本转义HTML是错误的,这应该在服务器。否则很容易绕过你的 XSS 保护。

                        为了说明我的观点,这里是一个使用其中一个答案的例子:

                        假设您正在使用函数 escapeHtml 从博客中的评论中转义 Html,然后将其发布到您的服务器。

                        var entityMap = {
                            "&": "&amp;",
                            "<": "&lt;",
                            ">": "&gt;",
                            '"': '&quot;',
                            "'": '&#39;',
                            "/": '&#x2F;'
                          };
                        
                          function escapeHtml(string) {
                            return String(string).replace(/[&<>"'\/]/g, function (s) {
                              return entityMap[s];
                            });
                          }
                        

                        用户可以:

                        • 编辑 POST 请求参数并将注释替换为 javascript 代码。
                        • 使用浏览器控制台覆盖 escapeHtml 函数。

                        如果用户将此 sn-p 粘贴到控制台中,它将绕过 XSS 验证:

                        function escapeHtml(string){
                           return string
                        }
                        

                        【讨论】:

                        • 我不同意。要绕过这种 XSS 保护,您必须使用 XSS 攻击(注入禁用转义的脚本),这就是您实际阻止的。在某些情况下,在客户端转义实际上更合适,例如,如果数据来自必须返回标准 JSON 的 REST API。
                        • @Qualcuno 如果您在客户端执行此验证并将此信息发布到服务器并相信它已验证,则用户可以简单地编辑请求,脚本将保存在数据库中。
                        • @Qualcuno 我举了一些例子来说明我的观点。
                        • 问题是关于转义从服务器接收到的字符串以在浏览器上显示它们。您所说的是在将字符串提交到服务器之前对其进行转义,这是另一回事(尽管您是对的,但它又回到了旧规则永远不要盲目地接受来自客户端的任何输入 i>)
                        • @Qualcuno 这是 Stackoverflow 中的一个热门问题,我相信这是一个需要讨论的重点。这就是我回答的原因。
                        【解决方案26】:

                        This answer 提供了 jQuery 和普通的 JS 方法,但是不使用 DOM 是最短的:

                        unescape(escape("It's > 20% less complicated this way."))
                        

                        转义字符串:It%27s%20%3E%2020%25%20less%20complicated%20this%20way.

                        如果转义的空格困扰您,请尝试:

                        unescape(escape("It's > 20% less complicated this way.").replace(/%20/g, " "))
                        

                        转义字符串:It%27s %3E 20%25 less complicated this way.

                        不幸的是,escape() 函数是 deprecated in JavaScript version 1.5encodeURI()encodeURIComponent() 是替代品,但它们忽略了',所以最后一行代码会变成这样:

                        decodeURI(encodeURI("It's > 20% less complicated this way.").replace(/%20/g, " ").replace("'", '%27'))
                        

                        所有主流浏览器仍然支持短代码,考虑到旧网站的数量,我怀疑这种情况很快就会改变。

                        【讨论】:

                        • 这是用于 URL 编码的。问题是关于 HTML 转义,这是非常不同的。
                        • @thelem,如果字符串嵌入在 HTML 中嵌入的 JavaScript 数组中,则不是,但我同意这是关于纯 HTML 转义,因此可以立即显示为文本。
                        【解决方案27】:

                        如果您不防止重新逃逸,所有解决方案都是无用的,例如大多数解决方案都会将&amp;amp; 转义为&amp;amp;

                        escapeHtml = function (s) {
                            return s ? s.replace(
                                /[&<>'"]/g,
                                function (c, offset, str) {
                                    if (c === "&") {
                                        var substr = str.substring(offset, offset + 6);
                                        if (/&(amp|lt|gt|apos|quot);/.test(substr)) {
                                            // already escaped, do not re-escape
                                            return c;
                                        }
                                    }
                                    return "&" + {
                                        "&": "amp",
                                        "<": "lt",
                                        ">": "gt",
                                        "'": "apos",
                                        '"': "quot"
                                    }[c] + ";";
                                }
                            ) : "";
                        };
                        

                        【讨论】:

                        • 这称为双重转义,应该通过确保您的输入数据尚未转义来解决。如果你想从字面上显示 <给用户?或者也许文本将在其他地方重用,并且取决于发生的转义?
                        猜你喜欢
                        • 2012-05-27
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多