如何使用jQuery解码HTML实体?


Answers:


437

安全说明:使用此答案(下面以其原始形式保留)可能会在您的应用程序中引入XSS漏洞您不应该使用此答案。阅读lucascaro的答案以获取对该答案中漏洞的解释,然后使用该答案或Mark Amery的答案中的方法

其实试试看

var decoded = $("<div/>").html(encodedStr).text();

175
不要与不受信任的输入做到这一点。即使该节点未连接到DOM,许多浏览器也会加载图像并引发相关事件。尝试跑步$("<div/>").html('<img src="http://www.google.com/images/logos/ps_logo2.png" onload=alert(1337)>')。在Firefox或Safari中,它会触发警报。
Mike Samuel

@Mike,那么您推荐什么呢?如果您不知道要替换的内容,那么您对.replace()的回答是不好的……
ekkis,2011年

7
@ekkis,在尝试解码实体之前,您需要剥离标签。 str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/g, "")或类似的东西。
迈克·塞缪尔

2
我对类似问题的回答是一个更好的实现(我认为),它从输入中剥离了大多数HTML标记(由Mike提供)。它也没有jQuery的开销,因此非常适合其他环境。
罗伯特·K

6
@MichaelStum在此处所做的编辑使Mike Samuel的评论和下一个投票最高的答案都无效,并且这样做并没有真正修复所有jQuery版本的XSS漏洞(如下面的答案所述)。向此答案添加安全警告是合理的(我将这样做);使此页面上的其他讨论变得荒谬而又无法真正解决安全漏洞绝对不是!
Mark Amery

211

没有任何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指出的那样,使用x<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)">')

但是,针对a的攻击是不可能的,<textarea>因为没有HTML元素被允许为a的内容<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捕获此漏洞。


6
提取文本值后销毁文本区域可能是个好主意:decodedString = textArea.value; textArea.remove(); return decodedString;
Werner

2
或仅当javascript版本实际上支持remove()时:if ('remove' in Element.prototype) textArea.remove();
Werner

6
@Werner函数退出后,将不再有任何变量持有对该函数的引用,因此它将由垃圾收集器自动删除。
user2428118

我将它与.NET从按钮单击的代码背后一起使用,由于某种原因,可接受的答案导致了回发。这个答案没有,所以这对我来说是最好的答案。谢谢!
Snailer

@Snailer $("<div />").html(string).text() 将执行提供的字符串中的所有JavaScript,我怀疑这是引起您问题的原因。接受的答案应更新为此。
jbowman

80

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

相反,请使用模板渲染器(例如Mustache.js@VyvIT注释中的encodeEntities)。

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

_.escape(字符串)

_.unescape(字符串)


2
这实际上值得更多的赞扬!绝对是我的首选解决方案。unescape顺便说一句,他们现在包括在文档中。
致命吉他

5
_.unescape("&#39;")结果只是“&#39;” 而不是单引号。有什么我想念的东西吗?或者下划线不能逃脱到HTML实体代码,如下所示:w3schools.com/tags/ref_entities.asp
Jason Axelson

6
github上的错误已关闭,显示为“无法修复”;这意味着该解决方案将无法正常工作。
伊戈尔·楚宾

3
您说Underscore的escapeunescape方法...对于用户输入而言并不安全”。这是什么意思 听起来对我来说是胡说八道,但也许我缺少了一些东西-您能澄清一下吗?
Mark Amery

2
@VyvIT尝试过_.unescape("&lt;img src=fake onerror=alert('boo!')&gt;")(在Chrome / FF / IE中)。但是它没有显示任何警报。在控制台中进行了尝试,并将其放入我的JS文件中。结果相同。
Vivek Athalye

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>

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

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

顺便说一句,您可以看到我在jQuery插件中找到的插件-HTML解码和编码,可以 HTML字符串进行编码和解码。


26

这个问题受到“使用jQuery”的限制,但它可能会帮助一些人知道,此处最佳答案中给出的jQuery代码在下面做了以下工作……无论是否使用jQuery,它都可以工作:

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

20

您可以使用he库,该库可从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"

质疑图书馆的作者是否有任何理由在客户端代码中使用此图书馆,以支持此处和其他地方的其他答案中<textarea>提供的技巧。他提供了一些可能的理由:

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

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

    如果您想避免与实体解码相关的浏览器错误和/或能够处理所有命名字符引用,则无法逃脱<textarea>;你需要像这样的图书馆。

  • 他真是个好主意,感觉像这样做事不那么hacky。


4
+1 jQuery并不是万能的解决方案。使用正确的工具完成工作。
Mathias Bynens 2014年

这些是解码HTML实体的最佳方法。所有其他答案(关于这个问题和类似问题)都使用innerHTML(创建新的HTML元素,处理HTML代码,然后获取该元素的innerHTML,如果您不十分小心,则可能会受到XSS攻击,请参阅),或者建议使用都不完整的Underscore.js unescape或Lodash unescape方法(仅适用于少数HTML实体)。he库是最完整,最安全的选择!
ands 19-10-24

18

编码:

$("<textarea/>").html('<a>').html();      // return '&lt;a&gt'

解码:

$("<textarea/>").html('&lt;a&gt').val()   // return '<a>'

3
已经有一个有效的答案,并且几乎与此相同。我们不需要重复的答案
markasoftware

4
这是有效的答案。汤姆的答案使用DIV元素,这使该答案容易受到XSS的攻击。
Francisco Hodge

2
这是清晰的最佳答案。
Dan Randolph'2

4

采用

myString = myString.replace( /\&amp;/g, '&' );

在服务器端最容易做到这一点,因为显然JavaScript没有用于处理实体的本机库,对于扩展JavaScript的各种框架,我也没有在搜索结果的顶部找到任何内容。

搜索“ JavaScript HTML实体”,您可能会为此目的找到一些库,但它们可能全部基于上述逻辑构建-逐个实体替换。


0

我只需要一个HTML实体字符(⇓)作为HTML按钮的值即可。HTML代码从浏览器开始就看起来不错:

<input type="button" value="Embed & Share  &dArr;" id="share_button" />

现在,我添加了一个开关,该开关也应显示字符。这是我的解决方案

$("#share_button").toggle(
    function(){
        $("#share").slideDown();
        $(this).attr("value", "Embed & Share " + $("<div>").html("&uArr;").text());
    }

这将再次在按钮中显示⇓。我希望这可以帮助某人。


更简单的方法是使用Unicode转义序列(即"Embed & Share \u21d1"),或者更好的方法是,"Embed & Share ⇑"只要您能够以UTF-8(或UTF-16或任何其他支持⇑字符的编码)来提供脚本。使用DOM元素解析HTML实体只是将任意的unicode字符烘焙到JavaScript字符串中,是一种狡猾且富有创意的方法,会让Rube Goldberg感到骄傲,但这不是一个好习惯;unicode转义使用专门用于处理此用例的语言。
马克·阿默里

0

您必须为html实体创建自定义函数:

function htmlEntities(str) {
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g,'&gt;').replace(/"/g, '&quot;');
}

我不知道,它帮助了我+1 l
Szymon Toda

可能因为它只处理某些实体而被否决。
Jasen

最初的问题是如何解码实体,这期望的相反。它将极其有限的字符集编码实体。正如不赞成投票的工具提示所言,“此答案没有用”。令我惊讶的是,在4年后,它的净得分仍为正。
斯蒂芬·P

0

假设您在String下面。

我们的豪华客舱温暖,舒适,舒适。自在

var str = $("p").text(); // get the text from <p> tag
$('p').html(str).text();  // Now,decode html entities in your variable i.e 

str并分配回

标签。

而已。


0

对于ExtJS用户,如果您已经有了编码的字符串,例如,当库函数的返回值是innerHTML内容时,请考虑以下ExtJS函数:

Ext.util.Format.htmlDecode(innerHtmlContent)

这仅适用于5个HTML实体。您可以在文档源代码中看到这一点。
ands


0

尝试这个 :

var htmlEntities = "&lt;script&gt;alert('hello');&lt;/script&gt;";
var htmlDecode =$.parseHTML(htmlEntities)[0]['wholeText'];
console.log(htmlDecode);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

parseHTML是Jquery库中的Function,它将返回一个数组,其中包含有关给定String的一些详细信息。

在某些情况下,字符串很大,因此该函数会将内容分为许多索引。

并获取所有索引数据,您应该转到任何索引,然后访问称为“ wholeText”的索引。

我选择索引0是因为它在所有情况下都适用(小字符串或大字符串)。


尽管此代码段可能是解决方案,但提供说明确实有助于提高您的帖子质量。请记住,您将来会为读者回答这个问题,而这些人可能不知道您提出代码建议的原因。
约翰

添加了解释...谢谢:)
Fawaz Al Romy

-1

这里仍然是一个问题:分配给输入值的转义字符串看起来不可读

var string = _.escape("<img src=fake onerror=alert('boo!')>");
$('input').val(string);

范例:https://jsfiddle.net/kjpdwmqa/3/


这不是问题的答案。OP要求解码(转义)HTML实体,但是在此答案中,您使用的escape是Underscore.js方法。也没有解释您的代码示例应如何解决OP的问题。
ands

-1

另外,这里还有一个图书馆。

在这里,https://cdnjs.com/libraries/he

npm install he                 //using node.js

<script src="js/he.js"></script>  //or from your javascript directory

用法如下...

//to encode text 
he.encode('© Ande & Nonso® Company LImited 2018');  

//to decode the 
he.decode('&copy; Ande &amp; Nonso&reg; Company Limited 2018');

干杯。


关于he库,已经有了一个完整的答案,其中包含简单的代码示例和很好的解释,说明您何时以及何时使用he库
ands

-3

要使用jQuery解码HTML实体,只需使用以下功能:

function html_entity_decode(txt){
    var randomID = Math.floor((Math.random()*100000)+1);
    $('body').append('<div id="random'+randomID+'"></div>');
    $('#random'+randomID).html(txt);
    var entity_decoded = $('#random'+randomID).html();
    $('#random'+randomID).remove();
    return entity_decoded;
}

如何使用:

Javascript:

var txtEncoded = "&aacute; &eacute; &iacute; &oacute; &uacute;";
$('#some-id').val(html_entity_decode(txtEncoded));

HTML:

<input id="some-id" type="text" />

-3

最简单的方法是为您的元素设置类选择器,然后使用以下代码:

$(function(){
    $('.classSelector').each(function(a, b){
        $(b).html($(b).text());
    });
});

不需要了!

我遇到了这个问题,并找到了明确的解决方案,并且效果很好。


这不是对OP问题的答案。OP要求在STRING中对HTML实体进行解码,这不仅不能解决OP的问题,而且还应将HTML元素中转义的HTML实体替换为不应忽略的HTML实体。
ands 19-10-24

-3

我认为这与选择的解决方案完全相反。

var decoded = $("<div/>").text(encodedStr).html();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.