Отменить экранирование HTML-объектов в Javascript?

У меня есть код Javascript, который взаимодействует с серверной частью XML-RPC. 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/

Какие еще способы диагностировать проблему?


person Joseph Turian    schedule 16.12.2009    source источник
comment
Огромная функция, включенная в эту статью, кажется, работает нормально: blogs.msdn.com/b/aoakley/archive/2003/11/12/49645.aspx Я не думаю, что это самое умное решение, но оно работает.   -  person Matias    schedule 13.09.2010
comment
Поскольку строки, содержащие объекты HTML, отличаются от escape d или строки в кодировке URI, эти функции не будут работать.   -  person Marcel Korpel    schedule 13.09.2010
comment
@Matias обратите внимание, что новые именованные объекты были добавлены в HTML (например, через спецификацию HTML 5), так как эта функция была создана в 2003 году - например, она не распознает &zopf;. Это проблема развивающейся спецификации; Таким образом, вы должны выбрать инструмент, который действительно поддерживается, чтобы решить эту проблему.   -  person Mark Amery    schedule 19.02.2017
comment
Возможный дубликат Как декодировать объекты HTML с помощью jQuery?   -  person lucascaro    schedule 13.11.2018
comment
Я только что понял, как легко спутать этот вопрос с кодировкой HTML-сущностей. Я только что понял, что случайно отправил ответ на неправильный вопрос по этому вопросу! Но я удалил его.   -  person GalaxyCat105    schedule 25.09.2020


Ответы (31)


РЕДАКТИРОВАТЬ: Вы должны использовать DOMParser API как Владимир предлагает, я отредактировал свой предыдущий ответ, так как опубликованная функция представила уязвимость системы безопасности.

Следующий фрагмент представляет собой старый код ответа с небольшой модификацией: использование textarea вместо div снижает уязвимость XSS, но это по-прежнему проблематично в IE9 и Firefox.

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'>"

В основном я создаю элемент DOM программно, назначаю закодированный HTML его innerHTML и получаю nodeValue из текстового узла, созданного при вставке innerHTML. Поскольку он просто создает элемент, но не добавляет его, HTML-код сайта не изменяется.

Он будет работать в разных браузерах (включая старые браузеры) и принимать все HTML-объекты символов < / а>.

РЕДАКТИРОВАТЬ: старая версия этого кода не работала в IE с пустыми входами, о чем свидетельствует здесь, на jsFiddle (посмотреть в IE). Версия выше работает со всеми входами.

ОБНОВЛЕНИЕ: похоже, это не работает с большой строкой, а также представляет уязвимость безопасности, см. Комментарии.

person Christian C. Salvadó    schedule 16.12.2009
comment
Понятно, вы изменили на ', так что позвольте мне удалить свой комментарий обратно, спасибо, отлично работает, +1 - person YOU; 16.12.2009
comment
@ S.Mark: &apos; не принадлежит к HTML 4 Entities, вот почему! w3.org/TR/html4/sgml/entities.html fishbowl.pastiche.org/2003/07/01/the_curse_of_apos - person Christian C. Salvadó; 16.12.2009
comment
См. Также примечание @kender о плохой безопасности этого подхода. - person Joseph Turian; 16.12.2009
comment
См. Мою заметку к @kender о плохом тестировании, которое он провел;) - person Roatin Marth; 17.12.2009
comment
См. Этот связанный пост в SO: stackoverflow.com/questions/1090056/ ... похоже, что использование innerHTML не подходит по соображениям безопасности. - person Tom Auger; 23.12.2010
comment
@CMS, как мне сделать обратное? - person Adam Lynch; 07.06.2011
comment
@CMS Nevermind. Сортировал мою проблему, кодируя объекты HTML в PHP, а затем используя вашу функцию в JS для декодирования - person Adam Lynch; 08.06.2011
comment
Некоторые тесты jsperf: jsperf.com/decodehtmlclone, если вы декодируете строки в цикле, вы можете подумать о создании только один раз div вне функции декодирования. - person corbacho; 07.02.2013
comment
Что касается комментария безопасности @TomAuger - приведенный выше код не добавляет div в DOM, поэтому ничего не отображается. Он безопасно конвертирует HTML-элементы без экранирования. - person Blazes; 24.07.2013
comment
На самом деле это не работает для очень длинных строк, превышающих 65536 символов в Chrome v39. Затем Chrome разбивает содержимое на множество e.childNodes[*], поэтому нужно перебирать их. Я добавил ответ, который делает это, см. stackoverflow.com/a/27546437/694469 - person KajMagnus; 18.12.2014
comment
Думаю, это вызовет медленную утечку памяти. Вероятно, вы захотите сохранить результат, удалить созданный элемент, а затем вернуть сохраненный результат. - person IAmNaN; 30.03.2015
comment
хорошо, я знаю, что ТАК не любит спасибо! и меня тоже !, но вы спасли мне день: ваш код также работает для чтения javascript внутри элемента ‹pre› ‹/pre› и оценки путем вставки элемента скрипта с javascript в качестве кода. Это то, что я пытался сделать часами ... - person user1251840; 06.08.2015
comment
Эта функция представляет угрозу безопасности, код JavaScript будет работать, даже если элемент не добавлен в DOM. Так что это можно использовать только в том случае, если входной строке доверяют. Я добавил свой ответ, объясняющий проблему и предоставляющий безопасное решение. В качестве побочного эффекта результат не обрезается, если существует несколько текстовых узлов. - person Wladimir Palant; 03.12.2015
comment
Это не работает, если строка уже не экранирована. В моем случае использования иногда строка экранируется, а иногда - нет. Поэтому мне нужен метод, который может принимать любую строку и декодировать ее. Это возможно? - person Kousha; 05.07.2016
comment
Для angular вы можете заключить это в фильтр, например в stackoverflow.com/questions/31412551/. - person Urb Gim Tam; 04.08.2016
comment
@CMS. Можно ли обновить ответ, чтобы он не предлагал небезопасный код, или удалить его, чтобы следующий ответ стал верхним? Надеюсь, я не выгляжу грубым - я бы хотел свести к минимуму риск того, что потенциально опасный код будет скопирован кем-то, не прочитав мелкий шрифт. Мне страшно ссылаться на эту ветку, как сейчас. - person Kos; 25.02.2018
comment
Это не работает, если JS не запущен в браузере, то есть с Node. - person Mattia Rasulo; 31.03.2021

Большинство приведенных здесь ответов имеют огромный недостаток: если строка, которую вы пытаетесь преобразовать, не заслуживает доверия, вы получите Уязвимость межсайтового скриптинга (XSS). Для функции в принятом ответе учтите следующее:

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

Строка здесь содержит неэкранированный HTML-тег, поэтому вместо того, чтобы декодировать что-либо, функция htmlDecode фактически запускает код JavaScript, указанный внутри строки.

Этого можно избежать, используя DOMParser, который поддерживается в все современные браузеры:

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

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

console.log(  htmlDecode("<img src='dummy' onerror='alert(/xss/)'>")  )  
// ""

Эта функция гарантированно не запускает какой-либо код JavaScript в качестве побочного эффекта. Любые HTML-теги будут проигнорированы, будет возвращено только текстовое содержимое.

Примечание о совместимости. Для синтаксического анализа HTML с DOMParser требуется как минимум Chrome 30, Firefox 12, Opera 17, Internet Explorer 10, Safari 7.1 или Microsoft Edge. Таким образом, все браузеры без поддержки давно прошли свой EOL, и по состоянию на 2017 год единственными из них, которые все еще можно увидеть в дикой природе, являются более старые версии Internet Explorer и Safari (обычно их все еще недостаточно, чтобы беспокоиться).

person Wladimir Palant    schedule 03.12.2015
comment
Я думаю, что это лучший ответ, потому что в нем упоминается уязвимость XSS. - person Константин Ван; 30.12.2015
comment
Обратите внимание, что (согласно вашей справке) DOMParser не поддерживал "text/html" до Firefox 12.0, и все еще существуют последние версии браузеры, которые даже не поддерживают DOMParser.prototype.parseFromString(). Согласно вашей ссылке, DOMParser по-прежнему является экспериментальной технологией, а заместители используют свойство innerHTML, которое, как вы также указали в ответ на мой подход имеет эту уязвимость XSS (которая должна быть исправлена ​​поставщиками браузеров). - person PointedEars; 28.02.2016
comment
@PastedEars: Кого волнует Firefox 12 в 2016 году? Проблемными являются Internet Explorer до 9.0 и Safari до 7.0. Если кто-то может позволить себе не поддерживать их (что, надеюсь, скоро будет у всех), то DOMParser - лучший выбор. Если нет - да, возможен вариант только с обрабатывающими объектами. - person Wladimir Palant; 28.02.2016
comment
1. Прочтите, пожалуйста, весь мой комментарий. 2. Вам не обязательно использовать ни то, ни другое, вы можете проводить функциональные тесты. 3. Это не меняет того факта, что если DOMParser недоступен, недостаточно обрабатывать «только объекты». - person PointedEars; 28.02.2016
comment
Поставщики браузеров @PastedEars не могут исправить innerHTML, потому что он работает точно так, как ожидалось: вы даете ему некоторый HTML, и браузер его отображает. Проблема, как говорится, между клавиатурой и стулом: а именно предоставление ему фрагментов HTML, которые не поступают с того же веб-сайта или из другого надежного источника. - person Tobia; 04.08.2016
comment
@Tobia Вы ошибаетесь. Если «script элементы, вставленные с использованием innerHTML, не выполняются при вставке» (см. Ссылку), то по крайней мере определенные значения обработчиков событий тоже не должны выполняться. - person PointedEars; 07.08.2016
comment
@PastedEars: невыполнение тегов <script> не является механизмом безопасности, это правило просто позволяет избежать сложных проблем с синхронизацией, если установка innerHTML может запускать синхронные скрипты в качестве побочного эффекта. Очистка HTML-кода - дело непростое, и innerHTML даже не пытается этого сделать - уже потому, что веб-страница может действительно намереваться установить встроенные обработчики событий. Это просто не механизм, предназначенный для небезопасных данных, точка. - person Wladimir Palant; 07.08.2016
comment
Поскольку ваш код, скорее всего, будет повторно использовать это много раз, избегайте использования new с new DOMParser (). Просто создайте его один раз и укажите экземпляр члена. - person AndroidDev; 27.07.2017
comment
@AndroidDev: Преждевременная оптимизация - это корень всех зол. Я не хочу делать предположений о том, будет ли и как использоваться этот код, и я не хочу поощрять программирование культа карго. - person Wladimir Palant; 29.07.2017
comment
ты хоть представляешь, почему пример newElement.innerHTML = "<img src='dummy' onerror='alert(/xss/)'>"; не работает? Я пробовал это в нескольких браузерах, включая IE6, пытался добавить вызов body.appendChild(newElement), но все равно не смог увидеть предупреждение. - person Dmitry Koroliov; 14.11.2017
comment
@ user907860: Что такое newElement? Если это что-то вроде <textarea> или <script>, содержимое элемента интерпретируется для них по-разному (однако это небезопасно). Кроме того, не будет предупреждений, если вы запустите этот код на about:blank, а не на обычной веб-странице - это как-то связано с тем, как разрешаются относительные URL-адреса, вам придется использовать абсолютный URL-адрес, а не dummy. - person Wladimir Palant; 14.11.2017
comment
newElement - это недавно созданный div из принятого ответа, где он был назван e: var e = document.createElement('div');. Нет, нет about: blank, я использую обычную веб-страницу на локальном сервере. Собственно, спасибо за ответ, сейчас мне этого достаточно, так как если это что-то неожиданное, я, вероятно, задам специальный вопрос чуть позже - person Dmitry Koroliov; 14.11.2017
comment
Это решение, которое действительно работает при оценке строки в документе SVG, который закодирован в IE11. Решение ‹div› НЕ работает, поскольку при задании внутреннего текста дочерние узлы не создаются. Так что я за это решение, поскольку оно работает в более широком смысле. Решение должно работать без каких-либо внешних фреймворков - изначально с тем, что предоставляют браузеры; это отвечает всем требованиям. - person Minok; 02.05.2018
comment
Спасибо, что поделились этим, но использование этого ответа не помогло преобразовать экранированную строку SVG. Не могли бы вы взглянуть? Большое спасибо: stackoverflow.com/questions/54003323/ - person Crashalot; 02.01.2019
comment
@Crashalot: DOMParser также может анализировать XML-код, вам просто нужно изменить тип MIME. Кто-то уже указал вам на это. - person Wladimir Palant; 02.01.2019
comment
Этот код очень медленный! См. мой ответ, где я предоставил доказательства. - person Илья Зеленько; 13.03.2019
comment
@ ИльяЗеленько: Планируете ли вы использовать этот код в жестком цикле или почему производительность имеет значение? Ваш ответ снова уязвим для XSS, действительно ли оно того стоило? - person Wladimir Palant; 13.03.2019
comment
Спасибо, Владимир Палант! Я искал это, оцените пример и объяснение. - person user752746; 11.04.2019
comment
Сработало у меня :) - person Naveen Kumar V; 18.09.2020

Вам нужно декодировать все закодированные объекты HTML или только &amp;?

Если вам нужно только обработать &amp;, вы можете сделать это:

var decoded = encoded.replace(/&amp;/g, '&');

Если вам нужно декодировать все объекты HTML, вы можете сделать это без jQuery:

var elem = document.createElement('textarea');
elem.innerHTML = encoded;
var decoded = elem.value;

Обратите внимание на комментарии Марка ниже, в которых подчеркиваются дыры в безопасности в более ранней версии этого ответа, и рекомендуется использовать textarea, а не div для защиты от потенциальных уязвимостей XSS. Эти уязвимости существуют независимо от того, используете ли вы jQuery или простой JavaScript.

person LukeH    schedule 13.09.2010
comment
Остерегаться! Это потенциально небезопасно. Если encoded='<img src="bla" onerror="alert(1)">', то в приведенном выше фрагменте будет отображаться предупреждение. Это означает, что если ваш закодированный текст поступает от пользователя, его декодирование с помощью этого фрагмента может представлять собой XSS-уязвимость. - person Mark Amery; 10.07.2015
comment
@MarkAmery Я не эксперт по безопасности, но похоже, что если вы сразу установите div на null после получения текста, предупреждение в img не сработает - jsfiddle.net/Mottie/gaBeb/128 - person Mottie; 17.07.2015
comment
@Mottie, обратите внимание, какой браузер у вас работал, но alert(1) у меня по-прежнему запускается в Chrome на OS X. Если вам нужен безопасный вариант этого взлома, попробуйте с textarea. - person Mark Amery; 17.07.2015
comment
+1 для простого регулярного выражения заменить альтернативу только для одного вида html-сущности. Используйте это, если вы ожидаете, что данные html будут интерполированы, скажем, из приложения python flask в шаблон. - person OzzyTheGiant; 02.03.2017
comment
Как это сделать на сервере Node? - person Mohammad Kermani; 27.06.2018
comment
@MohammadKermani: he, entities и html-entities, но это вопрос дубликат stackoverflow.com/questions/1912501/ - person Dan Dascalescu; 01.07.2020

Более современный вариант интерпретации HTML (текста и прочего) из JavaScript - это поддержка HTML в DOMParser API (см. здесь, в MDN). Это позволяет вам использовать собственный HTML-анализатор браузера для преобразования строки в HTML-документ. Он поддерживается в новых версиях всех основных браузеров с конца 2014 года.

Если мы просто хотим декодировать некоторый текстовый контент, мы можем поместить его как единственный контент в тело документа, проанализировать документ и вытащить его .body.textContent.

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);

В черновике спецификации для DOMParser мы видим, что JavaScript не включен для проанализированного документа, поэтому мы можем выполнить это преобразование текста без проблем с безопасностью.

Метод parseFromString(str, type) должен выполнять эти шаги в зависимости от типа:

  • "text/html"

    Разберите str с HTML parser и верните вновь созданный Document.

    Флаг сценария должен быть установлен на «отключено».

    NOTE

    script элементы помечаются как невыполнимые, а содержимое noscript анализируется как разметка.

Это выходит за рамки этого вопроса, но обратите внимание, что если вы берете сами проанализированные узлы DOM (а не только их текстовое содержимое) и перемещаете их в DOM живого документа, возможно, что их сценарии будет повторно включен, и могут возникнуть проблемы с безопасностью. Я не исследовал это, поэтому будьте осторожны.

person Jeremy    schedule 15.02.2017
comment
любая альтернатива для NodeJs? - person zukijuki; 19.08.2017
comment
@coderInrRain: he, entities и html-entities - person Dan Dascalescu; 01.07.2020

У Маттиаса Биненса для этого есть библиотека: 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"

Я предлагаю предпочесть его взломам, связанным с установкой HTML-содержимого элемента и последующим чтением его текстового содержимого. Такие подходы могут работать, но они обманчиво опасны и предоставляют возможности XSS, если используются для ввода ненадежных пользователей.

Если вы действительно не можете загрузить библиотеку, вы можете использовать хак textarea, описанный в этом ответе, чтобы -дуплицированный вопрос, который, в отличие от различных подобных подходов, которые были предложены, не имеет известных мне дыр в безопасности:

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

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

Но обратите внимание на проблемы безопасности, влияющие на аналогичные подходы к этому, которые я перечисляю в связанном ответе! Этот подход является взломом, и будущие изменения допустимого содержимого textarea (или ошибок в определенных браузерах) могут привести к тому, что код, который полагается, что однажды внезапно возникнет дыра XSS.

person Mark Amery    schedule 10.07.2015
comment
Библиотека Матиаса Биненса he просто великолепна! Большое спасибо за рекомендацию! - person Pedro A; 02.02.2018

Если вы используете jQuery:

function htmlDecode(value){ 
  return $('<div/>').html(value).text(); 
}

В противном случае используйте объект кодировщика Strictly Software, который имеет отличную htmlDecode() функцию.

person Chris Fulstow    schedule 16.12.2009
comment
Не (повторяйте НЕ) используйте это для пользовательского контента, кроме контента, созданного этим пользователем. Если в значении есть тег ‹script›, содержимое скрипта будет выполнено! - person Malvolio; 10.12.2010
comment
Я не могу найти лицензию на это нигде на сайте. Вы знаете, что такое лицензия? - person TRiG; 28.03.2011
comment
В заголовке исходного кода есть лицензия, это GPL. - person Chris Fulstow; 02.09.2011
comment
ДА, эта функция открывает путь для XSS: попробуйте htmlDecode (‹script› alert (12) ‹/script› 123) - person Dinis Cruz; 30.08.2012
comment
что означает $ ('‹div /›')? - person Echo Yang; 25.11.2016
comment
@Malvolio И чтобы дать некоторую причину / более глубокое объяснение: это открывает XSS-уязвимость, если сделано для ненадежного ввода! - person rugk; 14.03.2019

var htmlEnDeCode = (function() {
    var charToEntityRegex,
        entityToCharRegex,
        charToEntity,
        entityToChar;

    function resetCharacterEntities() {
        charToEntity = {};
        entityToChar = {};
        // add the default set
        addCharacterEntities({
            '&amp;'     :   '&',
            '&gt;'      :   '>',
            '&lt;'      :   '<',
            '&quot;'    :   '"',
            '&#39;'     :   "'"
        });
    }

    function addCharacterEntities(newEntities) {
        var charKeys = [],
            entityKeys = [],
            key, echar;
        for (key in newEntities) {
            echar = newEntities[key];
            entityToChar[key] = echar;
            charToEntity[echar] = key;
            charKeys.push(echar);
            entityKeys.push(key);
        }
        charToEntityRegex = new RegExp('(' + charKeys.join('|') + ')', 'g');
        entityToCharRegex = new RegExp('(' + entityKeys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
    }

    function htmlEncode(value){
        var htmlEncodeReplaceFn = function(match, capture) {
            return charToEntity[capture];
        };

        return (!value) ? value : String(value).replace(charToEntityRegex, htmlEncodeReplaceFn);
    }

    function htmlDecode(value) {
        var htmlDecodeReplaceFn = function(match, capture) {
            return (capture in entityToChar) ? entityToChar[capture] : String.fromCharCode(parseInt(capture.substr(2), 10));
        };

        return (!value) ? value : String(value).replace(entityToCharRegex, htmlDecodeReplaceFn);
    }

    resetCharacterEntities();

    return {
        htmlEncode: htmlEncode,
        htmlDecode: htmlDecode
    };
})();

Это из исходного кода ExtJS.

person WaiKit Kung    schedule 02.01.2014
comment
-1; это не может обрабатывать подавляющее большинство именованных объектов. Например, htmlEnDecode.htmlDecode('&euro;') должен возвращать '€', но вместо этого возвращает '&euro;'. - person Mark Amery; 19.02.2017

Хитрость заключается в том, чтобы использовать возможности браузера для декодирования специальных символов 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
    });
}
person Ben White    schedule 20.10.2017
comment
Регулярное выражение может быть немного более жестко сопоставлено с /\&#?[0-9a-z]+;/gi, поскольку # должен отображаться только как второй символ, если вообще. - person TheAtomicOption; 09.08.2019
comment
Это лучший ответ. Избегает уязвимости XSS и не удаляет HTML-теги. - person Emmanuel; 19.09.2019

Вы можете использовать функцию Lodash unescape / escape https://lodash.com/docs/4.17.5#unescape

import unescape from 'lodash/unescape';

const str = unescape('fred, barney, &amp; pebbles');

str станет 'fred, barney, & pebbles'

person I am L    schedule 23.02.2018
comment
возможно лучше сделать import _unescape из lodash / unescape; поэтому он не конфликтует с устаревшей функцией javascript с тем же именем: unescape - person Rick Penabella; 20.10.2019

element.innerText тоже делает свое дело.

person avg_joe    schedule 19.11.2012

На случай, если вы его ищете, как и я, тем временем есть хороший и безопасный метод JQuery.

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

Вы можете f.ex. введите это в свою консоль:

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

Итак, $ .parseHTML (x) возвращает массив, и если в вашем тексте есть разметка HTML, array.length будет больше 1.

person cslotty    schedule 14.01.2018
comment
У меня отлично сработало, это было именно то, что я искал, спасибо. - person Jonathan Nielsen; 17.07.2019
comment
Если x имеет значение <script>alert('hello');</script>, произойдет сбой выше. В текущем jQuery он фактически не будет пытаться запустить сценарий, но [0] выдаст undefined, поэтому вызов textContent завершится ошибкой, и ваш сценарий остановится на этом. $('<div />').html(x).text(); выглядит безопаснее - через gist.github.com/jmblog/3222899 - person Andrew Hodgkinson; 13.08.2019
comment
@AndrewHodgkinson да, но вопрос заключался в том, чтобы декодировать обратно в & в JavaScript, поэтому вы должны сначала протестировать содержимое x или убедиться, что вы используете его только в правильных случаях. - person cslotty; 05.12.2019
comment
Я действительно не понимаю, как это следует. Приведенный выше код работает во всех случаях. И как именно убедиться, что значение x нуждается в исправлении? А что, если приведенный выше пример сценария предупредил '', так что это действительно нужно исправить? Мы не знаем, откуда берутся строки OP, поэтому необходимо учитывать злонамеренный ввод. - person Andrew Hodgkinson; 07.12.2019
comment
@AndrewHodgkinson Мне нравится ваше внимание, но вопрос не в этом. Однако не стесняйтесь ответить на этот вопрос. Я думаю, вы могли бы удалить теги скрипта, например. - person cslotty; 07.12.2019
comment
@AndrewHodgkinson, ваше решение работает безупречно! вам следует подумать, чтобы ответить на этот вопрос с его помощью. Красиво, ясно, коротко и эффективно. +1 - person Sergio A.; 11.03.2020
comment
@SergioA. Спасибо, готово: stackoverflow.com/a/60645505 - person Andrew Hodgkinson; 12.03.2020

jQuery будет кодировать и декодировать за вас. Однако вам нужно использовать тег textarea, а не div.

var str1 = 'One & two & three';
var str2 = "One &amp; two &amp; three";
  
$(document).ready(function() {
   $("#encoded").text(htmlEncode(str1)); 
   $("#decoded").text(htmlDecode(str2));
});

function htmlDecode(value) {
  return $("<textarea/>").html(value).text();
}

function htmlEncode(value) {
  return $('<textarea/>').text(value).html();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<div id="encoded"></div>
<div id="decoded"></div>

person Jason Williams    schedule 28.09.2016
comment
-1, потому что здесь есть (неожиданная) дыра в безопасности для старых версий jQuery, некоторые из которых, вероятно, все еще имеют значительную базу пользователей - эти версии будут обнаруживать и явно оценивать сценарии в HTML, переданном в .html(). Таким образом, даже использования textarea недостаточно для обеспечения безопасности; Я предлагаю не использовать jQuery для этой задачи и написать эквивалентный код с простым DOM API. (Да, такое старое поведение jQuery безумно и ужасно.) - person Mark Amery; 19.02.2017
comment
Спасибо, что указали на это. Однако вопрос не включает требование проверки внедрения сценария. Вопрос конкретно касается HTML, отображаемого веб-сервером. Html-контент, сохраненный на веб-сервере, вероятно, должен быть проверен для внедрения сценария перед сохранением. - person Jason Williams; 23.02.2017

Ответ 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;
}

См. Этот ответ о максимальной длине innerHTML для получения дополнительной информации: https://stackoverflow.com/a/27545633/694469

person KajMagnus    schedule 18.12.2014

Сначала создайте <span id="decodeIt" style="display:none;"></span> где-нибудь в теле

Затем назначьте строку для декодирования как innerHTML этому:

document.getElementById("decodeIt").innerHTML=stringtodecode

Наконец-то,

stringtodecode=document.getElementById("decodeIt").innerText

Вот общий код:

var stringtodecode="<B>Hello</B> world<br>";
document.getElementById("decodeIt").innerHTML=stringtodecode;
stringtodecode=document.getElementById("decodeIt").innerText
person Infoglaze.com    schedule 09.01.2013
comment
-1; это опасно небезопасно для использования с ненадежным вводом. Например, подумайте, что произойдет, если stringtodecode содержит что-то вроде <script>alert(1)</script>. - person Mark Amery; 19.02.2017

Это не прямой ответ на ваш вопрос, но не лучше ли было бы, чтобы ваш RPC возвращал некоторую структуру (будь то XML, JSON или что-то еще) с этими данными изображения (URL-адреса в вашем примере) внутри этой структуры?

Затем вы можете просто проанализировать его в своем javascript и построить <img>, используя сам javascript.

Структура, которую вы получаете от RPC, может выглядеть так:

{"img" : ["myimage.jpg", "myimage2.jpg"]}

Я думаю, что так лучше, поскольку внедрение кода, поступающего из внешнего источника, на вашу страницу не выглядит очень безопасным. Представьте, что кто-то захватывает ваш XML-RPC скрипт и помещает туда то, что вам не нужно (даже какой-то javascript ...)

person kender    schedule 16.12.2009
comment
Имеет ли описанный выше подход @CMS этот недостаток безопасности? - person Joseph Turian; 16.12.2009
comment
Я только что проверил следующий аргумент, переданный функции htmlDecode: htmlDecode (img src = 'myimage.jpg'scriptdocument.write (' xxxxx '); / script), и он создает элемент ‹script› ‹/script›, который может быть плохим, ИМХО. И я по-прежнему считаю, что лучше возвращать структуру вместо вставляемого текста, например, вы можете хорошо обрабатывать ошибки. - person kender; 16.12.2009
comment
Я просто попробовал htmlDecode("&lt;img src='myimage.jpg'&gt;&lt;script&gt;alert('xxxxx');&lt;/script&gt;"), и ничего не вышло. Я вернул декодированную строку html, как и ожидал. - person Roatin Marth; 17.12.2009

Для однолинейных парней:

const htmlDecode = innerHTML => Object.assign(document.createElement('textarea'), {innerHTML}).value;

console.log(htmlDecode('Complicated - Dimitri Vegas &amp; Like Mike'));
person Ninh Pham    schedule 28.07.2017

Не за что ... просто мессенджер ... все заслуги передаются на ourcodeworld.com, ссылка ниже.

window.htmlentities = {
        /**
         * Converts a string to its html characters completely.
         *
         * @param {String} str String with unescaped HTML characters
         **/
        encode : function(str) {
            var buf = [];

            for (var i=str.length-1;i>=0;i--) {
                buf.unshift(['&#', str[i].charCodeAt(), ';'].join(''));
            }

            return buf.join('');
        },
        /**
         * Converts an html characterSet into its original character.
         *
         * @param {String} str htmlSet entities
         **/
        decode : function(str) {
            return str.replace(/&#(\d+);/g, function(match, dec) {
                return String.fromCharCode(dec);
            });
        }
    };

Полный кредит: https://ourcodeworld.com/articles/read/188/encode-and-decode-html-entities-using-pure-javascript.

person decoder7283    schedule 05.08.2019

Ответ Криса красивый и элегантный, но он терпит неудачу, если значение равно undefined. Простое улучшение делает его прочным:

function htmlDecode(value) {
   return (typeof value === 'undefined') ? '' : $('<div/>').html(value).text();
}
person nerijus    schedule 26.06.2012
comment
Если улучшится, то сделайте: return (typeof value !== 'string') ? '' : $('<div/>').html(value).text(); - person SynCap; 26.06.2017

решение javascript, которое улавливает общие:

var map = {amp: '&', lt: '<', gt: '>', quot: '"', '#039': "'"}
str = str.replace(/&([^;]+);/g, (m, c) => map[c])

это противоположно https://stackoverflow.com/a/4835406/2738039

person Peter Brandt    schedule 07.10.2016
comment
Если вы используете map[c] || '' нераспознанные, не будут отображаться как undefined - person Eldelshell; 07.01.2017
comment
Очень ограниченное покрытие; -1. - person Mark Amery; 19.02.2017
comment
+1, еще unescapeHtml(str){ var map = {amp: '&', lt: '<', le: '≤', gt: '>', ge: '≥', quot: '"', '#039': "'"} return str.replace(/&([^;]+);/g, (m, c) => map[c]|| '') } - person Trần Quốc Hoài new 2015; 22.09.2017
comment
Ручное покрытие. Не рекомендуется. - person Sergio A.; 11.03.2020

Я был достаточно сумасшедшим, чтобы пройти и сделать эту функцию, которая должна быть довольно, если не полностью, исчерпывающей:

function removeEncoding(string) {
    return string.replace(/&Agrave;/g, "À").replace(/&Aacute;/g, "Á").replace(/&Acirc;/g, "Â").replace(/&Atilde;/g, "Ã").replace(/&Auml;/g, "Ä").replace(/&Aring;/g, "Å").replace(/&agrave;/g, "à").replace(/&acirc;/g, "â").replace(/&atilde;/g, "ã").replace(/&auml;/g, "ä").replace(/&aring;/g, "å").replace(/&AElig;/g, "Æ").replace(/&aelig;/g, "æ").replace(/&szlig;/g, "ß").replace(/&Ccedil;/g, "Ç").replace(/&ccedil;/g, "ç").replace(/&Egrave;/g, "È").replace(/&Eacute;/g, "É").replace(/&Ecirc;/g, "Ê").replace(/&Euml;/g, "Ë").replace(/&egrave;/g, "è").replace(/&eacute;/g, "é").replace(/&ecirc;/g, "ê").replace(/&euml;/g, "ë").replace(/&#131;/g, "ƒ").replace(/&Igrave;/g, "Ì").replace(/&Iacute;/g, "Í").replace(/&Icirc;/g, "Î").replace(/&Iuml;/g, "Ï").replace(/&igrave;/g, "ì").replace(/&iacute;/g, "í").replace(/&icirc;/g, "î").replace(/&iuml;/g, "ï").replace(/&Ntilde;/g, "Ñ").replace(/&ntilde;/g, "ñ").replace(/&Ograve;/g, "Ò").replace(/&Oacute;/g, "Ó").replace(/&Ocirc;/g, "Ô").replace(/&Otilde;/g, "Õ").replace(/&Ouml;/g, "Ö").replace(/&ograve;/g, "ò").replace(/&oacute;/g, "ó").replace(/&ocirc;/g, "ô").replace(/&otilde;/g, "õ").replace(/&ouml;/g, "ö").replace(/&Oslash;/g, "Ø").replace(/&oslash;/g, "ø").replace(/&#140;/g, "Œ").replace(/&#156;/g, "œ").replace(/&#138;/g, "Š").replace(/&#154;/g, "š").replace(/&Ugrave;/g, "Ù").replace(/&Uacute;/g, "Ú").replace(/&Ucirc;/g, "Û").replace(/&Uuml;/g, "Ü").replace(/&ugrave;/g, "ù").replace(/&uacute;/g, "ú").replace(/&ucirc;/g, "û").replace(/&uuml;/g, "ü").replace(/&#181;/g, "µ").replace(/&#215;/g, "×").replace(/&Yacute;/g, "Ý").replace(/&#159;/g, "Ÿ").replace(/&yacute;/g, "ý").replace(/&yuml;/g, "ÿ").replace(/&#176;/g, "°").replace(/&#134;/g, "†").replace(/&#135;/g, "‡").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&#177;/g, "±").replace(/&#171;/g, "«").replace(/&#187;/g, "»").replace(/&#191;/g, "¿").replace(/&#161;/g, "¡").replace(/&#183;/g, "·").replace(/&#149;/g, "•").replace(/&#153;/g, "™").replace(/&copy;/g, "©").replace(/&reg;/g, "®").replace(/&#167;/g, "§").replace(/&#182;/g, "¶").replace(/&Alpha;/g, "Α").replace(/&Beta;/g, "Β").replace(/&Gamma;/g, "Γ").replace(/&Delta;/g, "Δ").replace(/&Epsilon;/g, "Ε").replace(/&Zeta;/g, "Ζ").replace(/&Eta;/g, "Η").replace(/&Theta;/g, "Θ").replace(/&Iota;/g, "Ι").replace(/&Kappa;/g, "Κ").replace(/&Lambda;/g, "Λ").replace(/&Mu;/g, "Μ").replace(/&Nu;/g, "Ν").replace(/&Xi;/g, "Ξ").replace(/&Omicron;/g, "Ο").replace(/&Pi;/g, "Π").replace(/&Rho;/g, "Ρ").replace(/&Sigma;/g, "Σ").replace(/&Tau;/g, "Τ").replace(/&Upsilon;/g, "Υ").replace(/&Phi;/g, "Φ").replace(/&Chi;/g, "Χ").replace(/&Psi;/g, "Ψ").replace(/&Omega;/g, "Ω").replace(/&alpha;/g, "α").replace(/&beta;/g, "β").replace(/&gamma;/g, "γ").replace(/&delta;/g, "δ").replace(/&epsilon;/g, "ε").replace(/&zeta;/g, "ζ").replace(/&eta;/g, "η").replace(/&theta;/g, "θ").replace(/&iota;/g, "ι").replace(/&kappa;/g, "κ").replace(/&lambda;/g, "λ").replace(/&mu;/g, "μ").replace(/&nu;/g, "ν").replace(/&xi;/g, "ξ").replace(/&omicron;/g, "ο").replace(/&piρ;/g, "ρ").replace(/&rho;/g, "ς").replace(/&sigmaf;/g, "ς").replace(/&sigma;/g, "σ").replace(/&tau;/g, "τ").replace(/&phi;/g, "φ").replace(/&chi;/g, "χ").replace(/&psi;/g, "ψ").replace(/&omega;/g, "ω").replace(/&bull;/g, "•").replace(/&hellip;/g, "…").replace(/&prime;/g, "′").replace(/&Prime;/g, "″").replace(/&oline;/g, "‾").replace(/&frasl;/g, "⁄").replace(/&weierp;/g, "℘").replace(/&image;/g, "ℑ").replace(/&real;/g, "ℜ").replace(/&trade;/g, "™").replace(/&alefsym;/g, "ℵ").replace(/&larr;/g, "←").replace(/&uarr;/g, "↑").replace(/&rarr;/g, "→").replace(/&darr;/g, "↓").replace(/&barr;/g, "↔").replace(/&crarr;/g, "↵").replace(/&lArr;/g, "⇐").replace(/&uArr;/g, "⇑").replace(/&rArr;/g, "⇒").replace(/&dArr;/g, "⇓").replace(/&hArr;/g, "⇔").replace(/&forall;/g, "∀").replace(/&part;/g, "∂").replace(/&exist;/g, "∃").replace(/&empty;/g, "∅").replace(/&nabla;/g, "∇").replace(/&isin;/g, "∈").replace(/&notin;/g, "∉").replace(/&ni;/g, "∋").replace(/&prod;/g, "∏").replace(/&sum;/g, "∑").replace(/&minus;/g, "−").replace(/&lowast;/g, "∗").replace(/&radic;/g, "√").replace(/&prop;/g, "∝").replace(/&infin;/g, "∞").replace(/&OEig;/g, "Œ").replace(/&oelig;/g, "œ").replace(/&Yuml;/g, "Ÿ").replace(/&spades;/g, "♠").replace(/&clubs;/g, "♣").replace(/&hearts;/g, "♥").replace(/&diams;/g, "♦").replace(/&thetasym;/g, "ϑ").replace(/&upsih;/g, "ϒ").replace(/&piv;/g, "ϖ").replace(/&Scaron;/g, "Š").replace(/&scaron;/g, "š").replace(/&ang;/g, "∠").replace(/&and;/g, "∧").replace(/&or;/g, "∨").replace(/&cap;/g, "∩").replace(/&cup;/g, "∪").replace(/&int;/g, "∫").replace(/&there4;/g, "∴").replace(/&sim;/g, "∼").replace(/&cong;/g, "≅").replace(/&asymp;/g, "≈").replace(/&ne;/g, "≠").replace(/&equiv;/g, "≡").replace(/&le;/g, "≤").replace(/&ge;/g, "≥").replace(/&sub;/g, "⊂").replace(/&sup;/g, "⊃").replace(/&nsub;/g, "⊄").replace(/&sube;/g, "⊆").replace(/&supe;/g, "⊇").replace(/&oplus;/g, "⊕").replace(/&otimes;/g, "⊗").replace(/&perp;/g, "⊥").replace(/&sdot;/g, "⋅").replace(/&lcell;/g, "⌈").replace(/&rcell;/g, "⌉").replace(/&lfloor;/g, "⌊").replace(/&rfloor;/g, "⌋").replace(/&lang;/g, "⟨").replace(/&rang;/g, "⟩").replace(/&loz;/g, "◊").replace(/&#039;/g, "'").replace(/&amp;/g, "&").replace(/&quot;/g, "\"");
}

Используется так:

let decodedText = removeEncoding("Ich hei&szlig;e David");
console.log(decodedText);

Отпечатки: Ich Heiße David

P.S. это заняло около полутора часов.

person David Chopin    schedule 25.11.2019

Это наиболее полное решение, которое я пробовал до сих пор:

const STANDARD_HTML_ENTITIES = {
    nbsp: String.fromCharCode(160),
    amp: "&",
    quot: '"',
    lt: "<",
    gt: ">"
};

const replaceHtmlEntities = plainTextString => {
    return plainTextString
        .replace(/&#(\d+);/g, (match, dec) => String.fromCharCode(dec))
        .replace(
            /&(nbsp|amp|quot|lt|gt);/g,
            (a, b) => STANDARD_HTML_ENTITIES[b]
        );
};
person Daniel    schedule 13.02.2020
comment
Самый полный? Вы пробовали запустить его с действительно всеобъемлющим набором тестов? - person Dan Dascalescu; 01.07.2020

В вопросе не указано происхождение x, но имеет смысл защитить, если мы можем, от злонамеренного (или просто неожиданного, из нашего собственного приложения) ввода. Например, предположим, что x имеет значение &amp; <script>alert('hello');</script>. Безопасный и простой способ справиться с этим в jQuery:

var x    = "&amp; <script>alert('hello');</script>";
var safe = $('<div />').html(x).text();

// => "& alert('hello');"

Найдено через https://gist.github.com/jmblog/3222899. Я не вижу многих причин избегать использования этого решения, учитывая, что оно по крайней мере такое же, если не короче, чем некоторые альтернативы и, обеспечивающие защиту от XSS.

(Изначально я разместил это как комментарий, но добавляю его как ответ, так как последующий комментарий в том же потоке потребовал, чтобы я это сделал).

person Andrew Hodgkinson    schedule 11.03.2020

Чтобы отключить экранирование HTML-объектов * в JavaScript, вы можете использовать небольшую библиотеку html-escaper: npm install html-escaper

import {unescape} from 'html-escaper';

unescape('escaped string');

Или unescape функцию из Lodash или Underscore, если вы его используете.


*) обратите внимание, что эти функции охватывают не все объекты HTML, а только наиболее распространенные, то есть &, <, >, ', ". Чтобы отключить экранирование всех HTML-объектов, вы можете использовать библиотеку he.

person Łukasz K    schedule 07.07.2020

Я пробовал все, чтобы удалить & из массива JSON. Ни один из приведенных выше примеров, но https://stackoverflow.com/users/2030321/chris дал отличное решение, которое привело мне исправить мою проблему.

var stringtodecode="<B>Hello</B> world<br>";
document.getElementById("decodeIt").innerHTML=stringtodecode;
stringtodecode=document.getElementById("decodeIt").innerText

Я не использовал, потому что не понимал, как вставить его в модальное окно, которое вытягивает данные JSON в массив, но я попробовал это на основе примера, и это сработало:

var modal = document.getElementById('demodal');
$('#ampersandcontent').text(replaceAll(data[0],"&amp;", "&"));

Мне он нравится, потому что он простой и работает, но не уверен, почему он не используется широко. Поискал по всем пунктам, чтобы найти простое решение. Я продолжаю искать понимание синтаксиса, и есть ли риск его использования. Пока ничего не нашел.

person Digexart    schedule 13.12.2018
comment
Ваше первое предложение немного сложно, но оно работает без особых усилий. Второй, напротив, использует только грубую силу для декодирования символов; это означает, что для выполнения функции полного декодирования может потребоваться ОЧЕНЬ много усилий и времени. Вот почему никто не использует этот способ для решения проблемы OP. - person Sergio A.; 11.03.2020

Замыкания позволяют избежать создания ненужных объектов.

const decodingHandler = (() => {
  const element = document.createElement('div');
  return text => {
    element.innerHTML = text;
    return element.textContent;
  };
})();

Более лаконичный способ

const decodingHandler = (() => {
  const element = document.createElement('div');
  return text => ((element.innerHTML = text), element.textContent);
})();
person weiya ou    schedule 29.10.2020

Я знаю, что здесь есть много хороших ответов, но, поскольку я реализовал немного другой подход, я решил поделиться.

Этот код представляет собой совершенно безопасный подход с точки зрения безопасности, поскольку обработчик экранирования зависит от браузера, а не от функции. Таким образом, если в будущем будет обнаружена новая уязвимость, это решение будет покрыто.

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>

Кстати, я решил использовать символы и , потому что они используются редко, поэтому вероятность влияния на производительность путем сопоставления их значительно ниже.

person Slavik Meltser    schedule 28.04.2021

Я использую это в своем проекте: вдохновленный другими ответами, но с дополнительным параметром безопасности, может быть полезно, когда вы имеете дело с украшенными персонажами

var decodeEntities=(function(){

    var el=document.createElement('div');
    return function(str, safeEscape){

        if(str && typeof str === 'string'){

            str=str.replace(/\</g, '&lt;');

            el.innerHTML=str;
            if(el.innerText){

                str=el.innerText;
                el.innerText='';
            }
            else if(el.textContent){

                str=el.textContent;
                el.textContent='';
            }

            if(safeEscape)
                str=str.replace(/\</g, '&lt;');
        }
        return str;
    }
})();

И его можно использовать как:

var label='safe <b> character &eacute;ntity</b>';
var safehtml='<div title="'+decodeEntities(label)+'">'+decodeEntities(label, true)+'</div>';
person tmx976    schedule 14.07.2017

У всех остальных ответов здесь есть проблемы.

Методы document.createElement ('div') (включая те, которые используют jQuery) выполняют любой переданный в него javascript (проблема безопасности), а метод DOMParser.parseFromString () удаляет пробелы. Вот чистое решение javascript, у которого нет ни одной проблемы:

function htmlDecode(html) {
    var textarea = document.createElement("textarea");
    html= html.replace(/\r/g, String.fromCharCode(0xe000)); // Replace "\r" with reserved unicode character.
    textarea.innerHTML = html;
    var result = textarea.value;
    return result.replace(new RegExp(String.fromCharCode(0xe000), 'g'), '\r');
}

TextArea используется специально, чтобы избежать выполнения кода js. Он передает эти:

htmlDecode('&lt;&amp;&nbsp;&gt;'); // returns "<& >" with non-breaking space.
htmlDecode('  '); // returns "  "
htmlDecode('<img src="dummy" onerror="alert(\'xss\')">'); // Does not execute alert()
htmlDecode('\r\n') // returns "\r\n", doesn't lose the \r like other solutions.
person EricP    schedule 24.09.2017
comment
Нет, использование другого тега не решает проблему. Это все еще XSS-уязвимость, попробуйте htmlDecode("</textarea><img src=x onerror=alert(1)>"). Вы разместили это после того, как я уже указывал на эту проблему в ответе Серджио Белевского. - person Wladimir Palant; 18.09.2018
comment
Я не могу воспроизвести описанную вами проблему. У меня есть ваш код в этом JsFiddle, и при запуске не отображается никаких предупреждений. jsfiddle.net/edsjt15g/1 Вы можете взглянуть? Какой браузер вы используете? - person EricP; 19.09.2018
comment
Я использую Firefox. Chrome действительно обрабатывает этот сценарий по-разному, поэтому код не выполняется - однако на это не стоит полагаться. - person Wladimir Palant; 19.09.2018

Есть вариант, который на 80% продуктивнее ответов на самом верху.

См. Тест: https://jsperf.com/decode-html12345678/1

тест производительности

console.log(decodeEntities('test: &gt'));

function decodeEntities(str) {
  // this prevents any overhead from creating the object each time
  const el = decodeEntities.element || document.createElement('textarea')

  // strip script/html tags
  el.innerHTML = str
    .replace(/<script[^>]*>([\S\s]*?)<\/script>/gmi, '')
    .replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gmi, '');

  return el.value;
}

Если вам нужно оставить теги, то удалите два вызова .replace(...) (вы можете оставить первый, если вам не нужны скрипты).

person Илья Зеленько    schedule 13.03.2019
comment
Поздравляем, вам удалось скрыть уязвимость с помощью фиктивной логики дезинфекции, и все это для повышения производительности, которое на практике не имеет значения. Попробуйте позвонить decodeEntities("</textarea '><img src=x onerror=alert(1) \">") в Firefox. Пожалуйста, прекратите попытки дезинфицировать HTML-код с помощью регулярных выражений. - person Wladimir Palant; 14.03.2019

person    schedule
comment
@ Владимир Палант (автор AdBlock Plus) уже дал ответ DOMParser 4 года раньше. Вы читали предыдущие ответы перед тем, как опубликовать свой? - person Dan Dascalescu; 01.07.2020

person    schedule
comment
Чем этот ответ лучше, чем textarea ответ, данный лет назад? - person Dan Dascalescu; 01.07.2020