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


202

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


11
Это не дубликат, так как этот вопрос не задает вопрос о jQuery. Меня интересует только этот, так как я не использую jQuery ...
lvella

Ответы:


331
function escapeHtml(unsafe) {
    return unsafe
         .replace(/&/g, "&")
         .replace(/</g, "&lt;")
         .replace(/>/g, "&gt;")
         .replace(/"/g, "&quot;")
         .replace(/'/g, "&#039;");
 }

11
Почему "& # 039;" а не "" ?
Середа


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;'>



47

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

Например:

http://jsfiddle.net/9H6Ch/

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

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

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

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


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);

Сегодня я узнал что-то новое о 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;
}

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


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 >><>';

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];
    });
}

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);


-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 (я надеюсь).


это опасная идея, она анализирует небезопасную строку HTML как HTML, если элемент был присоединен к DOM, который он исполнил бы. используйте вместо этого .innerText.
Текнопаул

Это не безопасно. Это превращается &lt;script&gt;в <script>.
августа
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.