Является ли это безопасным способом преобразования html в текст

#javascript #xss

#javascript #xss

Вопрос:

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

Я придумал это:

 function convertHtmlToText(html) {
    const div = document.createElement("div");
    // assumpton: because the div is not part of the document 
    // - no scripts are executed
    // - no layout pass
    div.innerHTML = html; 
    // assumption: whitespace is still normalized
    // assumption: this returns the text a user would see, if the element was inserted into the DOM.
    //             Minus the stuff that would depend on stylesheets anyway.
    return div.innerText; 
}

const html = `
    Some random untrusted string that is supposed to contain html. 
    Presumably some 'rich text'. 
    A few <div> or <p>, a link or two, a bit of <strong> and some such. 
    In any case not a complete html document.
`;

const text = convertHtmlToText(html);

const p = document.createElement("p");
p.textContent = text;
document.body.append(p);
  

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

Вопрос: Безопасно ли это?

Комментарии:

1. Да. Использование свойства textContent предотвратит выполнение всех XSS. Использование innerHTML было бы возможной ошибкой.

2. Да, это предпочтительный способ добиться этого.

3. Я не думаю, что в безопасности существуют такие вещи, как «полуповерие». ИМХО, это все или ничего. Вам действительно следует использовать для этого фреймворки или библиотеки.

4. @customcommander Вы, конечно, правы. Что я имел в виду, когда писал полу-доверенный , так это то, что я не рассматриваю API для отправки враждебного контента в общем случае. Поэтому мне пришлось бы провести дезинфекцию, чтобы предотвратить возможные XSS, но преобразованный текст, искаженный или пустой, был бы в порядке. Наихудшим возможным сценарием было бы получение пользователем ложного положительного / отрицательного результата поиска.

5. Некоторые комментарии здесь могут заставить будущих читателей поверить, что ваша первоначальная реализация была безопасной; это не так, как показано в ответе ниже. В идеале эти комментарии должны быть отредактированы.

Ответ №1:

Нет, это совсем небезопасно.

 function convertHtmlToText(html) {
    const div = document.createElement("div");
    // assumpton: because the div is not part of the document 
    // - no scripts are executed
    // - no layout pass
    div.innerHTML = html; 
    // assumption: whitespace is still normalized
    // assumption: this returns the text a user would see, if the element was inserted into the DOM.
    //             Minus the stuff that would depend on stylesheets anyway.
    return div.innerText; 
}

const html = `<img onerror="alert('Gotcha!')" src="">Hi`;

const text = convertHtmlToText(html);

const p = document.createElement("p");
p.textContent = text;
document.body.append(p);  

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

 function convertHtmlToText(html) {
  const doc = new DOMParser().parseFromString(html, 'text/html');
  return doc.body.innerText;
}

const html = `<img onerror="alert('Gotcha!')" src="">Hi`;

const text = convertHtmlToText(html);

const p = document.createElement("p");
p.textContent = text;
document.body.append(p);  

Но будьте осторожны, эти методы также будут перехватывать текстовое содержимое узлов, которые пользователи обычно не могут видеть (например, <style> или <script> ).