如何使用 jQuery 解码 HTML 实体?

IT技术 javascript jquery html
2021-01-22 09:03:52

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

6个回答

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

其实试试

var encodedStr = "This is fun & stuff";
var decoded = $("<div/>").html(encodedStr).text();
console.log(decoded);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div/>

@ekkis,您需要在尝试解码实体之前去除标签。 str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/g, "")或类似的东西。
2021-03-15 09:03:52
不要与不受信任的输入做到这一点。即使节点未附加到 DOM,许多浏览器也会加载图像并触发相关事件。尝试运行$("<div/>").html('<img src="http://www.google.com/images/logos/ps_logo2.png" onload=alert(1337)>')在 Firefox 或 Safari 中,它会触发警报。
2021-03-26 09:03:52
一个更好的实现(在我看来)从输入中去除大多数 HTML 标签(由 Mike 提供)在我对类似问题的回答中它也没有 jQuery 的开销,因此非常适合其他环境。
2021-03-28 09:03:52
@Mike,那么您推荐什么?如果您不知道要替换什么,那么您对 ​​.replace() 的回答就不好...
2021-04-03 09:03:52
@MichaelStum 您在此处的编辑使 Mike Samuel 的评论和下一个最高投票的答案无效,并且这样做并没有实际修复所有 jQuery 版本的 XSS 漏洞(如下面的答案所述)。向此答案添加安全警告是合理的(我将这样做);在此页面上呈现其他讨论无意义而未能实际修复安全漏洞绝对不是!
2021-04-06 09:03:52

没有任何 jQuery:

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

console.log(decodeEntities('1 &amp; 2')); // '1 & 2'

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


类似方法中的安全问题

正如Mike Samuel指出的使用不受信任的用户输入<div>而不是使用 a执行此<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)">')

然而,这种攻击是不可能针对 a 的,<textarea>因为没有允许 a 的内容的 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)">'))

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

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

//-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>

* 感谢Eru Penkman捕获此漏洞。

我在按钮点击后的代码隐藏中将它与 .NET 结合使用,并且由于某种原因,接受的答案导致了回发。这个答案没有,所以这对我来说是最好的答案。谢谢!
2021-03-10 09:03:52
或者仅当 javascript 版本实际支持 remove() 时: if ('remove' in Element.prototype) textArea.remove();
2021-03-14 09:03:52
@Snailer$("<div />").html(string).text() 将执行提供的字符串中的任何 javascript,我怀疑这是导致您出现问题的原因。接受的答案应该更新为这个答案。
2021-03-16 09:03:52
在提取其值后销毁 textarea 可能是一个好主意: decodedString = textArea.value; textArea.remove(); return decodedString;
2021-03-28 09:03:52
@Werner 一旦函数退出,就不会再有变量持有对它的引用,因此垃圾收集器会自动删除它
2021-04-03 09:03:52

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

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

Underscore.js实用程序带库带有escapeunescape方法,但它们对于用户输入并不安全:

_.escape(字符串)

_.unescape(字符串)

github 上的 bug 被关闭为“不会修复”;这意味着该解决方案不起作用,也不会起作用。
2021-03-14 09:03:52
@VyvIT 尝试过_.unescape("&lt;img src=fake onerror=alert('boo!')&gt;")(在 Chrome/FF/IE 中)。但它没有显示任何警报。在控制台中尝试过,也将其放入我的 JS 文件中。结果一样。
2021-03-15 09:03:52
_.unescape("&#39;")结果只是“'” 而不是单引号。有没有我遗漏的东西或下划线没有转义到 HTML 实体代码,如所示:w3schools.com/tags/ref_entities.asp
2021-03-16 09:03:52
这实际上值得更多的赞成!绝对是我首选的解决方案。他们unescape现在包含在文档中,顺便说一句。
2021-03-30 09:03:52
你说 Underscore 的"escapeunescape方法......对于用户输入不安全"你这是什么意思?这对我来说听起来像是胡说八道,但也许我遗漏了一些东西 - 你能澄清一下吗?
2021-03-30 09:03:52

我认为您混淆了文本和 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>

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

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

顺便说一下,你可以看到我在jQuery插件中找到的一个插件——HTML decode and encode,它对HTML字符串进行编码和解码。

该问题受到“使用 jQuery”的限制,但它可能有助于某些人知道此处最佳答案中给出的 jQuery 代码在下面执行以下操作……这在使用或不使用 jQuery 的情况下都有效:

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