我有一些与XML-RPC后端通信的JavaScript代码。 XML-RPC返回如下形式的字符串:

<img src='myimage.jpg'>

然而,当我使用JavaScript将字符串插入到HTML中时,它们会逐字呈现。我看到的不是图像,而是字符串:

<img src='myimage.jpg'>

我猜想HTML是通过XML-RPC通道转义的。

如何在JavaScript中解除字符串转义?我尝试了这个页面上的技巧,但没有成功:http://paulschreiber.com/blog/2008/09/20/javascript-how-to-unescape-html-entities/

诊断这个问题的其他方法是什么?


当前回答

当前投票最多的答案有从字符串中删除HTML的缺点。如果这不是你想要的(这当然不是问题的一部分),那么我建议使用正则表达式来查找HTML实体(/&[^;]*;/gmi),然后遍历匹配并转换它们。

function decodeHTMLEntities(str) { if (typeof str !== 'string') { return false; } var element = document.createElement('div'); return str.replace(/&[^;]*;/gmi, entity => { entity = entity.replace(/</gm, '&lt;'); element.innerHTML = entity; return element.textContent; }); } var encoded_str = `<b>&#8593; &#67;&#65;&#78;'&#84;&nbsp;&#72;&#65;&#67;&#75;&nbsp;&#77;&#69;,&nbsp;&#66;&#82;&#79;</b>`; var decoded_str = decodeHTMLEntities(encoded_str); console.log(decoded_str);

关于XSS攻击:

虽然innerHTML不执行<script>标签中的代码,但有可能在*事件属性中运行代码,因此用户传递的字符串可能会利用上面的正则表达式:

&<img src='asdfa' error='alert(`doin\' me a hack`)' />;

因此,有必要将任何<字符转换为它们的&lt;在将它们放入隐藏的div元素之前。

此外,为了覆盖我所有的基础,我将注意到,在全局作用域中定义的函数可以通过在控制台上重新定义它们来重写,因此使用const定义这个函数或将其放在非全局作用域中非常重要。

注意:以下示例中企图利用的漏洞会使堆栈片段编辑器混淆,因为它所做的预处理,所以您必须在浏览器的控制台中运行它,或者在它自己的文件中运行它才能查看结果。

var tests = [
  "here's a spade: &spades;!",
  "&<script>alert('hackerman')</script>;",
  "&<img src='asdfa' error='alert(`doin\' me a hack`)' />;",
  "<b>&#8593; &#67;&#65;&#78;'&#84;&nbsp;&#72;&#65;&#67;&#75;&nbsp;&#77;&#69;,&nbsp;&#66;&#82;&#79;</b>"
];

var decoded = tests.map(decodeHTMLEntities).join("\n");
console.log(decoded);

结果是:

here's a spade: ♠!
&<script>alert('hackerman')</script>;
&<img src='asdfa' error='alert(`doin' me a hack`)' />;
<b>↑ CAN'T HACK ME, BRO</b>

其他回答

var encodedStr = 'hello &amp; world';

var parser = new DOMParser;
var dom = parser.parseFromString(
    '<!doctype html><body>' + encodedStr,
    'text/html');
var decodedString = dom.body.textContent;

console.log(decodedString);

这里给出的大多数答案都有一个巨大的缺点:如果您试图转换的字符串不受信任,那么您将以跨站点脚本(XSS)漏洞告终。对于已接受答案中的函数,考虑如下:

htmlDecode("<img src='dummy' onerror='alert(/xss/)'>");

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

这可以通过使用所有现代浏览器都支持的DOMParser来避免:

html解码(输入)功能 瓦尔多克=新住户。parseFromString(输入,“短信/ html”); 归来医生。documentElement textContent; 的 控制台.log(htmlDecode(“< img src=‘myimage.jpg’>’) <img src='myimage.jpg'> ' 控制台(htmlDecode(“<img src=‘dummy’on误差=‘alert(/xss/)'>) - "

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

兼容性说明:使用DOMParser解析HTML至少需要Chrome 30、Firefox 12、Opera 17、Internet Explorer 10、Safari 7.1或Microsoft Edge。因此,所有没有支持的浏览器都已经超过了它们的EOL,截至2017年,唯一能在野外看到的是旧的Internet Explorer和Safari版本(通常这些版本仍然不够多)。

如果你正在寻找它,像我一样-同时有一个很好的和安全的JQuery方法。

https://api.jquery.com/jquery.parsehtml/

你可以用f.ex。在控制台中输入以下内容:

var x = "test &amp;";
> undefined
$.parseHTML(x)[0].textContent
> "test &"

因此$. parsehtml (x)返回一个数组,如果文本中有HTML标记,则返回数组。Length大于1。

我知道这里有很多好的答案,但由于我实现了一个有点不同的方法,我想分享一下。

这段代码是一种非常安全的安全方法,因为转义处理程序依赖于浏览器,而不是函数。因此,如果将来发现新的漏洞,将覆盖此解决方案。

const decodeHTMLEntities = text => {
    // Create a new element or use one from cache, to save some element creation overhead
    const el = decodeHTMLEntities.__cache_data_element 
             = decodeHTMLEntities.__cache_data_element 
               || document.createElement('div');
    
    const enc = text
        // Prevent any mixup of existing pattern in text
        .replace(/⪪/g, '⪪#')
        // Encode entities in special format. This will prevent native element encoder to replace any amp characters
        .replace(/&([a-z1-8]{2,31}|#x[0-9a-f]+|#\d+);/gi, '⪪$1⪫');

    // Encode any HTML tags in the text to prevent script injection
    el.textContent = enc;

    // Decode entities from special format, back to their original HTML entities format
    el.innerHTML = el.innerHTML
        .replace(/⪪([a-z1-8]{2,31}|#x[0-9a-f]+|#\d+)⪫/gi, '&$1;')
        .replace(/#⪫/g, '⪫');
   
    // Get the decoded HTML entities
    const dec = el.textContent;
    
    // Clear the element content, in order to preserve a bit of memory (it is just the text may be pretty big)
    el.textContent = '';

    return dec;
}

// Example
console.log(decodeHTMLEntities("<script>alert('&awconint;&CounterClockwiseContourIntegral;&#x02233;&#8755;⪪#x02233⪫');</script>"));
// Prints: <script>alert('∳∳∳∳⪪##x02233⪫');</script>

顺便说一下,我选择使用字符⪪和⪫,因为它们很少被使用,因此通过匹配它们影响性能的几率显著降低。

诀窍是使用浏览器的功能来解码特殊的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
    });
}