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



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Если вы избегаете HTML, я могу придумать только три, которые были бы действительно необходимы:
html.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
В зависимости от вашего варианта использования вам также могут потребоваться такие действия, как " - ". Если бы список стал достаточно большим, я бы просто использовал массив:
var escaped = html;
var findReplace = [[/&/g, "&"], [/</g, "<"], [/>/g, ">"], [/"/g, """]]
for(var item in findReplace)
escaped = escaped.replace(findReplace[item][0], findReplace[item][1]);
encodeURIComponent() будет экранировать его только для URL-адресов, но не для HTML.
Это регулярное выражение приведет к странным результатам, если в рассматриваемом HTML уже есть экранированные сущности. Например, при побеге «Том и Джерри» получится «Том и Джерри».
Используйте var для локального объявления item; в любом случае, не используйте цикл for … in при просмотре массива! Вместо этого используйте обычную петлю for. Да, и это encodeURIComponent, а не escapeURIComponent.
Если вы работаете с атрибутами тегов, вам также необходимо избегать кавычек и / или двойных кавычек. Документация PHP для htmlspecialchars содержит полезный список выполняемых преобразований. php.net/htmlspecialchars
Просто любезное напоминание для новичков, не используйте это, если вы хотите, чтобы где-то на вашем веб-сайте были неанглийские символы ... Очевидно, этого не будет из-за символов с диакритическими знаками, например 'é': é Вот список HTML-сущностей, для справки: w3schools.com/tags/ref_entities.asp
В общем, изобретать велосипед для подобных вещей - плохая идея ... здесь очень много подводных камней.
@Ryan: Хотя стоит отметить, что это решение некорректно обрабатывает уже закодированные строки, оно также ничего не стоит, так как то же самое относится к большинству - возможно ко всем - решениям на этой странице.
@Ryan есть простое решение проблемы двойного кодирования. Просто снимите экранирование строки перед тем, как экранировать ее. Вызов unescape будет NOOP, если строка еще не включает закодированные объекты.
@RyanMohr Вы говорите, что побег из «Тома и Джерри» произведет «Тома и Джерри». Хороший! Это совершенно правильное поведение. Такое правильное экранирование позволяет людям публиковать комментарии, подобные вашему, в которых обсуждается HTML, без каких-либо странных вещей. Если бы он остался прежним, который был бы странным.
@LoganWolfer Если вы заявили, что ваш HTML-код правильно использует UTF-8, вам не нужно экранировать такой символ, как é, в é.
@ mklement0 Это решение работает правильно. Функция, которая принимает строку, не может узнать, закодирована ли строка или экранирована, правильным поведением всегда является экранирование, а не попытка угадать, экранирована уже строка или нет.
@Flimm, ты хотел адресовать свой комментарий Райану? Мой комментарий не подразумевает, что решение работает некорректно, он просто заявляет, что может быть полезно уточнить - разумное - предположение о том, что предполагается, что входная строка уже не закодирована.
Поскольку вы используете 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"><script>alert('hi!');</script></div>
// get the text in a string:
var escaped = $("<div>").text(someHtmlString).html();
// value:
// <script>alert('hi!');</script>
Вы упустили момент, когда вам нужно получить доступ к $ ("div.someClass"). Html (), чтобы получить экранированную версию.
Это небезопасно для кроссбраузерности, если в вашей строке есть пробелы и символы \ n \ r \ t
@nivcaner, можете ли вы привести (или дать ссылку) пример его отказа?
@travis Это задокументировано на веб-сайте jQuery: «Из-за различий в парсерах HTML в разных браузерах возвращаемый текст может отличаться новой строкой и другими пробелами». api.jquery.com/text
@geofflee хм, интересно, спасибо за информацию! Я проведу небольшое тестирование, но похоже, что это когда .text() вызывается на некоторых узлах DOM. Могу ошибаться, отчитаюсь ...
Вот корзина JS для тестирования: jsbin.com/itahe4/7 Любое добавляемое мной количество пробелов, похоже, не препятствует правильному экранированию HTML.
Похоже, что комментарий @Kip к решению Хенрика Н. также применим и здесь: «Следует отметить, что это не делает ничего, чтобы избежать одинарных или двойных кавычек. Если вы планируете поместить значение в атрибут HTML, это может быть проблемой».
@mklement, если вы уже используете это решение, у вас не возникнет проблем, если вы сделаете что-то вроде: $(element2).attr("some-attr", $(element1).html()); См. этот пример: jsbin.com/atibig/1/edit
@travis Спасибо; Я предполагаю, что это то, что вы подразумевали, но просто чтобы сделать это явным: attr() выполняет свою собственную кодировку, поэтому вы можете просто передать незашифрованный текст напрямую; например, $(elem).attr("some-attr", "<script>alert('hi!');</script>").
почему бы просто не использовать $ ("
")?Это НЕ позволяет избежать кавычек и двойных кавычек, что плохо! wonko.com/post/html-escaping
Итак, если я сделаю elem.text(unsafestr), а затем вытащите это из элемента с помощью elem.html(), эта строка будет полностью безопасной для дальнейших манипуляций и innerHTML и (я хочу добавить к ней html и повторно вставить)
Кстати, вам не обязательно иметь элемент div.someClass в вашем документе. Вместо этого вы можете просто сгенерировать рабочий элемент на лету, например: var escaped = $('<div>').text(someHtmlString).html().
брофа права. Пожалуйста, отредактируйте сообщение, чтобы убрать необходимость в элементе div.
@broofa & Emerald214 Сначала я был сбит с толку, почему я даже написал это так, но это кто-то отредактировал. ☺ Обновлено, чтобы показать оба пути.
Я помогал другу с настраиваемым элементом, который его компания должна была использовать от третьей стороны. Этот настраиваемый элемент имел атрибут data-inner-html, в котором ожидаемым значением был HTML-тег, в котором вместо двойных кавычек использовались одинарные кавычки. HTML как значение для настраиваемого атрибута элемента HTML - поймите. Глядя на пример, предоставленный @travis в его комментарии, нам было нужно, чтобы HTML правильно и без проблем анализировал значение атрибута. Ваше здоровье!
$('<div/>').text('This is fun & stuff').html(); // "This is fun & stuff"
Источник: http://debuggable.com/posts/encode-html-entities-with-jquery:480f4dd6-13cc-4ce9-8071-4710cbdd56cb
Как упоминалось в ответе выше, это решение не гарантирует сохранение пробелов.
Следует отметить, что это не помогает избежать одинарных или двойных кавычек. если вы планируете поместить значение в атрибут HTML, это может быть проблемой.
@Kip: @travis обнаружил, что метод jQuery attr() (по крайней мере, начиная с версии 1.8.3) выполняет собственное кодирование, поэтому незакодированные строки могут передаваться напрямую; например: $('<div/>').attr('test-attr', '\'Tis "fun" & stuff')[0].outerHTML
При использовании этого решения я получаю ошибку '<div/>' is not a valid selector..
@tarekahf Это странно. Какую версию jQuery вы используете? Работает ли пример кода, если вы скопируете его дословно? Прекрасно работает с последней версией jQuery (3.1.0) здесь: jsbin.com/fazimigayo/1/edit?html,js,console,output (и он должен работать и на всех более ранних версиях)
Спасибо ... теперь работает. Не знаю, почему раньше это не сработало. Быстрый вопрос ... изменит ли это какой-либо существующий элемент <div>? когда вы выбираете элемент с помощью $('<div/>'), какой элемент фактически выбирается? Это виртуальный элемент div?
@tarekahf $('<div/>') создает новый элемент div, который не прикреплен к DOM. Таким образом, это не изменит никаких существующих элементов. Немного сбивает с толку, как jQuery использует одну и ту же функцию $() как для поиска элементов ($('div')), так и для их создания, а также для некоторых других вещей, помимо… :)
Если вы идете по маршруту регулярных выражений, в приведенном выше примере tghw есть ошибка.
<!-- WON'T WORK - item[0] is an index, not an item -->
var escaped = html;
var findReplace = [[/&/g, "&"], [/</g, "<"], [/>/g,">"], [/"/g,
"""]]
for(var item in findReplace) {
escaped = escaped.replace(item[0], item[1]);
}
<!-- WORKS - findReplace[item[]] correctly references contents -->
var escaped = html;
var findReplace = [[/&/g, "&"], [/</g, "<"], [/>/g, ">"], [/"/g, """]]
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]); }
escape() и unescape() предназначены для кодирования / декодирования строк URL-адресов, а не HTML.
На самом деле, я использую следующий фрагмент, чтобы сделать трюк, не требующий какой-либо структуры:
var escapedHtml = html.replace(/&/g, '&')
.replace(/>/g, '>')
.replace(/</g, '<')
.replace(/"/g, '"')
.replace(/'/g, ''');
Если вы собираетесь использовать ", вам нужно добавить хотя бы ' и `` в бой. Они действительно нужны только для данных строкового тега внутри элементов в html. Для самих данных html (вне тегов) требуются только первые 3.
Вот чистая и понятная функция 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, '&')
.replace(/>/g, '>')
.replace(/</g, '<')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function htmlEscape(str) {
var stringval = "";
$.each(str, function (i, element) {
alert(element);
stringval += element
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(' ', '-')
.replace('?', '-')
.replace(':', '-')
.replace('|', '-')
.replace('.', '-');
});
alert(stringval);
return String(stringval);
}
Попробуйте Underscore.string lib, он работает с jQuery.
_.str.escapeHTML('<div>Blah blah blah</div>')
выход:
'<div>Blah blah blah</div>'
Основная библиотека подчеркивания теперь имеет служебную функцию _.escape().
Также есть решение из mustache.js
var entityMap = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
'/': '/',
'`': '`',
'=': '='
};
function escapeHtml (string) {
return String(string).replace(/[&<>"'`=/]/g, function (s) {
return entityMap[s];
});
}
Обратите внимание, что, что любопытно, ' отображается на объект с форматом десятичный, тогда как / использует формат шестнадцатеричный.
Это должен быть принятый ответ - он простой, эффективный, не требует зависимостей и делает именно то, что задумано, без малопонятных хаков.
каковы рекомендации по преобразованию \n в <br>?
Вот обновленная ссылка на источник: github.com/janl/mustache.js/blob/…
@amwinter, я расширил сценарий выше, добавив "\ n": '<br>' на карту сущностей и обновил регулярное выражение до / [& "'\ /] | [\ n] / g
Это просто и правильно. Количество подводных камней в использовании text () и createTextNode того не стоит.
Еще одно замечание: если это выполняется с размытием, это позволит ему выполнить, если вы нажмете Enter. Как только вы потеряете фокус, он будет в порядке, но все еще может работать. Только что выяснил это на собственном горьком опыте = - /
Это следует принять как лучший ответ, поскольку он предотвращает выполнение сценариев XSS, таких как «».
Вы пишете карту и пишете функцию, соответствующую символам, для которых у вас есть ключ на вашей карте. В Интернете есть образцы, которые объединяют ключи в регулярное выражение. Преимущество в том, что при расширении карты вы не можете забыть адаптировать регулярное выражение. Пример: iwb.jp/jquery-javascript-html-escape underscore.js использует аналогичный подход.
@amwinter преобразование \n в <br> иногда вредно - например, в таких атрибутах, как title. использовать использование
Я остановился на &amp;amp;amp;amp;amp;. Где взять мультиметр
вот полезная ссылка, если вы хотите избежать большего: ascii.cl/htmlcodes.htm
Можно ли было бы порекомендовать избегать отметок (`) до `? Некоторые версии IE позволяют указывать атрибуты в кавычках.
Я обнаружил, что соответствие на & вызывает проблемы для текста, который уже имеет кодировку, например, Vénérange & Clemente. Он стал бы V & eacute; n & eacute; range & Clemente. Поэтому я изменил регулярное выражение на это / & | ["'\ /] / и добавил пробел в карту символов" & ":" & ". Таким образом, он преобразует единственный &, но не тот, который используется для кодирования сам.
Зачем вообще кодировать /? Это не нужно.
Это мне очень помогло. Мне нужна была запись в escapeMap для преобразования пробелов в "% 20", так как мне нужно было размещать пути к файлам, где были пробелы в именах папок и файлов. Я также добавил пробел к регулярному выражению.
Это не избавит от символов Unicode, таких как; / u003c и / u003e для "".
Почему убрали обратную кавычку `? github.com/janl/mustache.js/blob/… - А что у функции инверсия?
Этот ответ предоставляет методы 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, не если строки встроены в массивы JavaScript, встроенные в HTML, но я согласен, что речь шла о простом экранировании HTML, чтобы его можно было сразу отобразить как текст.
Это хороший безопасный пример ...
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;
}
}
Какие типы исключений вы там подавляете?
Я написал крошечную функцию, которая делает это. Он экранирует только ", &, < и > (но обычно это все, что вам нужно). Это немного более элегантно, чем ранее предложенные решения, поскольку оно использует только один.replace() для выполнения всех преобразований. (Обновлено еще раз: Сниженная сложность кода, делающая функцию еще меньше и аккуратнее, если вам интересен исходный код, см. Конец этого ответа.)
function escapeHtml(text) {
'use strict';
return text.replace(/[\"&<>]/g, function (a) {
return { '"': '"', '&': '&', '<': '<', '>': '>' }[a];
});
}
Это простой Javascript, без использования jQuery.
/ и ' тожеРедактировать в ответ на комментарий мклемент.
Вышеупомянутую функцию можно легко расширить, включив в нее любой символ. Чтобы указать больше символов для экранирования, просто вставьте их как в класс символов в регулярном выражении (т.е. внутри /[...]/g), так и как запись в объекте chr. (Обновлено еще раз: Таким же образом сократила и эту функцию.)
function escapeHtml(text) {
'use strict';
return text.replace(/[\"&'/<>]/g, function (a) {
return {
'"': '"', '&': '&', "'": ''',
'/': '/', '<': '<', '>': '>'
}[a];
});
}
Обратите внимание на приведенное выше использование ' для апострофа (вместо него мог быть использован символический объект ' - он определен в XML, но изначально не был включен в спецификацию HTML и поэтому может поддерживаться не всеми браузерами. См. Статья в Википедии о кодировках символов HTML). Я также помню, как где-то читал, что использование десятичных сущностей более широко поддерживается, чем использование шестнадцатеричных, но я не могу найти источник для этого сейчас. (И не может быть много браузеров, которые не поддерживают шестнадцатеричные сущности.)
Примечание: Добавление / и ' в список экранированных символов не так уж и полезно, поскольку они не имеют никакого специального значения в HTML и не позволяют экранировать необходимость.
escapeHtmlОбновлено еще раз: Исходная функция использовала переменную (chr) для хранения объекта, необходимого для обратного вызова .replace(). Эта переменная также нуждалась в дополнительной анонимной функции для ее масштабирования, что делало функцию (без нужды) немного больше и сложнее.
var escapeHtml = (function () {
'use strict';
var chr = { '"': '"', '&': '&', '<': '<', '>': '>' };
return function (text) {
return text.replace(/[\"&<>]/g, function (a) { return chr[a]; });
};
}());
Я не проверял, какая из двух версий быстрее. Если да, не стесняйтесь добавлять сюда информацию и ссылки об этом.
Спасибо, что нашли время, @Zrajm. Хороший момент в том, что не нужно убегать; любая идея, почему и mustache.js, и underscore.js делают это? Кстати о последнем: он распознает только числовые объекты (представляющие ' и / ') в форме прописные шестнадцатеричные при ООНescaping. Таким образом, экранирование текста в mustache.js, что любопытно, использует шестнадцатеричное смешивание. и десятичные форматы - в underscore.js некорректно неэкранировать. Интересно, как с этим справляются другие популярные библиотеки.
Шестнадцатеричная форма нижнего регистра - это наиболее поддерживаемая форма, так что (вероятно) это форма, которую библиотеки должны преобразовывать в к. (Конечно, обе формы должны работать при преобразовании из.) - Апострофы ' имеют какую-то зарезервированную функцию в XML (и, следовательно, XHTML, я полагаю?), Поэтому XML (но не HTML) имеет именованный объект '. Я не знаю, почему и каким образом он «зарезервирован». - Косые черты являются особенными в URL-адресах, но фактически не гарантирует их включение в экранирующий HTML (поскольку кодирование URL-адресов - это нечто совершенно иное).
По ': правильно: безопасное использование только в XHTML; прямо из рот толпы - акцент мой: «(...) прочитано соответствующим процессором HTML, (...) использование 'или ссылок на настраиваемые объекты может не поддерживаться (...)» - на практике: поддержка современных браузеров это даже в HTML. Re case в шестнадцатеричном формате. (тот же источник; курсив мой): «x должен быть в нижнем регистре в XML-документах. […] hhhh может смешивать верхний и нижний регистр, хотя прописные буквы - это обычный стиль». Остается задаться вопросом, кто решил кодировать слэши; возможно, действительно просто путаница между кодировкой URI и HTML?
Заключительные мысли: кажется, что кодирование / не требуется, но кодирование ' по-прежнему кажется полезным для безопасного обращения с тем случаем, когда закодированная строка используется как значение атрибут, заключенное в одинарные кавычки.
Оба они медленные. Самое быстрое решение с двузначным полем - это серия замен, которым вместо функций передаются строки.
Я улучшил пример mustache.js, добавив метод escapeHTML() к строковому объекту.
var __entityMap = {
"&": "&",
"<": "<",
">": ">",
'"': '"',
"'": ''',
"/": '/'
};
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'){...}
(function(undefined){
var charsToReplace = {
'&': '&',
'<': '<',
'>': '>'
};
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({'©': '©'})
результат:
"some<tag>and&symbol©"
function htmlDecode(t){
if (t) return $('<div />').html(t).text();
}
работает как шарм
text удаляет HTML-теги, но $ ('
').html(t).html(); worksПосле последних тестов я могу порекомендовать самый быстрый и полностью кросс-браузер-совместимое решение собственный 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;
@DanDascalescu: Согласно MDN, функция textContent поддерживается только Chrome 1+, Firefox 2, IE9, Opera 9.64 и Safari 3 (последние два помечены как «возможно раньше»). Таким образом, это нарушит утверждение OP о «полностью кроссбраузерности».
p.innerText = html; return p.innerHTML
Достаточно просто использовать подчеркивание:
_.escape(string)
Подчеркивать - это служебная библиотека, которая предоставляет множество функций, которые не предоставляет собственный js. Также существует Lodash, который представляет собой тот же API, что и подчеркивание, но был переписан для большей производительности.
А обратный - _.unescape(string).
Если у вас есть underscore.js, используйте _.escape (более эффективный, чем метод jQuery, указанный выше):
_.escape('Curly, Larry & Moe'); // returns: Curly, Larry & Moe
Вы легко можете сделать это с помощью vanilla js.
Просто добавьте текстовый узел в документ. Он будет экранирован браузером.
var escaped = document.createTextNode("<HTML TO/ESCAPE/>")
document.getElementById("[PARENT_NODE]").appendChild(escaped)
Если вы сохраняете эту информацию в база данных, неправильно экранировать HTML с помощью сценария сторона клиента, это следует делать в сервер. В противном случае легко обойти вашу XSS-защиту.
Чтобы прояснить мою точку зрения, вот пример, использующий один из ответов:
Допустим, вы используете функцию escapeHtml, чтобы избежать HTML-кода из комментария в своем блоге, а затем разместить его на своем сервере.
var entityMap = {
"&": "&",
"<": "<",
">": ">",
'"': '"',
"'": ''',
"/": '/'
};
function escapeHtml(string) {
return String(string).replace(/[&<>"'/]/g, function (s) {
return entityMap[s];
});
}
Пользователь мог:
Если пользователь вставит этот фрагмент в консоль, он обойдет проверку XSS:
function escapeHtml(string){
return string
}
Я не согласен. Чтобы обойти эту защиту XSS, вам придется использовать атаку XSS (внедрение сценария, отключающего экранирование), что вы фактически блокируете. В некоторых случаях на самом деле более целесообразно уйти от клиента, например, если данные поступают из REST API, который должен возвращать стандартный JSON.
@Qualcuno Если вы выполняете эту проверку на клиенте и отправляете эту информацию на сервер, полагая, что она была проверена, пользователь может просто отредактировать запрос, и сценарий будет сохранен в базе данных.
@Qualcuno Я включил несколько примеров, чтобы прояснить свою точку зрения.
Вопрос касался экранирования строк, полученных с сервера, в отображать их в браузере. То, что вы говорите, касается экранирования строк перед их отправкой на сервер, что другое дело (хотя вы правы, и это восходит к старому правилу никогда не принимайте вслепую информацию от клиента)
@Qualcuno Это популярный вопрос в Stackoverflow, и я считаю, что это важный момент, который необходимо рассмотреть. Вот почему я ответил.
@Qualcuno И ответ довольно открытый, поэтому я думаю, что мы должны осветить все вопросы.
Все решения бесполезны, если вы не предотвратите повторный побег, например. большинство решений продолжали бы переходить от & к &.
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] + ";";
}
) : "";
};
Это называется двойным экранированием, и его следует исправить, убедившись, что ваши входные данные еще не экранированы. Что, если бы вы хотели буквально показать <пользователю? Или, возможно, текст будет повторно использован в другом месте и будет зависеть от того, что произошло побег?
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 &ersand (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.
Экранирование кавычек имеет только функциональное значение в атрибутах. Поскольку мы экранируем < и >, экранирование кавычек также бесполезно, если только целью сгенерированного контента не является переход в атрибут.
Это также имеет (вероятный нежелательный) побочный эффект преобразования null в буквальный 'null'.
@efdee Я думаю, что любое из этих решений будет иметь такой эффект. Это дело программиста.
Простой пример экранирования JavaScript:
function escapeHtml(text) {
var div = document.createElement('div');
div.innerText = text;
return div.innerHTML;
}
escapeHtml("<script>alert('hi!');</script>")
// "<script>alert('hi!');</script>"
Ответы только на код не приветствуются, потому что они не объясняют, как они решают проблему. Обновите свой ответ, чтобы объяснить как это улучшает другие принятые и одобренные ответы, что этот вопрос уже задан. Кроме того, этому вопросу 9 лет, ваши усилия будут более оценены пользователями, у которых недавно остались вопросы без ответа. Просмотрите Как мне написать хороший ответ.
@FluffyKitten - это чрезвычайно красиво написанное сообщение в блоге о преимуществах и недостатках такой функции, в котором подробно объясняется все, что вы хотели бы знать :) shebang.brandonmintern.com/…
@ db306 Ответ был отмечен как низкое качество, потому что ответ, содержащий только код, не соответствует рекомендациям по переполнению стека - см. Как написать хороший ответ. Мой комментарий был добавлен в процессе проверки, чтобы объяснить, что требуется для его улучшения, т.е. ответ необходимо обновить, чтобы объяснить, что делает код и как он улучшает существующие ответы. Отзывы других обозревателей подтверждают это. Добавление внешней ссылки в комментарии по-прежнему не соответствует рекомендациям SO. Вместо этого Эндрю нужно включить соответствующую информацию прямо в свой ответ.
Обратите внимание, что срок действия brandonmintern DOT com истек и теперь он припаркован. Новый адрес shebang - shebang.mintern.net/foolproof-html-escaping-in-javascript/.
ES6 один лайнер для решение из mustache.js
const escapeHTML = str => (str+'').replace(/[&<>"'`=/]/g, s => ({'&': '&','<': '<','>': '>','"': '"',"'": ''','/': '/','`': '`','=': '='})[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 = """; break; // "
case 38: r = "&" ; break; // &
case 39: r = "'" ; break; // '
case 60: r = '<' ; break; // <
case 62: r = '>' ; 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));
Также см. Perf: jsperf.com/…