在Javascript中使用Unescape HTML实体?

Jos*_*ian 147 html javascript xml-rpc escaping

我有一些与XML-RPC后端通信的Javascript代码.XML-RPC返回表单的字符串:

<img src='myimage.jpg'>
Run Code Online (Sandbox Code Playgroud)

但是,当我使用Javascript将字符串插入HTML时,它们会逐字呈现.我没有看到图像,我真的看到了字符串:

<img src='myimage.jpg'>
Run Code Online (Sandbox Code Playgroud)

我的猜测是HTML正在通过XML-RPC通道进行转义.

我怎样才能在Javascript中取消字符串?我尝试了这个页面上的技术,但未成功:http://paulschreiber.com/blog/2008/09/20/javascript-how-to-unescape-html-entities/

诊断问题的其他方法有哪些?

Wla*_*ant 318

这里给出的大多数答案都有一个很大的缺点:如果您尝试转换的字符串不受信任,那么您最终会遇到跨站点脚本(XSS)漏洞.对于接受的答案中的功能,请考虑以下事项:

htmlDecode("<img src='dummy' onerror='alert(/xss/)'>");
Run Code Online (Sandbox Code Playgroud)

这里的字符串包含一个未转义的HTML标记,因此该htmlDecode函数不会解码任何内容,而是实际运行字符串中指定的JavaScript代码.

使用所有现代浏览器都支持的DOMParser可以避免这种情况:

function htmlDecode(input)
{
  var doc = new DOMParser().parseFromString(input, "text/html");
  return doc.documentElement.textContent;
}

// This returns "<img src='myimage.jpg'>"
htmlDecode("&lt;img src='myimage.jpg'&gt;");

// This returns ""
htmlDecode("<img src='dummy' onerror='alert(/xss/)'>");
Run Code Online (Sandbox Code Playgroud)

保证此函数不会将任何JavaScript代码作为副作用运行.将忽略任何HTML标记,仅返回文本内容.

兼容性说明:解析HTML DOMParser至少需要Chrome 30,Firefox 12,Opera 17,Internet Explorer 10,Safari 7.1或Microsoft Edge.因此,所有没有支持的浏览器都会超过他们的EOL,而截至2017年,唯一仍然可以在野外看到的浏览器偶尔会出现旧的Internet Explorer和Safari版本(通常这些版本仍然不足以打扰).

  • 我认为这个答案是最好的,因为它提到了XSS漏洞. (16认同)
  • @PointedEars:2016年谁关心Firefox 12?有问题的是Internet Explorer高达9.0和Safari高达7.0.如果有人能够不支持它们(希望很快就能成为所有人),那么DOMParser就是最好的选择.如果不是 - 是的,处理实体只是一种选择. (4认同)
  • @PointedEars:`<script>`标签没有被执行不是一种安全机制,如果设置`innerHTML`可以运行同步脚本作为副作用,这条规则只是避免了棘手的时间问题.清理HTML代码是一件棘手的事情,而且`innerHTML`甚至没有尝试 - 因为网页实际上可能打算设置内联事件处理程序.这根本不是用于不安全数据的机制,完全停止. (4认同)
  • 请注意(根据您的参考)`DOMParser`在Firefox 12.0之前不支持`"text/html"`,并且[仍然有一些最新版本的浏览器甚至不支持`DOMParser.prototype.parseFromString()`] (http://caniuse.com/#search=domparser).根据你的参考,`DOMParser`仍然是一种实验技术,而替换使用`innerHTML`属性,正如你在回答[我的方法]时指出的那样(http://stackoverflow.com/a/ 12585218/855543),有这个XSS漏洞(应由浏览器供应商修复). (2认同)
  • @ИльяЗеленько:您是否打算在紧密循环中使用此代码,或者为什么性能很重要?你的答案再次容易受到 XSS 攻击,这真的值得吗? (2认同)

CMS*_*CMS 162

我使用以下方法:

function htmlDecode(input){
  var e = document.createElement('textarea');
  e.innerHTML = input;
  // handle case of empty input
  return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}

htmlDecode("&lt;img src='myimage.jpg'&gt;"); 
// returns "<img src='myimage.jpg'>"
Run Code Online (Sandbox Code Playgroud)

基本上我以编程方式创建DOM元素,将编码的HTML分配给其innerHTML,并从innerHTML插入中创建的文本节点中检索nodeValue.由于它只是创建一个元素但从未添加它,因此不会修改任何网站HTML.

它将跨浏览器(包括旧版浏览器)工作并接受所有HTML角色实体.

编辑:此代码的旧版本无法在IE上使用空白输入,如jsFiddle(在IE中查看)中所示.上述版本适用于所有输入.

更新:看起来这不适用于大字符串,它还引入了一个安全漏洞,请参阅注释.

  • 此功能存在安全隐患,即使未将元素添加到DOM,JavaScript代码也会运行.因此,如果输入字符串是可信的,那么这只是使用的东西.我添加了[我自己的答案](/sf/answers/2384510411/)解释问题并提供安全的解决方案.作为副作用,如果存在多个文本节点,则不会切断结果. (21认同)
  • 另见@ kender关于这种方法安全性差的说明. (2认同)
  • 请参阅我对@kender关于他所做的不良测试的说明;) (2认同)

Chr*_*tow 38

如果你正在使用jQuery:

function htmlDecode(value){ 
  return $('<div/>').html(value).text(); 
}
Run Code Online (Sandbox Code Playgroud)

否则,请使用Strictly Software的编码器对象,它具有出色的htmlDecode()功能.

  • 不要(重复NOT)将此用于用户生成的内容,而不是*this*user生成的内容.如果值中有<script>标记,则将执行脚本的内容! (53认同)
  • 是的,该功能为XSS开辟道路:尝试htmlDecode("<script> alert(12)</ script> 123&gt;") (6认同)

Ben*_*ite 9

诀窍是使用浏览器的电源特殊HTML字符解码,而不是让浏览器,如果它是实际的HTML ...此功能使用正则表达式来识别并替换编码的HTML字符执行的结果,一个字符一次.

function unescapeHtml(html) {
    var el = document.createElement('div');
    return html.replace(/\&[#0-9a-z]+;/gi, function (enc) {
        el.innerHTML = enc;
        return el.innerText
    });
}
Run Code Online (Sandbox Code Playgroud)

  • 正则表达式可以与 `/\&amp;#?[0-9a-z]+;/gi` 匹配得更紧一些,因为 # 应该只作为第二个字符出现。 (2认同)
  • 这是最好的答案。避免 XSS 漏洞,并且不剥离 HTML 标签。 (2认同)

Kaj*_*nus 5

CMS的答案很好,除非你想要浏览的HTML很长,超过65536个字符.因为在Chrome中,内部HTML被分成许多子节点,每个子节点最多65536个,并且您需要连接它们.此函数也适用于非常长的字符串:

function unencodeHtmlContent(escapedHtml) {
  var elem = document.createElement('div');
  elem.innerHTML = escapedHtml;
  var result = '';
  // Chrome splits innerHTML into many child nodes, each one at most 65536.
  // Whereas FF creates just one single huge child node.
  for (var i = 0; i < elem.childNodes.length; ++i) {
    result = result + elem.childNodes[i].nodeValue;
  }
  return result;
}
Run Code Online (Sandbox Code Playgroud)

有关innerHTML更多信息,请参阅有关最大长度的答案:https://stackoverflow.com/a/27545633/694469


Łuk*_*z K 5

要在 JavaScript 中转义 HTML 实体*,您可以使用小型库html-escapernpm install html-escaper

import {unescape} from 'html-escaper';

unescape('escaped string');
Run Code Online (Sandbox Code Playgroud)

或者使用LodashUnderscoreunescape的函数(如果您正在使用它)。


*) 请注意,这些函数并不涵盖所有 HTML 实体,而仅涵盖最常见的实体,即&, <, >, ', "。要转义所有 HTML 实体,您可以使用他的库。