Как показать escapeHTML4 строку в unescaped формате [duplicate]

По вопросу «что мне делать с этим» может быть много ответов.

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

Короче говоря, инварианты класса гарантируют, что в вашем классе будут некоторые ограничения, которые не будут нарушены при нормальном использовании (и, следовательно, класс будет not получить в несогласованном состоянии). Предпосылки означают, что данные, данные как входные данные для функции / метода, должны соответствовать установленным ограничениям и никогда не нарушать их, а постулаты означают, что вывод функции / метода должен соответствовать установленным ограничениям снова не нарушая их. Условия контракта никогда не должны нарушаться во время выполнения программы без ошибок, поэтому дизайн по контракту проверяется на практике в режиме отладки, а отключен в выпусках , чтобы максимизировать развитую производительность системы.

Таким образом, вы можете избежать случаев NullReferenceException, которые являются результатом нарушения установленных ограничений. Например, если вы используете свойство объекта X в классе, а затем попытаетесь вызвать один из его методов, а X имеет нулевое значение, то это приведет к NullReferenceException:

public X { get; set; }

public void InvokeX()
{
    X.DoSomething(); // if X value is null, you will get a NullReferenceException
}

Но если вы установите «свойство X никогда не должно иметь нулевого значения» в качестве предпосылки для метода, вы можете предотвратить описанный ранее сценарий:

//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant () 
{
    Contract.Invariant ( X != null );
    //...
}

По этой причине Код Контракт существует для приложений .NET.

В качестве альтернативы дизайн по контракту может быть применен с использованием утверждений .

ОБНОВЛЕНИЕ: Стоит отметить, что этот термин был придуман Бертраном Майером в связи с его дизайном языка программирования Эйфеля .

103
задан Joseph Turian 16 December 2009 в 06:27
поделиться

9 ответов

Я использую следующий метод:

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

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

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

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

EDIT: старая версия этого кода не работала на IE с пустыми вводами, о чем свидетельствует здесь, в jsFiddle (просмотр в IE). Версия выше работает со всеми входами.

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

148
ответ дан Smallhacker 27 August 2018 в 21:49
поделиться
  • 1
    Получил это, вы изменили на ', поэтому позвольте мне удалить мой комментарий назад, thx, его отлично работает, +1 – YOU 16 December 2009 в 06:41
  • 2
    @ S.Mark: &apos; не принадлежит к элементам HTML 4, вот почему! w3.org/TR/html4/sgml/entities.html fishbowl.pastiche.org/2003/07/01/the_curse_of_apos – CMS 16 December 2009 в 06:48
  • 3
    См. Также примечание @ kender о плохой безопасности этого подхода. – Joseph Turian 16 December 2009 в 21:52
  • 4
    См. Мою записку @kender о плохом тестировании, которое он сделал;) – Roatin Marth 16 December 2009 в 22:08
  • 5
    Эта функция является угрозой безопасности, JavaScript-код будет работать даже несмотря на то, что элемент не добавлен в DOM. Таким образом, это только то, что нужно использовать, если входная строка является надежной. Я добавил мой собственный ответ , объясняющий проблему и обеспечивающий безопасное решение. В качестве побочного эффекта результат не прерывается, если существует несколько текстовых узлов. – Wladimir Palant 3 December 2015 в 12:13

Хитрость заключается в использовании мощности браузера для декодирования специальных символов 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
    });
}
5
ответ дан Ben White 27 August 2018 в 21:49
поделиться

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

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

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

39
ответ дан Chris Fulstow 27 August 2018 в 21:49
поделиться
  • 1
    Не используйте (повторите NOT) это для созданного пользователем контента, кроме контента, сгенерированного пользователем this . Если есть & lt; script & gt; тега в значении, содержимое скрипта будет выполнено! – Malvolio 10 December 2010 в 20:00
  • 2
    Я не могу найти лицензию на это где угодно на сайте. Вы знаете, что такое лицензия? – TRiG 28 March 2011 в 15:24
  • 3
    В заголовке источника есть лицензия, это GPL. – Chris Fulstow 1 September 2011 в 23:06
  • 4
    ДА, эта функция открывает путь для XSS: попробуйте htmlDecode (& quot; & lt; script & gt; alert (12) & lt; / script & gt; 123 & amp; gt; ") – Dinis Cruz 30 August 2012 в 12:16
  • 5
    что означает $ ('& lt; div / & gt;') ? – Echo Yang 25 November 2016 в 07:49

Это лучше:

String::decode = ->
   $('<textarea />').html(this).text()

use:

"&lt;img src='myimage.jpg'&gt;".decode();

from: HTML Entity Decode

4
ответ дан Community 27 August 2018 в 21:49
поделиться
  • 1
    Это довольно умно. Вот чистая версия JS: stackoverflow.com/a/7394787/290790 Вы можете использовать String.prototype.decode = function ..., чтобы использовать его таким же образом. – qwerty 22 October 2016 в 15:51
  • 2
    Это по сути тот же ответ, что и тот, который был опубликован Крисом Фулстоу семь лет назад - и с теми же недостатками безопасности. – Wladimir Palant 17 May 2017 в 11:31
  • 3
    @Kaiido: Нет, это то же самое, просто с крошечным поворот. См. этот скрипт , он будет запускать код JavaScript из поставляемой строки. Метод jQuery html() небезопасен, независимо от того, где вы его используете. – Wladimir Palant 29 August 2017 в 06:57

Все остальные ответы здесь имеют проблемы.

Методы 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 используется специально, чтобы избежать выполнения кода jscript. Он передает следующее:

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.
1
ответ дан Dwayne 27 August 2018 в 21:49
поделиться

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

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

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

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

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

3
ответ дан kender 27 August 2018 в 21:49
поделиться
  • 1
    У подхода @CMS выше есть этот недостаток безопасности? – Joseph Turian 16 December 2009 в 07:30
  • 2
    Я просто проверил следующий аргумент, переданный в htmlDecode fuction: htmlDecode (& amp; lt; img src = 'myimage.jpg' & amp; lt; script & amp; gt; document.write ('xxxxx'); & amp; lt; / script & amp; gt; "), и он создает & lt; script & gt; & lt; / script & gt; элемент, который может быть плохим, imho. И я все же думаю, что возвращение структуры вместо текста, который нужно вставить, лучше, вы можете обрабатывать ошибки, например, красиво. – kender 16 December 2009 в 08:06
  • 3
    Я просто попробовал htmlDecode("&lt;img src='myimage.jpg'&gt;&lt;script&gt;alert('xxxxx');&lt;/script&gt;"), и ничего не произошло. Я получил декодированную строку html как ожидалось. – Roatin Marth 16 December 2009 в 22:05
  • 4
    а затем, если вы вставляете эту строку в DOM, вы выполняете скрипт ... – Metagrapher 12 April 2012 в 03:51

Крис отвечает хорошо и amp; но он терпит неудачу, если значение undefined . Простое улучшение делает его твердым:

function htmlDecode(value) {
   return (typeof value === 'undefined') ? '' : $('<div/>').html(value).text();
}
4
ответ дан nerijus 27 August 2018 в 21:49
поделиться
  • 1
    Если это улучшится, тогда выполните: return (typeof value !== 'string') ? '' : $('<div/>').html(value).text(); – SynCap 26 June 2017 в 08:09

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

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>';
0
ответ дан tmx976 27 August 2018 в 21:49
поделиться

Большинство ответов, приведенных здесь, имеют огромный недостаток: если строка, которую вы пытаетесь преобразовать, не доверяет, вы получите уязвимость Cross-Site Scripting (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;
}

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

// This returns ""
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 (как правило, они все еще недостаточно многочисленны, чтобы беспокоиться).

195
ответ дан Wladimir Palant 27 August 2018 в 21:49
поделиться
  • 1
    Это заслуживает большего внимания – rink.attendant.6 15 December 2015 в 04:39
  • 2
    Я считаю, что этот ответ является лучшим, потому что он упоминает об уязвимости XSS. – K._ 30 December 2015 в 19:04
  • 3
    Обратите внимание, что (согласно вашей ссылке) DOMParser не поддерживал "text/html" до Firefox 12.0, а все еще есть некоторые последние версии браузеров, которые даже не поддерживают DOMParser.prototype.parseFromString() . Согласно вашей рекомендации, DOMParser все еще является экспериментальной технологией, а в режиме ожидания используется свойство innerHTML, которое, как вы также указали в ответ на мой подход , имеет эту уязвимость XSS ( которые должны быть исправлены поставщиками браузеров). – PointedEars 28 February 2016 в 09:53
  • 4
    @PointedEars: Кто заботится о Firefox 12 в 2016 году? Проблемными являются Internet Explorer до 9.0 и Safari до 7.0. Если кто-то может позволить себе не поддерживать их (что, надеюсь, будет всем скоро), то DOMParser - лучший выбор. Если нет - да, обрабатывающие объекты будут только вариантом. – Wladimir Palant 28 February 2016 в 13:43
  • 5
    @PointedEars: теги <script>, которые не выполняются, не являются механизмом безопасности, это правило просто избегает сложных проблем синхронизации, если установка innerHTML может запускать синхронные скрипты в качестве побочного эффекта. Санитарный код HTML - это сложное дело, а innerHTML даже не пытается - уже потому, что веб-страница может на самом деле намереваться установить встроенные обработчики событий. Это просто не механизм, предназначенный для небезопасных данных, полная остановка. – Wladimir Palant 7 August 2016 в 14:48
Другие вопросы по тегам:

Похожие вопросы: