Экранирование строк HTML с помощью jQuery

Кто-нибудь знает простой способ избежать HTML из строк в jQuery? Мне нужно иметь возможность передать произвольную строку и правильно экранировать ее для отображения на HTML-странице (предотвращая атаки JavaScript / HTML-инъекций). Я уверен, что для этого можно расширить jQuery, но на данный момент я недостаточно знаю о фреймворке, чтобы добиться этого.

Также см. Perf: jsperf.com/…

Christophe Roussy 27.10.2015 12:39
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
627
1
690 999
26
Перейти к ответу Данный вопрос помечен как решенный

Ответы 26

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

html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");

В зависимости от вашего варианта использования вам также могут потребоваться такие действия, как " - &quot;. Если бы список стал достаточно большим, я бы просто использовал массив:

var escaped = html;
var findReplace = [[/&/g, "&amp;"], [/</g, "&lt;"], [/>/g, "&gt;"], [/"/g, "&quot;"]]
for(var item in findReplace)
    escaped = escaped.replace(findReplace[item][0], findReplace[item][1]);

encodeURIComponent() будет экранировать его только для URL-адресов, но не для HTML.

Это регулярное выражение приведет к странным результатам, если в рассматриваемом HTML уже есть экранированные сущности. Например, при побеге «Том и Джерри» получится «Том и Джерри».

Ryan 07.11.2010 21:24

Используйте var для локального объявления item; в любом случае, не используйте цикл for … in при просмотре массива! Вместо этого используйте обычную петлю for. Да, и это encodeURIComponent, а не escapeURIComponent.

Marcel Korpel 16.03.2011 19:33

Если вы работаете с атрибутами тегов, вам также необходимо избегать кавычек и / или двойных кавычек. Документация PHP для htmlspecialchars содержит полезный список выполняемых преобразований. php.net/htmlspecialchars

geofflee 24.03.2011 15:05

Просто любезное напоминание для новичков, не используйте это, если вы хотите, чтобы где-то на вашем веб-сайте были неанглийские символы ... Очевидно, этого не будет из-за символов с диакритическими знаками, например 'é': &eacute; Вот список HTML-сущностей, для справки: w3schools.com/tags/ref_entities.asp

LoganWolfer 02.04.2011 01:50

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

bchurchill 10.02.2013 06:20

@Ryan: Хотя стоит отметить, что это решение некорректно обрабатывает уже закодированные строки, оно также ничего не стоит, так как то же самое относится к большинству - возможно ко всем - решениям на этой странице.

mklement0 12.04.2013 18:21

@Ryan есть простое решение проблемы двойного кодирования. Просто снимите экранирование строки перед тем, как экранировать ее. Вызов unescape будет NOOP, если строка еще не включает закодированные объекты.

Ryan Mohr 27.02.2014 22:48

@RyanMohr Вы говорите, что побег из «Тома и Джерри» произведет «Тома и Джерри». Хороший! Это совершенно правильное поведение. Такое правильное экранирование позволяет людям публиковать комментарии, подобные вашему, в которых обсуждается HTML, без каких-либо странных вещей. Если бы он остался прежним, который был бы странным.

Flimm 21.06.2019 18:27

@LoganWolfer Если вы заявили, что ваш HTML-код правильно использует UTF-8, вам не нужно экранировать такой символ, как é, в &eacute;.

Flimm 21.06.2019 18:28

@ mklement0 Это решение работает правильно. Функция, которая принимает строку, не может узнать, закодирована ли строка или экранирована, правильным поведением всегда является экранирование, а не попытка угадать, экранирована уже строка или нет.

Flimm 21.06.2019 18:30

@Flimm, ты хотел адресовать свой комментарий Райану? Мой комментарий не подразумевает, что решение работает некорректно, он просто заявляет, что может быть полезно уточнить - разумное - предположение о том, что предполагается, что входная строка уже не закодирована.

mklement0 22.06.2019 01:18
Ответ принят как подходящий

Поскольку вы используете jQuery, вы можете просто установить свойство text элемента:

// before:
// <div class = "someClass">text</div>
var someHtmlString = "<script>alert('hi!');</script>";

// set a DIV's text:
$("div.someClass").text(someHtmlString);
// after: 
// <div class = "someClass">&lt;script&gt;alert('hi!');&lt;/script&gt;</div>

// get the text in a string:
var escaped = $("<div>").text(someHtmlString).html();
// value: 
// &lt;script&gt;alert('hi!');&lt;/script&gt;

Вы упустили момент, когда вам нужно получить доступ к $ ("div.someClass"). Html (), чтобы получить экранированную версию.

Morten Christiansen 30.01.2009 23:17

Это небезопасно для кроссбраузерности, если в вашей строке есть пробелы и символы \ n \ r \ t

nivcaner 04.12.2010 20:31

@nivcaner, можете ли вы привести (или дать ссылку) пример его отказа?

travis 06.12.2010 21:58

@travis Это задокументировано на веб-сайте jQuery: «Из-за различий в парсерах HTML в разных браузерах возвращаемый текст может отличаться новой строкой и другими пробелами». api.jquery.com/text

geofflee 24.03.2011 14:48

@geofflee хм, интересно, спасибо за информацию! Я проведу небольшое тестирование, но похоже, что это когда .text() вызывается на некоторых узлах DOM. Могу ошибаться, отчитаюсь ...

travis 24.03.2011 18:19

Вот корзина JS для тестирования: jsbin.com/itahe4/7 Любое добавляемое мной количество пробелов, похоже, не препятствует правильному экранированию HTML.

travis 25.03.2011 01:28

Похоже, что комментарий @Kip к решению Хенрика Н. также применим и здесь: «Следует отметить, что это не делает ничего, чтобы избежать одинарных или двойных кавычек. Если вы планируете поместить значение в атрибут HTML, это может быть проблемой».

mklement0 12.04.2013 17:41

@mklement, если вы уже используете это решение, у вас не возникнет проблем, если вы сделаете что-то вроде: $(element2).attr("some-attr", $(element1).html()); См. этот пример: jsbin.com/atibig/1/edit

travis 12.04.2013 22:01

@travis Спасибо; Я предполагаю, что это то, что вы подразумевали, но просто чтобы сделать это явным: attr() выполняет свою собственную кодировку, поэтому вы можете просто передать незашифрованный текст напрямую; например, $(elem).attr("some-attr", "<script>alert('hi!');</script>").

mklement0 13.04.2013 08:54

почему бы просто не использовать $ ("

")?
BrainSlugs83 20.06.2013 14:57

Это НЕ позволяет избежать кавычек и двойных кавычек, что плохо! wonko.com/post/html-escaping

Lior 18.03.2014 14:10

Итак, если я сделаю elem.text(unsafestr), а затем вытащите это из элемента с помощью elem.html(), эта строка будет полностью безопасной для дальнейших манипуляций и innerHTML и (я хочу добавить к ней html и повторно вставить)

Max Yari 23.04.2015 01:51

Кстати, вам не обязательно иметь элемент div.someClass в вашем документе. Вместо этого вы можете просто сгенерировать рабочий элемент на лету, например: var escaped = $('<div>').text(someHtmlString).html().

broofa 04.05.2015 17:49

брофа права. Пожалуйста, отредактируйте сообщение, чтобы убрать необходимость в элементе div.

emeraldhieu 21.05.2015 09:49

@broofa & Emerald214 Сначала я был сбит с толку, почему я даже написал это так, но это кто-то отредактировал. ☺ Обновлено, чтобы показать оба пути.

travis 21.05.2015 18:12

Я помогал другу с настраиваемым элементом, который его компания должна была использовать от третьей стороны. Этот настраиваемый элемент имел атрибут data-inner-html, в котором ожидаемым значением был HTML-тег, в котором вместо двойных кавычек использовались одинарные кавычки. HTML как значение для настраиваемого атрибута элемента HTML - поймите. Глядя на пример, предоставленный @travis в его комментарии, нам было нужно, чтобы HTML правильно и без проблем анализировал значение атрибута. Ваше здоровье!

DaveyJake 20.01.2021 02:13

$('<div/>').text('This is fun & stuff').html(); // "This is fun &amp; stuff"

Источник: http://debuggable.com/posts/encode-html-entities-with-jquery:480f4dd6-13cc-4ce9-8071-4710cbdd56cb

Как упоминалось в ответе выше, это решение не гарантирует сохранение пробелов.

geofflee 24.03.2011 14:53

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

Kip 16.06.2011 23:21

@Kip: @travis обнаружил, что метод jQuery attr() (по крайней мере, начиная с версии 1.8.3) выполняет собственное кодирование, поэтому незакодированные строки могут передаваться напрямую; например: $('<div/>').attr('test-attr', '\'Tis "fun" & stuff')[0].outerHTML

mklement0 13.04.2013 09:08

При использовании этого решения я получаю ошибку '<div/>' is not a valid selector..

tarekahf 04.11.2016 23:26

@tarekahf Это странно. Какую версию jQuery вы используете? Работает ли пример кода, если вы скопируете его дословно? Прекрасно работает с последней версией jQuery (3.1.0) здесь: jsbin.com/fazimigayo/1/edit?html,js,console,output (и он должен работать и на всех более ранних версиях)

Henrik N 05.11.2016 23:46

Спасибо ... теперь работает. Не знаю, почему раньше это не сработало. Быстрый вопрос ... изменит ли это какой-либо существующий элемент <div>? когда вы выбираете элемент с помощью $('<div/>'), какой элемент фактически выбирается? Это виртуальный элемент div?

tarekahf 07.11.2016 19:11

@tarekahf $('<div/>') создает новый элемент div, который не прикреплен к DOM. Таким образом, это не изменит никаких существующих элементов. Немного сбивает с толку, как jQuery использует одну и ту же функцию $() как для поиска элементов ($('div')), так и для их создания, а также для некоторых других вещей, помимо… :)

Henrik N 08.11.2016 09:59

Если вы идете по маршруту регулярных выражений, в приведенном выше примере tghw есть ошибка.

<!-- WON'T WORK -  item[0] is an index, not an item -->

var escaped = html; 
var findReplace = [[/&/g, "&amp;"], [/</g, "&lt;"], [/>/g,"&gt;"], [/"/g,
"&quot;"]]

for(var item in findReplace) {
     escaped = escaped.replace(item[0], item[1]);   
}


<!-- WORKS - findReplace[item[]] correctly references contents -->

var escaped = html;
var findReplace = [[/&/g, "&amp;"], [/</g, "&lt;"], [/>/g, "&gt;"], [/"/g, "&quot;"]]

for(var item in findReplace) {
     escaped = escaped.replace(findReplace[item[0]], findReplace[item[1]]);
}

Я считаю, что это должно быть для (var item в findReplace) {escaped = escaped.replace (findReplace [item] [0], findReplace [item] [1]); }

Chris Stephens 24.06.2011 01:23

escape() и unescape() предназначены для кодирования / декодирования строк URL-адресов, а не HTML.

На самом деле, я использую следующий фрагмент, чтобы сделать трюк, не требующий какой-либо структуры:

var escapedHtml = html.replace(/&/g, '&amp;')
                      .replace(/>/g, '&gt;')
                      .replace(/</g, '&lt;')
                      .replace(/"/g, '&quot;')
                      .replace(/'/g, '&apos;');

Если вы собираетесь использовать ", вам нужно добавить хотя бы ' и `` в бой. Они действительно нужны только для данных строкового тега внутри элементов в html. Для самих данных html (вне тегов) требуются только первые 3.

Marius 12.07.2013 16:01

Вот чистая и понятная функция JavaScript. Он будет экранировать текст, например "несколько

function escapeHtmlEntities (str) {
  if (typeof jQuery !== 'undefined') {
    // Create an empty div to use as a container,
    // then put the raw text in and get the HTML
    // equivalent out.
    return jQuery('<div/>').text(str).html();
  }

  // No jQuery, so use string replace.
  return str
    .replace(/&/g, '&amp;')
    .replace(/>/g, '&gt;')
    .replace(/</g, '&lt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&apos;');
}

function htmlEscape(str) {
    var stringval = "";
    $.each(str, function (i, element) {
        alert(element);
        stringval += element
            .replace(/&/g, '&amp;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(' ', '-')
            .replace('?', '-')
            .replace(':', '-')
            .replace('|', '-')
            .replace('.', '-');
    });
    alert(stringval);
    return String(stringval);
}

Попробуйте Underscore.string lib, он работает с jQuery.

_.str.escapeHTML('<div>Blah blah blah</div>')

выход:

'&lt;div&gt;Blah blah blah&lt;/div&gt;'

Основная библиотека подчеркивания теперь имеет служебную функцию _.escape().

codeape 11.10.2012 16:14

Также есть решение из mustache.js

var entityMap = {
  '&': '&amp;',
  '<': '&lt;',
  '>': '&gt;',
  '"': '&quot;',
  "'": '&#39;',
  '/': '&#x2F;',
  '`': '&#x60;',
  '=': '&#x3D;'
};

function escapeHtml (string) {
  return String(string).replace(/[&<>"'`=/]/g, function (s) {
    return entityMap[s];
  });
}

Обратите внимание, что, что любопытно, ' отображается на объект с форматом десятичный, тогда как / использует формат шестнадцатеричный.

mklement0 18.04.2013 17:15

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

lorefnon 29.07.2013 16:28

каковы рекомендации по преобразованию \n в <br>?

amwinter 18.10.2013 12:02

Вот обновленная ссылка на источник: github.com/janl/mustache.js/blob/…

mjackson 02.04.2014 23:42

@amwinter, я расширил сценарий выше, добавив "\ n": '<br>' на карту сущностей и обновил регулярное выражение до / [& "'\ /] | [\ n] / g

walv 25.06.2014 20:30

Это просто и правильно. Количество подводных камней в использовании text () и createTextNode того не стоит.

user 23.09.2014 11:11

Еще одно замечание: если это выполняется с размытием, это позволит ему выполнить, если вы нажмете Enter. Как только вы потеряете фокус, он будет в порядке, но все еще может работать. Только что выяснил это на собственном горьком опыте = - /

Mungoid 19.10.2014 08:29

Это следует принять как лучший ответ, поскольку он предотвращает выполнение сценариев XSS, таких как «».

emeraldhieu 25.05.2015 07:52

Вы пишете карту и пишете функцию, соответствующую символам, для которых у вас есть ключ на вашей карте. В Интернете есть образцы, которые объединяют ключи в регулярное выражение. Преимущество в том, что при расширении карты вы не можете забыть адаптировать регулярное выражение. Пример: iwb.jp/jquery-javascript-html-escape underscore.js использует аналогичный подход.

Bernhard Döbler 04.08.2015 15:01

@amwinter преобразование \n в <br> иногда вредно - например, в таких атрибутах, как title. использовать использование

<pre> or do it explicitly.</pre>
Jasen 30.10.2015 04:17

Я остановился на &amp;amp;amp;amp;amp;amp;. Где взять мультиметр

Silviu-Marian 23.11.2015 14:24

вот полезная ссылка, если вы хотите избежать большего: ascii.cl/htmlcodes.htm

Andy Raddatz 25.11.2015 06:10

Можно ли было бы порекомендовать избегать отметок (`) до &DiacriticalGrave;? Некоторые версии IE позволяют указывать атрибуты в кавычках.

Quinn Comendant 25.11.2015 07:12

Я обнаружил, что соответствие на & вызывает проблемы для текста, который уже имеет кодировку, например, Vénérange & Clemente. Он стал бы V & eacute; n & eacute; range & Clemente. Поэтому я изменил регулярное выражение на это / & | ["'\ /] / и добавил пробел в карту символов" & ":" & ". Таким образом, он преобразует единственный &, но не тот, который используется для кодирования сам.

JeffG 19.04.2016 05:42

Зачем вообще кодировать /? Это не нужно.

joeytwiddle 31.05.2016 10:27

Это мне очень помогло. Мне нужна была запись в escapeMap для преобразования пробелов в "% 20", так как мне нужно было размещать пути к файлам, где были пробелы в именах папок и файлов. Я также добавил пробел к регулярному выражению.

Greg Barth 09.12.2016 23:09

Это не избавит от символов Unicode, таких как; / u003c и / u003e для "".

Rasika Perera 17.01.2017 07:55

Почему убрали обратную кавычку `? github.com/janl/mustache.js/blob/… - А что у функции инверсия?

qräbnö 21.01.2021 22:19

Этот ответ предоставляет методы jQuery и обычные JS, но это самый короткий вариант без использования DOM:

unescape(escape("It's > 20% less complicated this way."))

Экранированная строка: It%27s%20%3E%2020%25%20less%20complicated%20this%20way.

Если вас беспокоят экранированные пробелы, попробуйте:

unescape(escape("It's > 20% less complicated this way.").replace(/%20/g, " "))

Экранированная строка: It%27s %3E 20%25 less complicated this way.

К сожалению, функция escape() была устарело в версии JavaScript 1.5. encodeURI() или encodeURIComponent() - альтернативы, но они игнорируют ', поэтому последняя строка кода превратилась бы в это:

decodeURI(encodeURI("It's > 20% less complicated this way.").replace(/%20/g, " ").replace("'", '%27'))

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

Это для кодировки URL. Вопрос касался экранирования HTML, а это совсем другое.

thelem 15.10.2015 12:22

@thelem, не если строки встроены в массивы JavaScript, встроенные в HTML, но я согласен, что речь шла о простом экранировании HTML, чтобы его можно было сразу отобразить как текст.

Cees Timmerman 15.10.2015 16:02

Это хороший безопасный пример ...

function escapeHtml(str) {
    if (typeof(str) == "string"){
        try{
            var newStr = "";
            var nextCode = 0;
            for (var i = 0;i < str.length;i++){
                nextCode = str.charCodeAt(i);
                if (nextCode > 0 && nextCode < 128){
                    newStr += "&#"+nextCode+";";
                }
                else{
                    newStr += "?";
                }
             }
             return newStr;
        }
        catch(err){
        }
    }
    else{
        return str;
    }
}

Какие типы исключений вы там подавляете?

Stefan Majewsky 16.11.2012 20:08

Я написал крошечную функцию, которая делает это. Он экранирует только ", &, < и > (но обычно это все, что вам нужно). Это немного более элегантно, чем ранее предложенные решения, поскольку оно использует только один.replace() для выполнения всех преобразований. (Обновлено еще раз: Сниженная сложность кода, делающая функцию еще меньше и аккуратнее, если вам интересен исходный код, см. Конец этого ответа.)

function escapeHtml(text) {
    'use strict';
    return text.replace(/[\"&<>]/g, function (a) {
        return { '"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;' }[a];
    });
}

Это простой Javascript, без использования jQuery.

Выход из / и ' тоже

Редактировать в ответ на комментарий мклемент.

Вышеупомянутую функцию можно легко расширить, включив в нее любой символ. Чтобы указать больше символов для экранирования, просто вставьте их как в класс символов в регулярном выражении (т.е. внутри /[...]/g), так и как запись в объекте chr. (Обновлено еще раз: Таким же образом сократила и эту функцию.)

function escapeHtml(text) {
    'use strict';
    return text.replace(/[\"&'/<>]/g, function (a) {
        return {
            '"': '&quot;', '&': '&amp;', "'": '&#39;',
            '/': '&#47;',  '<': '&lt;',  '>': '&gt;'
        }[a];
    });
}

Обратите внимание на приведенное выше использование &#39; для апострофа (вместо него мог быть использован символический объект &apos; - он определен в XML, но изначально не был включен в спецификацию HTML и поэтому может поддерживаться не всеми браузерами. См. Статья в Википедии о кодировках символов HTML). Я также помню, как где-то читал, что использование десятичных сущностей более широко поддерживается, чем использование шестнадцатеричных, но я не могу найти источник для этого сейчас. (И не может быть много браузеров, которые не поддерживают шестнадцатеричные сущности.)

Примечание: Добавление / и ' в список экранированных символов не так уж и полезно, поскольку они не имеют никакого специального значения в HTML и не позволяют экранировать необходимость.

Оригинальная функция escapeHtml

Обновлено еще раз: Исходная функция использовала переменную (chr) для хранения объекта, необходимого для обратного вызова .replace(). Эта переменная также нуждалась в дополнительной анонимной функции для ее масштабирования, что делало функцию (без нужды) немного больше и сложнее.

var escapeHtml = (function () {
    'use strict';
    var chr = { '"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;' };
    return function (text) {
        return text.replace(/[\"&<>]/g, function (a) { return chr[a]; });
    };
}());

Я не проверял, какая из двух версий быстрее. Если да, не стесняйтесь добавлять сюда информацию и ссылки об этом.

Спасибо, что нашли время, @Zrajm. Хороший момент в том, что не нужно убегать; любая идея, почему и mustache.js, и underscore.js делают это? Кстати о последнем: он распознает только числовые объекты (представляющие ' и / ') в форме прописные шестнадцатеричные при ООНescaping. Таким образом, экранирование текста в mustache.js, что любопытно, использует шестнадцатеричное смешивание. и десятичные форматы - в underscore.js некорректно неэкранировать. Интересно, как с этим справляются другие популярные библиотеки.

mklement0 18.04.2013 17:22

Шестнадцатеричная форма нижнего регистра - это наиболее поддерживаемая форма, так что (вероятно) это форма, которую библиотеки должны преобразовывать в к. (Конечно, обе формы должны работать при преобразовании из.) - Апострофы ' имеют какую-то зарезервированную функцию в XML (и, следовательно, XHTML, я полагаю?), Поэтому XML (но не HTML) имеет именованный объект &apos;. Я не знаю, почему и каким образом он «зарезервирован». - Косые черты являются особенными в URL-адресах, но фактически не гарантирует их включение в экранирующий HTML (поскольку кодирование URL-адресов - это нечто совершенно иное).

zrajm 20.04.2013 05:29

По &apos;: правильно: безопасное использование только в XHTML; прямо из рот толпы - акцент мой: «(...) прочитано соответствующим процессором HTML, (...) использование 'или ссылок на настраиваемые объекты может не поддерживаться (...)» - на практике: поддержка современных браузеров это даже в HTML. Re case в шестнадцатеричном формате. (тот же источник; курсив мой): «x должен быть в нижнем регистре в XML-документах. […] hhhh может смешивать верхний и нижний регистр, хотя прописные буквы - это обычный стиль». Остается задаться вопросом, кто решил кодировать слэши; возможно, действительно просто путаница между кодировкой URI и HTML?

mklement0 20.04.2013 06:34

Заключительные мысли: кажется, что кодирование / не требуется, но кодирование ' по-прежнему кажется полезным для безопасного обращения с тем случаем, когда закодированная строка используется как значение атрибут, заключенное в одинарные кавычки.

mklement0 20.04.2013 07:05

Оба они медленные. Самое быстрое решение с двузначным полем - это серия замен, которым вместо функций передаются строки.

Adam Leggett 12.07.2017 00:02

Я улучшил пример mustache.js, добавив метод escapeHTML() к строковому объекту.

var __entityMap = {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': '&quot;',
    "'": '&#39;',
    "/": '&#x2F;'
};

String.prototype.escapeHTML = function() {
    return String(this).replace(/[&<>"'/]/g, function (s) {
        return __entityMap[s];
    });
}

Таким образом, использовать "Some <text>, more Text&Text".escapeHTML() довольно просто.

Полезно, но я также переместил __entityMap в локальную область видимости функции. И все это завернул в if (typeof String.prototype.escapeHTML !== 'function'){...}

FlameStorm 09.08.2017 14:27

(function(undefined){
    var charsToReplace = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;'
    };

    var replaceReg = new RegExp("[" + Object.keys(charsToReplace).join("") + "]", "g");
    var replaceFn = function(tag){ return charsToReplace[tag] || tag; };

    var replaceRegF = function(replaceMap) {
        return (new RegExp("[" + Object.keys(charsToReplace).concat(Object.keys(replaceMap)).join("") + "]", "gi"));
    };
    var replaceFnF = function(replaceMap) {
        return function(tag){ return replaceMap[tag] || charsToReplace[tag] || tag; };
    };

    String.prototype.htmlEscape = function(replaceMap) {
        if (replaceMap === undefined) return this.replace(replaceReg, replaceFn);
        return this.replace(replaceRegF(replaceMap), replaceFnF(replaceMap));
    };
})();

Никаких глобальных переменных, некоторая оптимизация памяти. Использование:

"some<tag>and&symbol©".htmlEscape({'©': '&copy;'})

результат:

"some&lt;tag&gt;and&amp;symbol&copy;"

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

работает как шарм

text удаляет HTML-теги, но $ ('

').html(t).html(); works
Bass Jobsen 08.08.2013 23:50

После последних тестов я могу порекомендовать самый быстрый и полностью кросс-браузер-совместимое решение собственный javaScript (DOM):

function HTMLescape(html){
    return document.createElement('div')
        .appendChild(document.createTextNode(html))
        .parentNode
        .innerHTML
}

Если вы повторяете это много раз, вы можете сделать это с заранее подготовленными переменными:

//prepare variables
var DOMtext = document.createTextNode("test");
var DOMnative = document.createElement("span");
DOMnative.appendChild(DOMtext);

//main work for each case
function HTMLescape(html){
  DOMtext.nodeValue = html;
  return DOMnative.innerHTML
}

Посмотрите на мой финальный перформанс сравнение (стек вопрос).

Обязательно ли использовать два узла? Как насчет всего одного: var p = document.createElement('p'); p.textContent = html; return p.innerHTML;

Dan Dascalescu 13.08.2015 18:14

@DanDascalescu: Согласно MDN, функция textContent поддерживается только Chrome 1+, Firefox 2, IE9, Opera 9.64 и Safari 3 (последние два помечены как «возможно раньше»). Таким образом, это нарушит утверждение OP о «полностью кроссбраузерности».

zb226 11.11.2015 14:00

p.innerText = html; return p.innerHTML

Bekim Bacaj 27.11.2016 11:58

Достаточно просто использовать подчеркивание:

_.escape(string) 

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

А обратный - _.unescape(string).

qräbnö 21.01.2021 22:12

Если у вас есть underscore.js, используйте _.escape (более эффективный, чем метод jQuery, указанный выше):

_.escape('Curly, Larry & Moe'); // returns: Curly, Larry &amp; Moe

Вы легко можете сделать это с помощью vanilla js.

Просто добавьте текстовый узел в документ. Он будет экранирован браузером.

var escaped = document.createTextNode("<HTML TO/ESCAPE/>")
document.getElementById("[PARENT_NODE]").appendChild(escaped)

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

Чтобы прояснить мою точку зрения, вот пример, использующий один из ответов:

Допустим, вы используете функцию escapeHtml, чтобы избежать HTML-кода из комментария в своем блоге, а затем разместить его на своем сервере.

var entityMap = {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': '&quot;',
    "'": '&#39;',
    "/": '&#x2F;'
  };

  function escapeHtml(string) {
    return String(string).replace(/[&<>"'/]/g, function (s) {
      return entityMap[s];
    });
  }

Пользователь мог:

  • Отредактируйте параметры запроса POST и замените комментарий кодом javascript.
  • Замените функцию escapeHtml с помощью консоли браузера.

Если пользователь вставит этот фрагмент в консоль, он обойдет проверку XSS:

function escapeHtml(string){
   return string
}

Я не согласен. Чтобы обойти эту защиту XSS, вам придется использовать атаку XSS (внедрение сценария, отключающего экранирование), что вы фактически блокируете. В некоторых случаях на самом деле более целесообразно уйти от клиента, например, если данные поступают из REST API, который должен возвращать стандартный JSON.

ItalyPaleAle 13.03.2015 21:00

@Qualcuno Если вы выполняете эту проверку на клиенте и отправляете эту информацию на сервер, полагая, что она была проверена, пользователь может просто отредактировать запрос, и сценарий будет сохранен в базе данных.

Kauê Gimenes 13.03.2015 21:12

@Qualcuno Я включил несколько примеров, чтобы прояснить свою точку зрения.

Kauê Gimenes 13.03.2015 21:21

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

ItalyPaleAle 13.03.2015 21:26

@Qualcuno Это популярный вопрос в Stackoverflow, и я считаю, что это важный момент, который необходимо рассмотреть. Вот почему я ответил.

Kauê Gimenes 13.03.2015 21:29

@Qualcuno И ответ довольно открытый, поэтому я думаю, что мы должны осветить все вопросы.

Kauê Gimenes 13.03.2015 21:31

Все решения бесполезны, если вы не предотвратите повторный побег, например. большинство решений продолжали бы переходить от & к &amp;.

escapeHtml = function (s) {
    return s ? s.replace(
        /[&<>'"]/g,
        function (c, offset, str) {
            if (c === "&") {
                var substr = str.substring(offset, offset + 6);
                if (/&(amp|lt|gt|apos|quot);/.test(substr)) {
                    // already escaped, do not re-escape
                    return c;
                }
            }
            return "&" + {
                "&": "amp",
                "<": "lt",
                ">": "gt",
                "'": "apos",
                '"': "quot"
            }[c] + ";";
        }
    ) : "";
};

Это называется двойным экранированием, и его следует исправить, убедившись, что ваши входные данные еще не экранированы. Что, если бы вы хотели буквально показать <пользователю? Или, возможно, текст будет повторно использован в другом месте и будет зависеть от того, что произошло побег?

thelem 15.10.2015 12:26

2 простых метода, не требующих НИКАКИХ JQUERY ...

Вы можете закодировать все символы в своей строке вот так:

function encode(e){return e.replace(/[^]/g,function(e){return"&#"+e.charCodeAt(0)+";"})}

Или просто нацелить главных героев, чтобы беспокоиться о &, разрывах строк, <, >, " и ', например:

function encode(r){
return r.replace(/[\x26\x0A\<>'"]/g,function(r){return"&#"+r.charCodeAt(0)+";"})
}

var myString='Encode HTML entities!\n"Safe" escape <script></'+'script> & other tags!';

test.value=encode(myString);

testing.innerHTML=encode(myString);

/*************
* \x26 is &ampersand (it has to be first),
* \x0A is newline,
*************/
<p><b>What JavaScript Generated:</b></p>

<textarea id=test rows = "3" cols = "55"></textarea>

<p><b>What It Renders Too In HTML:</b></p>

<div id = "testing">www.WHAK.com</div>

Я понимаю, как опаздываю на эту вечеринку, но у меня есть очень простое решение, не требующее jQuery.

escaped = new Option(unescaped).innerHTML;

Обновлено: это не позволяет избежать кавычек. Единственный случай, когда кавычки нужно будет экранировать, - это если содержимое будет вставлено встроенным в атрибут в строке HTML. Мне трудно представить себе случай, когда это было бы хорошим дизайном.

Изменить 3: для самого быстрого решения проверьте ответ Сарама выше. Этот самый короткий.

Это не меняет кавычек - по крайней мере, сейчас в Firefox 52.

getsetbro 10.01.2017 23:55

Экранирование кавычек имеет только функциональное значение в атрибутах. Поскольку мы экранируем < и >, экранирование кавычек также бесполезно, если только целью сгенерированного контента не является переход в атрибут.

Adam Leggett 11.01.2017 00:38

Это также имеет (вероятный нежелательный) побочный эффект преобразования null в буквальный 'null'.

efdee 17.06.2020 10:45

@efdee Я думаю, что любое из этих решений будет иметь такой эффект. Это дело программиста.

Adam Leggett 17.06.2020 21:33

Простой пример экранирования JavaScript:

function escapeHtml(text) {
    var div = document.createElement('div');
    div.innerText = text;
    return div.innerHTML;
}

escapeHtml("<script>alert('hi!');</script>")
// "&lt;script&gt;alert('hi!');&lt;/script&gt;"

Ответы только на код не приветствуются, потому что они не объясняют, как они решают проблему. Обновите свой ответ, чтобы объяснить как это улучшает другие принятые и одобренные ответы, что этот вопрос уже задан. Кроме того, этому вопросу 9 лет, ваши усилия будут более оценены пользователями, у которых недавно остались вопросы без ответа. Просмотрите Как мне написать хороший ответ.

FluffyKitten 11.10.2017 13:20

@FluffyKitten - это чрезвычайно красиво написанное сообщение в блоге о преимуществах и недостатках такой функции, в котором подробно объясняется все, что вы хотели бы знать :) shebang.brandonmintern.com/…

db306 13.11.2017 10:54

@ db306 Ответ был отмечен как низкое качество, потому что ответ, содержащий только код, не соответствует рекомендациям по переполнению стека - см. Как написать хороший ответ. Мой комментарий был добавлен в процессе проверки, чтобы объяснить, что требуется для его улучшения, т.е. ответ необходимо обновить, чтобы объяснить, что делает код и как он улучшает существующие ответы. Отзывы других обозревателей подтверждают это. Добавление внешней ссылки в комментарии по-прежнему не соответствует рекомендациям SO. Вместо этого Эндрю нужно включить соответствующую информацию прямо в свой ответ.

FluffyKitten 14.11.2017 12:19

Обратите внимание, что срок действия brandonmintern DOT com истек и теперь он припаркован. Новый адрес shebang - shebang.mintern.net/foolproof-html-escaping-in-javascript/.

Brandon 24.04.2020 21:52

ES6 один лайнер для решение из mustache.js

const escapeHTML = str => (str+'').replace(/[&<>"'`=/]/g, s => ({'&': '&amp;','<': '&lt;','>': '&gt;','"': '&quot;',"'": '&#39;','/': '&#x2F;','`': '&#x60;','=': '&#x3D;'})[s]);

Версия с оптимизацией скорости:

function escapeHtml(s) {
   let out = "";
   let p2 = 0;
   for (let p = 0; p < s.length; p++) {
      let r;
      switch (s.charCodeAt(p)) {
         case 34: r = "&quot;"; break;  // "
         case 38: r = "&amp;" ; break;  // &
         case 39: r = "&#39;" ; break;  // '
         case 60: r = '&lt;'  ; break;  // <
         case 62: r = '&gt;'  ; break;  // >
         default: continue;
      }
      if (p2 < p) {
         out += s.substring(p2, p);
      }
      out += r;
      p2 = p + 1;
   }
   if (p2 == 0) {
      return s;
   }
   if (p2 < s.length) {
      out += s.substring(p2);
   }
   return out;
}

const s = "Hello <World>!";
document.write(escapeHtml(s));
console.info(escapeHtml(s));

Другие вопросы по теме