如何使用jQuery解码HTML实体?

Edd*_*dyR 327 html javascript jquery

如何使用jQuery解码字符串中的HTML实体?

小智 434

安全说明:使用此答案(保存在下面的原始格式中)可能会在您的应用程序中引入XSS漏洞.你不应该使用这个答案.阅读lucascaro的答案,解释这个答案中的漏洞,并使用答案中的方法或Mark Amery的答案.

实际上,试试吧

var decoded = $("<div/>").html(encodedStr).text();
Run Code Online (Sandbox Code Playgroud)

  • 请不要**使用不受信任的输入执行此操作.即使节点未附加到DOM,许多浏览器也会加载图像和触发相关事件.尝试运行`$("<div />").html('<img rel="nofollow noreferrer" src ="http://www.google.com/images/logos/ps_logo2.png"onload = alert(1337)>')`.在Firefox或Safari中,它会触发警报. (173认同)
  • @ekkis,你需要在尝试解码实体之前剥离标签.`str.replace(/ <\ /?\ w(?:[^"'>] |"[^"]*"|'[^']*')*>/g,"")`或类似的东西. (7认同)
  • @MichaelStum你的编辑在这里使Mike Samuel的评论和下一个最高投票的答案无效,并且没有实际修复所有jQuery版本的XSS漏洞*(如下面的答案所述).为这个答案添加安全警告是合理的(我将这样做); 在这个页面上进行其他讨论是荒谬的,而未能真正修复安全漏洞绝对不是! (5认同)
  • 一个更好的实现(在我看来)从输入中删除了大多数HTML标签(由迈克提供)是我对[类似问题](http://stackoverflow.com/a/9609450/24950)的回答.它也没有jQuery的开销,所以它非常适合其他环境. (2认同)

luc*_*aro 202

没有任何jQuery:

function decodeEntities(encodedString) {
  var textArea = document.createElement('textarea');
  textArea.innerHTML = encodedString;
  return textArea.value;
}

console.log(decodeEntities('1 &amp; 2')); // '1 & 2'
Run Code Online (Sandbox Code Playgroud)

这与接受的答案类似,但可以安全地使用不受信任的用户输入.


类似方法中的安全问题

正如Mike Samuel指出的那样,使用一个不受信任的用户输入<div>代替<textarea>一个XSS漏洞,即使<div>从未添加到DOM:

function decodeEntities(encodedString) {
  var div = document.createElement('div');
  div.innerHTML = encodedString;
  return div.textContent;
}

// Shows an alert
decodeEntities('<img src="nonexistent_image" onerror="alert(1337)">')
Run Code Online (Sandbox Code Playgroud)

但是,这种攻击是不可能的,<textarea>因为没有HTML元素是允许的内容<textarea>.因此,仍然存在于"编码"字符串中的任何HTML标记将由浏览器自动进行实体编码.

function decodeEntities(encodedString) {
    var textArea = document.createElement('textarea');
    textArea.innerHTML = encodedString;
    return textArea.value;
}

// Safe, and returns the correct answer
console.log(decodeEntities('<img src="nonexistent_image" onerror="alert(1337)">'))
Run Code Online (Sandbox Code Playgroud)

警告:这样做使用jQuery的.html().val()方法,而不是使用.innerHTML.value也是不安全*的jQuery的一些版本中,使用时甚至textarea.这是因为旧版本的jQuery会故意并明确地评估传递给字符串的脚本.html().因此这样的代码在jQuery 1.8中显示了一个警告:

//<!-- CDATA
// Shows alert
$("<textarea>")
.html("<script>alert(1337);</script>")
.text();

//-->
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>
Run Code Online (Sandbox Code Playgroud)

*感谢Eru Penkman捕获此漏洞.

  • 在提取其值后销毁textarea可能是个好主意:`decodingString = textArea.value;``textArea.remove();``return decodingString;` (5认同)
  • @Werner一旦函数退出,就没有更多变量持有对它的引用,所以它将被[垃圾收集器]自动删除(https://developer.mozilla.org/docs/Web/JavaScript/内存管理). (5认同)
  • 或者只有当javascript的版本实际上支持remove()时:`if('remove'在Element.prototype中)textArea.remove();` (2认同)

Ala*_*ett 80

就像Mike Samuel所说,不要使用jQuery.html().text()来解码html实体,因为它不安全.

相反,使用来自@ VyvIT评论的Mustache.jsdecodeEntities等模板渲染器.

Underscore.js公用事业带库带有escapeunescape方法,但它们都没有用户输入的安全:

_.escape(串)

_.unescape(串)

  • github上的bug被关闭为"Will not fix"; 这意味着此解决方案不起作用,不起作用. (6认同)
  • `_.capecape("&#39;")`只会产生"&#39;" 而不是单引号.是否有我遗漏的内容或者下划线没有转义为HTML实体代码,如下所示:http://www.w3schools.com/tags/ref_entities.asp (5认同)
  • 你说Underscore的*"`escape`和`unescape`方法......对于用户输入来说是不安全的"*.你这是什么意思?这对我来说听起来像是胡说八道,但也许我错过了一些东西 - 你能澄清一下吗? (3认同)
  • 这实际上值得更多的赞成!绝对是我的首选解决方案.到目前为止,他们在文档中包含了"unes​​cape",顺便说一下. (2认同)
  • @VyvIT尝试使用_.unescape(“&lt; img src = fake onerror = alert('boo!')&gt;”))(在Chrome / FF / IE中)。但是它*没有*显示任何警报。在控制台中进行了尝试,并将其放入我的JS文件中。结果相同。 (2认同)

Can*_*var 28

我认为你混淆了文本和HTML方法.看看这个例子,如果你使用元素的内部HTML作为文本,你将得到解码的HTML标签(第二个按钮).但是如果你将它们用作HTML,你将获得HTML格式的视图(第一个按钮).

<div id="myDiv">
    here is a <b>HTML</b> content.
</div>
<br />
<input value="Write as HTML" type="button" onclick="javascript:$('#resultDiv').html($('#myDiv').html());" />
&nbsp;&nbsp;
<input value="Write as Text" type="button" onclick="javascript:$('#resultDiv').text($('#myDiv').html());" />
<br /><br />
<div id="resultDiv">
    Results here !
</div>
Run Code Online (Sandbox Code Playgroud)

第一个按钮写道:这是一个HTML内容.

第二个按钮写道:这是一个<B> HTML </ B>内容.

顺便说一下,你可以看到我在jQuery插件中找到的插件 - HTML解码和编码,用于编码和解码HTML字符串.


Ron*_*ndo 26

这个问题受到'with jQuery'的限制,但它可能有助于一些人知道在这里的最佳答案中给出的jQuery代码在下面做了以下...这有或没有jQuery:

function decodeEntities(input) {
  var y = document.createElement('textarea');
  y.innerHTML = input;
  return y.value;
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*ery 18

您可以使用他的库,可从https://github.com/mathiasbynens/he获得

例:

console.log(he.decode("J&#246;rg &amp J&#xFC;rgen rocked to &amp; fro "));
// Logs "Jörg & Jürgen rocked to & fro"
Run Code Online (Sandbox Code Playgroud)

向图书馆的作者提出了一个问题,即是否有任何理由在客户端代码中使用此库以支持此处和其他地方的其他答案中<textarea>提供的黑客.他提供了一些可能的理由:

  • 如果您正在使用node.js服务器端,则使用用于HTML编码/解码的库可以为您提供一个可在客户端和服务器端工作的单一解决方案.

  • 某些浏览器的实体解码算法存在错误或缺少对某些命名字符引用的支持.例如,Internet Explorer将&nbsp;正确解码和呈现非中断空格(),但是通过DOM元素的innerText属性将它们报告为普通空格而不是非中断空格,从而打破了<textarea>黑客攻击(虽然只是一种次要的方式).此外,IE 8和9根本不支持 HTML 5中添加的任何新命名字符引用.的作者还在http://mathias.html5.org/tests/html上对命名字符引用支持进行了测试./ named-character-references /.在IE 8中,它报告了超过一千个错误.

    如果你想要与实体解码相关的浏览器错误和/或能够处理所有命名的字符引用,你就无法摆脱<textarea>黑客攻击.你需要像这样的图书馆.

  • 他只是觉得用这种方式做事就不那么黑了.

  • +1 jQuery不是解决所有问题的方法.使用正确的工具完成工作. (3认同)

小智 17

编码:

$("<textarea/>").html('<a>').html();      // return '&lt;a&gt'
Run Code Online (Sandbox Code Playgroud)

解码:

$("<textarea/>").html('&lt;a&gt').val()   // return '<a>'
Run Code Online (Sandbox Code Playgroud)

  • 这是有效的答案.tom的答案使用了DIV元素,这使得该答案容易受到XSS的攻击. (4认同)
  • 已经有一个有效的答案,它几乎与此相同.我们不需要重复的答案 (3认同)
  • 这是清晰的最佳答案。 (2认同)