#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>
).