200

显然,这比我想象的更难找到。它甚至是如此简单......

是否有与 PHP内置在 JavaScript中的htmlspecialchars等效的功能?我知道自己实现它相当容易,但是使用内置函数(如果可用)会更好。

对于那些不熟悉 PHP 的人,htmlspecialchars 会将类似的东西翻译<htmltag/>&lt;htmltag/&gt;

我知道这一点escape()encodeURI()但不要这样工作。

4

17 回答 17

365

您的解决方案代码存在问题 - 它只会转义每个特殊字符的第一次出现。例如:

escapeHtml('Kip\'s <b>evil</b> "test" code\'s here');
Actual:   Kip&#039;s &lt;b&gt;evil</b> &quot;test" code's here
Expected: Kip&#039;s &lt;b&gt;evil&lt;/b&gt; &quot;test&quot; code&#039;s here

这是正常工作的代码:

function escapeHtml(text) {
  return text
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;")
      .replace(/'/g, "&#039;");
}

更新

以下代码将产生与上述相同的结果,但它的性能更好,特别是在大文本块上(感谢jbo5112)。

function escapeHtml(text) {
  var map = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#039;'
  };
  
  return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}
于 2011-01-29T05:48:48.727 回答
35

那就是 HTML 编码。没有原生的 javascript 函数可以做到这一点,但你可以用谷歌搜索并得到一些很好的完成。

例如http://sanzon.wordpress.com/2008/05/01/neat-little-html-encoding-trick-in-javascript/

编辑:
这是我测试过的:

var div = document.createElement('div');
  var text = document.createTextNode('<htmltag/>');
  div.appendChild(text);
  console.log(div.innerHTML);

输出:&lt;htmltag/&gt;

于 2009-11-24T02:04:55.460 回答
30

值得一读: http ://bigdingus.com/2007/12/29/html-escaping-in-javascript/

escapeHTML: (function() {
 var MAP = {
   '&': '&amp;',
   '<': '&lt;',
   '>': '&gt;',
   '"': '&#34;',
   "'": '&#39;'
 };
  var repl = function(c) { return MAP[c]; };
  return function(s) {
    return s.replace(/[&<>'"]/g, repl);
  };
})()

注意:只运行一次。并且不要在已经编码的字符串上运行它,例如&amp;变成&amp;amp;

于 2012-03-13T02:09:55.493 回答
23

这是一个转义 HTML 的函数:

function escapeHtml(str)
{
    var map =
    {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#039;'
    };
    return str.replace(/[&<>"']/g, function(m) {return map[m];});
}

并解码:

function decodeHtml(str)
{
    var map =
    {
        '&amp;': '&',
        '&lt;': '<',
        '&gt;': '>',
        '&quot;': '"',
        '&#039;': "'"
    };
    return str.replace(/&amp;|&lt;|&gt;|&quot;|&#039;/g, function(m) {return map[m];});
}
于 2017-01-17T14:01:56.337 回答
18

使用 jQuery 可以是这样的:

var escapedValue = $('<div/>').text(value).html();

来自相关问题Escapeing HTML strings with jQuery

正如评论中提到的那样,双引号和单引号保持原样用于此实现。这意味着如果您需要将元素属性作为原始 html 字符串,则不应使用此解决方案。

于 2010-09-02T11:51:20.750 回答
8

Underscore.js为此提供了一个函数:

_.escape(string)

转义字符串以插入 HTML,替换 &、<、>、" 和 ' 字符。

http://underscorejs.org/#escape

它不是内置的 JavaScript 函数,但如果您已经在使用 Underscore.js,如果要转换的字符串不太大,它是比编写自己的函数更好的选择。

于 2014-06-02T12:14:32.653 回答
6

对此的另一种看法是完全放弃所有字符映射,而是将所有不需要的字符转换为它们各自的数字字符引用,例如:

function escapeHtml(raw) {
    return raw.replace(/[&<>"']/g, function onReplace(match) {
        return '&#' + match.charCodeAt(0) + ';';
    });
}

请注意,指定的 RegEx 仅处理 OP 想要转义的特定字符,但根据要使用转义 HTML 的上下文,这些字符可能不够用。Ryan Grove 的文章There's more to HTML escaping than &, <, >, and "是关于该主题的好读物。根据您的上下文,可能非常需要以下 RegEx 以避免 XSS 注入:

var regex = /[&<>"'` !@$%()=+{}[\]]/g
于 2014-09-08T16:48:33.430 回答
5

采用:

String.prototype.escapeHTML = function() {
        return this.replace(/&/g, "&amp;")
                   .replace(/</g, "&lt;")
                   .replace(/>/g, "&gt;")
                   .replace(/"/g, "&quot;")
                   .replace(/'/g, "&#039;");
    }

样本:

var toto = "test<br>";
alert(toto.escapeHTML());
于 2014-03-20T08:31:31.513 回答
4

您可能不需要这样的功能。由于您的代码已经在浏览器中*,您可以直接访问 DOM,而不是生成和编码必须由浏览器向后解码才能实际使用的 HTML。

使用innerText属性将纯文本安全地插入到 DOM 中,比使用任何提供的转义函数快得多。甚至将静态预编码字符串分配给innerHTML.

用于classList编辑类、dataset设置data-属性和setAttribute其他用途。

所有这些都将为您处理逃逸。更准确地说,不需要转义,也不会在下面执行编码**,因为您正在处理 HTML,即 DOM 的文本表示。

// use existing element
var author = 'John "Superman" Doe <john@example.com>';
var el = document.getElementById('first');
el.dataset.author = author;
el.textContent = 'Author: '+author;

// or create a new element
var a = document.createElement('a');
a.classList.add('important');
a.href = '/search?q=term+"exact"&n=50';
a.textContent = 'Search for "exact" term';
document.body.appendChild(a);

// actual HTML code
console.log(el.outerHTML);
console.log(a.outerHTML);
.important { color: red; }
<div id="first"></div>

* 此答案不适用于服务器端 JavaScript 用户(Node.js

** 除非您之后明确地将其转换为实际的 HTML。例如,通过访问innerHTML- 当您$('<div/>').text(value).html();在其他答案中建议运行时会发生这种情况。因此,如果您的最终目标是在文档中插入一些数据,那么通过这种方式您将完成两次工作。您还可以看到,在生成的 HTML 中,并非所有内容都被编码,只有其有效所需的最小值。它是根据上下文完成的,这就是为什么这个 jQuery 方法不对引号进行编码,因此不应该用作通用转义符。当您将 HTML 构造为字符串时,在属性值的位置使用不受信任或包含引号的数据时,需要引号转义。如果您使用 DOM API,则根本不必关心转义。

于 2017-11-29T16:22:47.537 回答
2
function htmlEscape(str){
    return str.replace(/[&<>'"]/g,x=>'&#'+x.charCodeAt(0)+';')
}

此解决方案使用字符的数字代码,例如<替换为&#60;.

虽然它的性能比使用 map 的解决方案稍差,但它具有以下优点:

  • 不依赖于库或 DOM
  • 很容易记住(你不需要记住 5 个 HTML 转义字符)
  • 小代码
  • 相当快(它仍然比 5 链式替换更快)
于 2018-11-02T14:33:23.033 回答
2

靠书本

OWASP 建议“[e] 除了字母数字字符,[您应该] 转义所有 ASCII 值小于 256 的字符,其&#xHH;格式(或命名实体,如果可用)以防止切换出 [an] 属性。”

所以这是一个可以做到这一点的函数,并带有一个使用示例:

function escapeHTML(unsafe) {
  return unsafe.replace(
    /[\u0000-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u00FF]/g,
    c => '&#' + ('000' + c.charCodeAt(0)).slice(-4) + ';'
  )
}

document.querySelector('div').innerHTML =
  '<span class=' +
  escapeHTML('"fakeclass" onclick="alert("test")') +
  '>' +
  escapeHTML('<script>alert("inspect the attributes")\u003C/script>') +
  '</span>'
<div></div>

您应该验证我提供的实体范围以自己验证函数的安全性。你也可以使用这个正则表达式,它具有更好的可读性并且应该覆盖相同的字符代码,但在我的浏览器中性能降低了大约 10%:

/(?![0-9A-Za-z])[\u0000-\u00FF]/g

于 2020-06-11T21:03:31.877 回答
1

对于 Node.js 用户(或在浏览器中使用 Jade 运行时的用户),您可以使用 Jade 的转义功能。

require('jade').runtime.escape(...);

如果其他人在维护它,那么自己编写它没有任何意义。:)

于 2011-10-28T20:37:54.960 回答
1

我正在详细说明okw 的回答

您可以为此使用浏览器的 DOM 函数。

var utils = {
    dummy: document.createElement('div'),
    escapeHTML: function(s) {
        this.dummy.textContent = s
        return this.dummy.innerHTML
    }
}

utils.escapeHTML('<escapeThis>&')

这返回&lt;escapeThis&gt;&amp;

它使用标准函数createElement创建一个不可见元素,然后使用该函数textContent将任何字符串设置为其内容,然后innerHTML以 HTML 表示形式获取内容。

于 2019-02-27T23:02:22.273 回答
0
function htmlspecialchars(str) {
 if (typeof(str) == "string") {
  str = str.replace(/&/g, "&amp;"); /* must do &amp; first */
  str = str.replace(/"/g, "&quot;");
  str = str.replace(/'/g, "&#039;");
  str = str.replace(/</g, "&lt;");
  str = str.replace(/>/g, "&gt;");
  }
 return str;
 }
于 2013-03-04T12:35:09.720 回答
0

我希望这能赢得比赛,因为它的性能和最重要的不是使用 .replace('&','&').replace('<','<') 的链式逻辑...

var mapObj = {
   '&':  "&amp;",
   '<':  "&lt;",
   '>':  "&gt;",
   '"':  "&quot;",
   '\'': "&#039;"
};
var re = new RegExp(Object.keys(mapObj).join("|"), "gi");

function escapeHtml(str)
{
    return str.replace(re, function(matched)
    {
        return mapObj[matched.toLowerCase()];
    });
}

console.log('<script type="text/javascript">alert('Hello World');</script>');
console.log(escapeHtml('<script type="text/javascript">alert('Hello World');</script>'));
于 2014-02-26T16:45:47.883 回答
0

这与这个问题没有直接关系,但是可以通过以下方式在 JS 中完成相反的操作:

> String.fromCharCode(8212);
> "—&quot;

这也适用于 TypeScript。

于 2020-12-14T17:52:21.647 回答
-1

反转一:

function decodeHtml(text) {
    return text
        .replace(/&amp;/g, '&')
        .replace(/&lt;/ , '<')
        .replace(/&gt;/, '>')
        .replace(/&quot;/g,'"')
        .replace(/&#039;/g,"'");
}
于 2016-12-01T08:35:21.563 回答