使用jQuery转义HTML字符串

Pag*_*age 593 javascript string jquery escaping

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

Tom*_*ner 584

还有来自mustache.js的解决方案

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

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

  • 这应该是公认的答案 - 它简单,高效,不需要依赖,并且完全没有模糊的黑客攻击. (42认同)
  • @amwinter,我在上面扩展了脚本,将"\n":'<br>'添加到实体地图,并将正则表达式更新为/ [&<>"'\ /] | [\n]/g (8认同)
  • 请注意,奇怪的是,```映射到具有*decimal*格式的实体,而```使用*hex*格式. (7认同)
  • 将`\n`转换为```的指导是什么? (6认同)
  • 这是源代码的更新链接:https://github.com/janl/mustache.js/blob/ba510eb3549e5c7e673fd262e87f2a8027e03237/mustache.js#L47-L60 (2认同)
  • @amwinter将`\n`转换为```有时是有害的 - 例如:在title等属性中.使用<pre>或明确地执行. (2认同)
  • 我最终得到了“&amp; amp; amp; amp;”。我在哪里可以买到万用表 (2认同)
  • 为什么编码`/`?这是[不需要](http://stackoverflow.com/questions/7381974/which-characters-need-to-be-escaped-on-html). (2认同)
  • 这不会转义 unicode 字符;/u003c 和 /u003e 用于“&lt;”和“&gt;”。 (2认同)

tra*_*vis 437

由于您使用的是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;
Run Code Online (Sandbox Code Playgroud)

  • 您错过了必须访问$("div.someClass").html()以获取转义版本的要点. (57认同)
  • @travis jQuery网站上记录了这一点:"由于不同浏览器中HTML解析器的不同,返回的文本可能因换行符和其他空格而异." http://api.jquery.com/text/ (20认同)
  • 如果你的字符串中有空格和\n\r\t字符,那么这不是跨浏览器安全的 (16认同)
  • 这不会逃避报价和双引号,这是不好的!http://wonko.com/post/html-escaping (16认同)
  • @mklement如果你已经在使用这个解决方案,你就不会遇到任何问题:`$(element2).attr("some-attr",$(element1).html());`See这个例子:http://jsbin.com/atibig/1/edit (3认同)
  • @travis谢谢; 我认为这是你暗示的,但只是为了明确:`attr()`做自己的编码,所以你可以直接传递未编码的文本*; 例如,`$(elem).attr("some-attr","<script> alert('hi!'); </ script>")`. (2认同)
  • 为什么不使用$("<div> </ div>")? (2认同)
  • 顺便说一句,您不需要在文档中使用`div.someClass`元素.相反,你可以动态生成一个worker元素,如下所示:`var escaped = $('<div>').text(someHtmlString).html()`. (2认同)

Hen*_*k N 180

$('<div/>').text('This is fun & stuff').html(); // "This is fun &amp; stuff"
Run Code Online (Sandbox Code Playgroud)

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

  • 应该注意的是,这无法避免单引号或双引号.如果您计划将值放入HTML属性,这可能是一个问题. (46认同)
  • 如上面的答案中所述,此解决方案无法保证保留空白. (11认同)
  • @Kip:@travis发现jQuery的`attr()`方法(截至至少1.8.3)执行自己的编码,因此未编码的字符串可以直接传递*; 例如:`$('<div />').attr('test-attr','\'Tis"fun"&stuff')[0] .outerHTML` (6认同)

tgh*_*ghw 61

如果你正在逃避HTML,那么我只能想到三个非常必要的东西:

html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
Run Code Online (Sandbox Code Playgroud)

根据您的使用情况,您可能还需要执行类似的"操作&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]);
Run Code Online (Sandbox Code Playgroud)

encodeURIComponent() 只会为URL而不是HTML转义它.

  • 如果有问题的HTML已经转义了实体,那么这个正则表达式将产生奇怪的结果.例如,逃离"Tom&amp; Jerry"将产生"Tom&amp; amp; Jerry" (13认同)
  • 请使用`var`在本地声明`item`; 无论如何,在循环遍历数组时,根本不要使用`for ... in`循环!请使用普通的`for`循环.哦,它是`encodeURIComponent`,而不是`escapeURIComponent`. (12认同)
  • @Ryan:虽然值得指出这个解决方案不能正确处理已经编码的字符串,但同样适用于此页面上的大多数(可能是所有)解决方案也是值得的. (11认同)
  • 只是对于新人们的一种提醒,不,如果你打算对你的网站非英文字符的地方使用这个......显然,这不会因为像"E"重音符号的字符做:`&eacute`; 这是一个html实体列表,供参考:http://www.w3schools.com/tags/ref_entities.asp (4认同)
  • 如果您正在使用标记属性,那么您还需要转义引号和/或双引号.htmlspecialchars的PHP文档包含它执行的有用转换列表.http://www.php.net/htmlspecialchars (3认同)
  • @RyanMohr 你说逃避“汤姆和杰瑞”会产生“汤姆和杰瑞”。好的!这正是正确的行为。像这样正确的转义可以让人们发表像你这样的评论,讨论 HTML,而不会发生奇怪的事情。如果它保持不变,*那*会很奇怪。 (2认同)

zra*_*ajm 36

我写了一个很小的功能来做到这一点.它只是逃脱",&,<>(但通常这就是你所需要的是这样).它比先前提出的解决方案稍微优雅一点,因为它只使用一个 .replace()来完成所有转换.(编辑2:降低代码复杂性使得功能更小更整洁,如果您对原始代码感到好奇,请参阅此答案的结尾.)

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

这是普通的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];
    });
}
Run Code Online (Sandbox Code Playgroud)

请注意以上&#39;对撇号的使用(&apos;可能已使用符号实体- 它以XML格式定义,但最初未包含在HTML规范中,因此可能不受所有浏览器支持.请参阅:维基百科有关HTML字符编码的文章).我还记得在某处读取使用十进制实体比使用十六进制更广泛支持,但我现在似乎无法找到它的来源.(并且不存在很多不支持十六进制实体的浏览器.)

注意:添加/'转义转义字符列表并不是那么有用,因为它们在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]; });
    };
}());
Run Code Online (Sandbox Code Playgroud)

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

  • 最后的想法:似乎不需要编码`/`,但编码`'`似乎仍然有用,可以安全地处理编码字符串用作*引号**中包含的*attribute*值的情况. (2认同)

cho*_*ovy 36

很容易使用下划线:

_.escape(string) 
Run Code Online (Sandbox Code Playgroud)

Underscore是一个实用程序库,它提供了本机js不提供的许多功能.还有lodash与下划线相同的API,但被重写为更高性能.

  • 其逆过程是`_.unescape(string)`。 (2认同)

Ada*_*ett 33

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

escaped = new Option(unescaped).innerHTML;
Run Code Online (Sandbox Code Playgroud)

编辑:这不会逃避报价.引用需要转义的唯一情况是,内容是否将内联粘贴到HTML字符串中的属性.我很难想象一个这样做的好例子.

编辑2:如果性能至关重要,最高性能解决方案(约50%)仍然是一系列正则表达式替换.现代浏览器将检测到正则表达式不包含运算符,只包含字符串,并将所有运算符折叠为单个运算.


int*_*dis 31

这是一个干净,清晰的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;');
}
Run Code Online (Sandbox Code Playgroud)


Sar*_*ram 28

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

function HTMLescape(html){
    return document.createElement('div')
        .appendChild(document.createTextNode(html))
        .parentNode
        .innerHTML
}
Run Code Online (Sandbox Code Playgroud)

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

//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
}
Run Code Online (Sandbox Code Playgroud)

看看我的最终性能比较(堆栈问题).

  • 是否有必要使用两个节点?只有一个:`var p = document.createElement('p'); p.textContent = html; return p.innerHTML;` (2认同)
  • @DanDascalescu:根据[MDN](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent),只有Chrome 1+,Firefox 2支持`textContent`功能, IE9,Opera 9.64和Safari 3(后两个注释"可能更早").因此,它将打破OP"完全跨浏览器兼容"的主张. (2认同)

Nik*_*rov 24

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

_.str.escapeHTML('<div>Blah blah blah</div>')
Run Code Online (Sandbox Code Playgroud)

输出:

'&lt;div&gt;Blah blah blah&lt;/div&gt;'
Run Code Online (Sandbox Code Playgroud)

  • 主下划线库现在有一个``_.escape()``实用函数. (20认同)

Nic*_*ier 15

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

实际上,我使用以下代码片段来完成不需要任何框架的技巧:

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


Jee*_*ena 15

我已经增强了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];
    });
}
Run Code Online (Sandbox Code Playgroud)

这样它很容易使用 "Some <text>, more Text&Text".escapeHTML()


ron*_*bot 10

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

_.escape('Curly, Larry & Moe'); // returns: Curly, Larry &amp; Moe
Run Code Online (Sandbox Code Playgroud)


Way*_*yne 5

如果你正在使用正则表达式路线,那么上面的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]]);
}
Run Code Online (Sandbox Code Playgroud)

  • 我相信它应该是(在findReplace中的var项目){escaped = escaped.replace(findReplace [item] [0],findReplace [item] [1]); } (2认同)

小智 5

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 你在那里抑制什么类型的异常? (4认同)