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

609

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

страница
источник
Также см. Perf
Кристоф Русси,

Ответы:

445

Поскольку вы используете 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;
Трэвис
источник
57
Вы упустили момент, когда вам нужен доступ к $ ("div.someClass"). Html (), чтобы получить экранированную версию.
Мортен Кристиансен
16
Это небезопасно для браузера, если в вашей строке есть пробелы и символы \ n \ r \ t
nivcaner
20
@travis Это задокументировано на веб-сайте jQuery: «Из-за различий в синтаксических анализаторах HTML в разных браузерах возвращаемый текст может различаться в новых строках и других пробелах». api.jquery.com/text
Джеффли
3
@mklement, если вы уже используете это решение, у вас не возникнет проблем, если вы сделаете что-то вроде этого: $(element2).attr("some-attr", $(element1).html());См. этот пример: jsbin.com/atibig/1/edit
travis
16
Это не избежать кавычек и двойных кавычек, что плохо! wonko.com/post/html-escaping
Лиор
601

Также есть решение от 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];
  });
}
Том Грунер
источник
7
Обратите внимание, что, как ни странно, 'отображается на объект в десятичном формате, тогда как /используется шестнадцатеричный формат.
mklement0
43
Это должен быть принятый ответ - он прост, эффективен, не требует никаких зависимостей и делает именно то, для чего предназначен, без скрытых взломов.
Lorefnon
6
Каковы рекомендации по переходу \nна <br>?
amwinter
2
Вот обновленная ссылка на источник: github.com/janl/mustache.js/blob/…
mjackson
8
@amwinter, я расширил скрипт выше, добавив "\ n": '<br>' к карте сущностей и обновил регулярное выражение в / [& <> "'\ /] | [\ n] / g
walv
182
$('<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

Хенрик Н
источник
11
Как уже упоминалось в ответе выше, это решение не гарантирует сохранение пробелов.
Джеффли
47
Следует отметить, что это ничего не делает, чтобы избежать одинарных или двойных кавычек. если вы планируете поместить значение в атрибут HTML, это может быть проблемой.
Кип
6
@Kip: @travis обнаружил, что attr()метод jQuery (по крайней мере с 1.8.3) выполняет свою собственную кодировку, так что незакодированные строки могут передаваться напрямую ; Например:$('<div/>').attr('test-attr', '\'Tis "fun" & stuff')[0].outerHTML
mklement0
1
@tarekahf Странно. Какую версию jQuery вы используете? Работает ли пример кода, если вы копируете и вставляете его дословно? Прекрасно работает с последней версией jQuery (3.1.0): jsbin.com/fazimigayo/1/edit?html,js,console,output (и она должна работать на всех более ранних версиях)
Henrik N
1
@tarekahf $('<div/>')создает новый divэлемент, который не присоединен к DOM. Так что это не изменит существующие элементы. Это немного сбивает с толку, как jQuery использует одну и ту же $()функцию как для поиска элементов ( $('div')), так и для их создания, а также для некоторых других вещей, кроме… :)
Henrik N
61

Если вы переходите на 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.

tghw
источник
13
Это регулярное выражение будет давать странные результаты, если рассматриваемый HTML уже экранировал сущности. Например, выход из «Тома и Джерри» даст «Тома и Джерри»
Райан,
12
Пожалуйста, используйте, varчтобы объявить itemлокально; в любом случае, не используйте for … inцикл при циклическом просмотре массива! forВместо этого используйте обычный цикл. О, и это encodeURIComponentне так escapeURIComponent.
Марсель Корпель
3
Если вы работаете с атрибутами тегов, вам также нужно будет избегать кавычек и / или двойных кавычек. Документация PHP для htmlspecialchars содержит полезный список преобразований, которые он выполняет. php.net/htmlspecialchars
Джеффли
4
Просто своего рода напоминание для новых людей, не используйте это , если вы собираетесь иметь не английские символы где - то на вашем сайте ... Очевидно , что это не будет делать из символов с акцентами , как «E»: &eacute; Вот список html-сущностей для справки: w3schools.com/tags/ref_entities.asp
LoganWolfer,
11
@Ryan: Хотя стоит отметить, что это решение неправильно обрабатывает уже закодированные строки, также ничего не стоит, что то же самое относится к большинству - возможно, ко всем - решениям на этой странице.
mklement0
37

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

_.escape(string) 

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

chovy
источник
36

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

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

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

Убегая /и 'тоже

Отредактируйте в ответ на комментарий mklement .

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

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функция

РЕДАКТИРОВАНИЕ 2: Исходная функция использовала переменную ( 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
источник
Спасибо, что нашли время, @Zrajm. Хорошая мысль о том, что вам не нужно убегать; есть идеи зачем и так mustache.jsи underscore.jsделать? Говоря о последнем: он распознает только числовые объекты (представляющие 'и /'), в заглавной шестнадцатеричной форме, когда не экранирует. Таким образом, текст ускользнул в mustache.js- который с любопытством использует смесь гекса. и десятичные форматы - не будут правильно удалены в underscore.js. Интересно, как другие популярные библиотеки справляются с этим.
mklement0
1
Нижняя форма случае шестигранной наиболее поддерживается форма, так что это (возможно) форма , что библиотеки должны быть преобразованы в . (Конечно, обе формы должны работать при конвертации из .) - У апострофов 'есть какая-то зарезервированная функция в XML (и, следовательно, XHTML, я так понимаю?), Поэтому у XML (но не HTML) есть именованная сущность &apos;. Точно, почему или каким образом это «зарезервировано», я не знаю. - Косые черты - это особые URL-адреса, но это на самом деле не гарантирует их включение в экранирующий HTML (поскольку кодирование URL-адреса является чем-то совершенно другим).
Зрайм
Re &apos;: правильно: безопасное использование только в XHTML ; прямо из уст краудсорсинга - подчеркиваю: «(...) чтение с помощью соответствующего HTML- процессора, (...) использование« или ссылки на собственные объекты могут не поддерживаться (...) »- на практике : современные браузеры поддерживают его даже в HTML . Re регистр в шестнадцатеричных числах. (тот же источник; выделение мое): «Символ x должен быть строчным в документах XML. […] hhhh может смешивать прописные и строчные буквы, хотя прописные буквы - это обычный стиль ». Оставляет нас удивляться, кто решил закодировать слэши; возможно на самом деле просто путаница между кодировкой URI и HTML?
mklement0
2
Заключительные мысли: кажется, что кодирование /не нужно, но кодирование 'все еще кажется полезным для безопасной обработки случая, когда закодированная строка используется в качестве значения атрибута, заключенного в одинарные кавычки .
mklement0
Оба они медленные. Самым быстрым решением с двузначным полем является серия замен, в которых передаются строки вместо функций.
Адам Леггетт
34

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

escaped = new Option(unescaped).innerHTML;

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

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

Адам Леггетт
источник
Это не меняет кавычки - по крайней мере, сейчас в Firefox 52.
getsetbro
1
Выход из кавычек имеет только функциональное значение в атрибутах. Поскольку мы экранируем <и >, экранировать кавычки также не имеет смысла, если только целью сгенерированного контента не является переход в атрибут.
Адам Леггетт
31

Вот простая и понятная функция JavaScript. Это будет экранировать текст, такой как «несколько <многие» в «несколько & lt; многие».

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;');
}
intrepidis
источник
28

После последних тестов я могу порекомендовать самое быстрое и полностью совместимое с браузером нативное решение 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
}

Посмотрите на мое окончательное сравнение производительности ( вопрос стека ).

Сары
источник
2
Нужно ли использовать два узла? Как насчет только одного:var p = document.createElement('p'); p.textContent = html; return p.innerHTML;
Дэн Даскалеску
2
@DanDascalescu: Согласно MDN , textContentфункция поддерживается только Chrome 1+, Firefox 2, IE9, Opera 9.64 и Safari 3 (последние два аннотированы «возможно раньше»). Это, таким образом, нарушило бы требование OP «полностью совместимо с браузерами».
zb226
p.innerText = html; return p.innerHTML
Беким Бакай
24

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

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

вывод:

'&lt;div&gt;Blah blah blah&lt;/div&gt;'
Никита Кокшаров
источник
20
Основная библиотека подчеркивания теперь имеет функцию _.escape()полезности.
Codeape
15

Я улучшил пример 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()

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

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

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

var escapedHtml = html.replace(/&/g, '&amp;')
                      .replace(/>/g, '&gt;')
                      .replace(/</g, '&lt;')
                      .replace(/"/g, '&quot;')
                      .replace(/'/g, '&apos;');
NicolasBernier
источник
Если вы собираетесь иметь "s, то вам нужно добавить хотя бы 'и `` к драке. Они нужны только для данных строковых тегов внутри элементов в html. Для самих данных html (внешних тегов) требуются только первые 3.
Мариус
10

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

_.escape('Curly, Larry & Moe'); // returns: Curly, Larry &amp; Moe
ronnbot
источник
5

Если вы собираетесь использовать регулярное выражение, в приведенном выше примере с 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]]);
}
Wayne
источник
2
Я считаю, что это должно быть для (var item в findReplace) {escaped = escaped.replace (findReplace [item] [0], findReplace [item] [1]); }
Крис Стивенс
5

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

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;
    }
}
amrp
источник
4
Какие исключения вы там подавляете?
Стефан Маевский
3

Вы можете легко сделать это с ванильным JS.

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

var escaped = document.createTextNode("<HTML TO/ESCAPE/>")
document.getElementById("[PARENT_NODE]").appendChild(escaped)
raam86
источник
2
(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;"
Gheljenor
источник
2

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>

Дэйв Браун
источник
2

Простой 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;"
Эндрю Лука
источник
3
Ответы только на код не рекомендуется, потому что они не объясняют, как они решают проблему. Пожалуйста, обновите свой ответ, чтобы объяснить, как это улучшает другие принятые и отклоненные ответы на этот вопрос. Кроме того, этому вопросу 9 лет, ваши усилия будут более оценены пользователями, у которых есть недавние вопросы без ответа. Пожалуйста, просмотрите, Как мне написать хороший ответ .
FluffyKitten
1
@FluffyKitten - это очень хорошо написанное сообщение в блоге о преимуществах и недостатках такой функции, которое подробно объясняет все, что вы хотели бы знать :) shebang.brandonmintern.com/…
db306
@ db306 Ответ был помечен как низкокачественный, поскольку ответ только для кода не соответствует рекомендациям по переполнению стека - см. Как написать хороший ответ . Мой комментарий был добавлен в процессе проверки, чтобы объяснить, что требуется для его улучшения, то есть ответ должен быть обновлен, чтобы объяснить, что делает код и как он улучшает существующие ответы. Положительные отзывы других рецензентов подтверждают это. Добавление внешней ссылки на комментарии по-прежнему не соответствует требованиям SO. Вместо этого Эндрю должен включить соответствующую информацию непосредственно в свой ответ.
FluffyKitten
Обратите внимание, что brandonmintern DOT com истек и теперь припаркован. Новый адрес Шебанга - shebang.mintern.net/foolproof-html-escaping-in-javascript/.
Брэндон
0
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);
}
Катхарапу Рамана
источник
0
function htmlDecode(t){
   if (t) return $('<div />').html(t).text();
}

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

d -_- б
источник
text удаляет теги html, но $ ('<div />'). html (t) .html (); работает
Бас Йобсен
0

Этот ответ предоставляет 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, поэтому его можно сразу отобразить в виде текста.
Сис Тиммерман
0

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

const escapeHTML = str => (str+'').replace(/[&<>"'`=\/]/g, s => ({'&': '&amp;','<': '&lt;','>': '&gt;','"': '&quot;',"'": '&#39;','/': '&#x2F;','`': '&#x60;','=': '&#x3D;'})[s]);
цыплята
источник
-2

Если вы сохраняете эту информацию в базе данных , неправильно экранировать 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
@Qualcuno Если вы выполняете эту проверку на клиенте и отправляете эту информацию на сервер, полагая, что она была проверена, пользователь может просто отредактировать запрос, и сценарий будет сохранен в базе данных.
Кау Гименес
@Qualcuno Я привел несколько примеров, чтобы прояснить мою точку зрения.
Кауэ Гименес
1
Вопрос был об экранировании строк, полученных с сервера, для их отображения в браузере. Вы говорите об экранировании строк перед их отправкой на сервер, и это совсем другое дело (хотя вы правы и возвращаетесь к старому правилу, никогда не принимайте слепо входные данные от клиента )
ItalyPaleAle
@Qualcuno Это популярный вопрос в Stackoverflow, и я считаю, что это важный момент, который необходимо рассмотреть. Вот почему я ответил.
Кауэ Гименес
-2

Все решения бесполезны, если вы не помешаете повторному выходу, например, большинство решений будут продолжать &выходить на &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] + ";";
        }
    ) : "";
};
С Нимманант
источник
4
Это называется двойным экранированием и должно быть исправлено, убедившись, что ваши входные данные еще не экранированы. Что если вы хотите буквально показать & lt; пользователю? Или, может быть, текст будет повторно использован в другом месте, и будет зависеть от того, что произошло побег?
телем