Могу ли я избежать специальных символов html в javascript?

202

Я хочу, чтобы отобразить текст в HTML с помощью функции JavaScript. Как я могу избежать специальных символов html в JS? Есть ли API?

fernando123
источник
11
Это не дубликат, так как этот вопрос не задает вопрос о jQuery. Меня интересует только этот, так как я не использую jQuery ...
lvella
4
возможный дубликат HtmlSpecialChars эквивалента в Javascript?
Берги

Ответы:

331
function escapeHtml(unsafe) {
    return unsafe
         .replace(/&/g, "&")
         .replace(/</g, "&lt;")
         .replace(/>/g, "&gt;")
         .replace(/"/g, "&quot;")
         .replace(/'/g, "&#039;");
 }
bjornd
источник
11
Почему "& # 039;" а не "" ?
Середа
36
потому что: stackoverflow.com/questions/2083754/…
Shreyans
2
Я думаю, что регулярные выражения в replace()вызовах не нужны. Обычные старые односимвольные строки тоже подойдут.
jamix
22
@jamix Вы не можете выполнить глобальную замену необработанными строками, в то время как современные браузерные движки довольно хорошо оптимизируют простое регулярное выражение.
Бьорнд
5
есть какой-нибудь стандартный API или это единственный способ?
Сунил Гарг
57

function escapeHtml(html){
  var text = document.createTextNode(html);
  var p = document.createElement('p');
  p.appendChild(text);
  return p.innerHTML;
}

// Escape while typing & print result
document.querySelector('input').addEventListener('input', e => {
  console.clear();
  console.log( escapeHtml(e.target.value) );
});
<input style='width:90%; padding:6px;' placeholder='&lt;b&gt;cool&lt;/b&gt;'>

spiderlama
источник
47

Вы можете использовать .text()функцию jQuery .

Например:

http://jsfiddle.net/9H6Ch/

Из документации jQuery относительно .text()функции:

Нам нужно знать, что этот метод экранирует строку, предоставленную по мере необходимости, чтобы он правильно отображался в HTML. Для этого он вызывает метод DOM .createTextNode (), не интерпретирует строку как HTML.

Предыдущие версии документации jQuery сформулировали это следующим образом ( выделение добавлено ):

Нам нужно знать, что этот метод экранирует строку, предоставленную по мере необходимости, чтобы он правильно отображался в HTML. Для этого он вызывает метод DOM .createTextNode (), который заменяет специальные символы их эквивалентами сущностей HTML (например, & lt; for <).

jeremysawesome
источник
3
Вы даже можете использовать его на новом элементе, если вы просто хотите конвертировать так: const str = "foo<>'\"&"; $('<div>').text(str).html()yieldsfoo&lt;&gt;'"&amp;
amoebe
28

Я думаю, что нашел правильный способ сделать это ...

// Create a DOM Text node:
var text_node = document.createTextNode(unescaped_text);

// Get the HTML element where you want to insert the text into:
var elem = document.getElementById('msg_span');

// Optional: clear its old contents
//elem.innerHTML = '';

// Append the text node into it:
elem.appendChild(text_node);
lvella
источник
Сегодня я узнал что-то новое о HTML. w3schools.com/jsref/met_document_createtextnode.asp .
Sellorio
1
Имейте в виду, что содержимое текстового узла не может быть экранировано, если вы попытаетесь получить к нему доступ следующим образом:document.createTextNode("<script>alert('Attack!')</script>").textContent
maechler
Это правильный путь, если все, что вы делаете, это настраиваете текст. Это также textContent, но, видимо, он не очень хорошо поддерживается. Это не сработает, однако, если вы создаете строку с некоторыми частями текста html, то вам все равно нужно бежать.
jgmjgm
21

Это, безусловно, самый быстрый способ, которым я видел это. Плюс, все это делается без добавления, удаления или изменения элементов на странице.

function escapeHTML(unsafeText) {
    let div = document.createElement('div');
    div.innerText = unsafeText;
    return div.innerHTML;
}
arjunpat
источник
7
Предупреждение: он не экранирует кавычки, поэтому вы не можете использовать выходные данные внутри значений атрибутов в коде HTML. Например, var divCode = '<div data-title="' + escapeHTML('Jerry "Bull" Winston') + '">Div content</div>'приведет к неверному HTML!
Изогфиф
17

Интересно было найти лучшее решение:

var escapeHTML = function(unsafe) {
  return unsafe.replace(/[&<"']/g, function(m) {
    switch (m) {
      case '&':
        return '&amp;';
      case '<':
        return '&lt;';
      case '"':
        return '&quot;';
      default:
        return '&#039;';
    }
  });
};

Я не анализирую, >потому что это не нарушает XML / HTML-код в результате.

Вот тесты: http://jsperf.com/regexpairs Также я создал универсальную escapeфункцию: http://jsperf.com/regexpairs2

iegik
источник
1
Интересно видеть, что использование переключателя значительно быстрее, чем карта. Я не ожидал этого! Спасибо, что поделился!
Питер Т.
Существует намного больше символов Юникода, чем вы могли бы кодировать и принимать во внимание. Я не рекомендовал бы этот ручной метод вообще.
vsync
Зачем вообще избегать многобайтовые символы? Просто используйте UTF-8 везде.
Неонит
4
Пропуск> может потенциально нарушить код. Вы должны иметь в виду, что внутри <> также есть HTML. В этом случае пропуск> сломается. Если вы используете экранирование только между тегами, вам, вероятно, нужно только экранировать <и &.
jgmjgm
8

Самый краткий и эффективный способ отображения незакодированного текста - это использование textContentсвойства.

Быстрее, чем используя innerHTML. И это без учета возможности избежать накладных расходов.

document.body.textContent = 'a <b> c </b>';

пользователь
источник
@ZzZombo, совершенно нормально, что он не работает со стилем и тегами скрипта. Когда вы добавляете к ним контент, вы добавляете код , а не текст , в этом случае используйте innerHTML. Более того, вам не нужно избегать этого, это два специальных тега, которые не анализируются как HTML. При синтаксическом анализе их содержимое обрабатывается как текст, пока не </будет достигнута завершающая последовательность .
пользователь
6

DOM Elements поддерживает преобразование текста в HTML, присваивая innerText . innerText не является функцией, но присвоение ей работает так, как если бы текст был экранирован.

document.querySelectorAll('#id')[0].innerText = 'unsafe " String >><>';
teknopaul
источник
1
По крайней мере, в Chrome назначение многострочного текста добавляет <br>элементы вместо новых строк, которые могут нарушать определенные элементы, такие как стили или сценарии. createTextNodeНе склонен к этой проблеме.
ZzZombo
1
innerTextимеет некоторые проблемы наследства / спецификации. Лучше использовать textContent.
Рой Тинкер
3

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

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

Или просто нацеливайтесь на главных героев, о которых нужно беспокоиться (&, inebreaks, <,>, "и '), например:

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

test.value=encode('How to encode\nonly html tags &<>\'" nice & fast!');

/*************
* \x26 is &ampersand (it has to be first),
* \x0A is newline,
*************/
<textarea id=test rows="9" cols="55">&#119;&#119;&#119;&#46;&#87;&#72;&#65;&#75;&#46;&#99;&#111;&#109;</textarea>

Дэйв Браун
источник
Написание собственной функции escape - вообще плохая идея. Другие ответы лучше в этом отношении.
Яннис
2

Однострочник (для ES6 +):

var escapeHtml = s => (s + '').replace(/[&<>"']/g, m => ({
    '&': '&amp;', '<': '&lt;', '>': '&gt;',
    '"': '&quot;', "'": '&#39;'
})[m]);

Для более старых версий:

function escapeHtml(s) {
    return (s + '').replace(/[&<>"']/g, function (m) {
        return ({
            '&': '&amp;', '<': '&lt;', '>': '&gt;',
            '"': '&quot;', "'": '&#39;'
        })[m];
    });
}
Ossia
источник
0

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

var _div = document.createElement('div');
var _separator = document.createTextNode('&raquo;');
//_div.appendChild(_separator); /* this resulted in '&raquo;' being displayed */
_div.innerHTML = _separator.textContent; /* this was key */
Сайлас
источник
0

Если вы уже используете модули в своем приложении, вы можете использовать escape-html module.

import escapeHtml from 'escape-html';
const unsafeString = '<script>alert("XSS");</script>';
const safeString = escapeHtml(unsafeString);
Шимон С
источник
-3

Попробуйте это, используя prototype.jsбиблиотеку:

string.escapeHTML();

Попробуйте демо

Счастливый
источник
5
Для этого требуется библиотека "prototype.js", которая не была сразу очевидна из демонстрации. :(
audiodude
-4

Я придумал это решение.

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

var unsafe = 'some unsafe data like <script>alert("oops");</script> here';

var html = '';
html += '<div>';
html += '<p>' + unsafe + '</p>';
html += '</div>';

element.html(html);

Это небезопасно против атак XSS. Теперь добавьте это.

$(document.createElement('div')).html(unsafe).text();

Так что, это

var unsafe = 'some unsafe data like <script>alert("oops");</script> here';

var html = '';
html += '<div>';
html += '<p>' + $(document.createElement('div')).html(unsafe).text(); + '</p>';
html += '</div>';

element.html(html);

Для меня это намного проще, чем использовать, .replace()и это удалит !!! все возможные теги HTML (я надеюсь).

Kostiantyn
источник
это опасная идея, она анализирует небезопасную строку HTML как HTML, если элемент был присоединен к DOM, который он исполнил бы. используйте вместо этого .innerText.
Текнопаул
Это не безопасно. Это превращается &lt;script&gt;в <script>.
августа