Использование свойства innerHTML в JavaScript позволяет
динамически вставлять HTML-контент в DOM. Оно чрезвычайно удобно для
обновления содержимого страницы, но несет в себе значительные
риски безопасности, связанные с XSS (Cross-Site
Scripting). Основная опасность заключается в том, что любой ввод
пользователя, вставленный через innerHTML, может быть
интерпретирован как код браузером, что позволяет злоумышленнику
выполнять произвольный JavaScript.
Встраивание скриптов
element.innerHTML = '<img src="x" oner ror="alert(\'XSS\')">';
В этом примере атрибут onerror выполнит JavaScript при
загрузке изображения. Если данные поступают от пользователя,
злоумышленник может вставить такой код, вызывая нежелательные
действия.
Манипуляции с DOM Через innerHTML
можно вставить <script> или
<iframe> с вредоносным содержимым:
element.innerHTML = '<script>alert("Вредоносный код")</script>';
Скрипт выполнится немедленно, что создает прямую угрозу безопасности.
Атаки через события и атрибуты HTML Помимо
<script> можно использовать события
(onclick, onmouseover) и динамически
загружаемые ресурсы (<iframe src=...>).
Любые данные, вставляемые через innerHTML, должны быть
очищены или экранированы.
Экранирование заменяет специальные символы HTML на безопасные
сущности:
| Символ | Экранирование |
|---|---|
< |
< |
> |
> |
& |
& |
" |
" |
' |
' |
Пример функции экранирования:
function escapeHTML(str) {
return str.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
element.innerHTML = escapeHTML(userInput);
Этот подход гарантирует, что любые пользовательские символы будут интерпретированы как текст, а не как HTML.
textContent вместо innerHTMLЕсли нужно вставить только текст, безопаснее
использовать свойство textContent:
element.textContent = userInput;
textContent автоматически экранирует все HTML-символы,
предотвращая XSS, и делает использование innerHTML ненужным
для обычного текста.
Для вставки сложной структуры вместо конкатенации строк лучше использовать методы создания элементов:
const div = document.createElement('div');
const span = document.createElement('span');
span.textContent = userInput; // безопасно
div.appendChild(span);
container.appendChild(div);
Такой способ предотвращает выполнение нежелательного JavaScript, так как текст добавляется безопасно, а структура строится через DOM-методы.
Для проектов, где вставляется HTML, полученный от пользователей (например, комментарии, сообщения), рекомендуется использовать библиотеки для санитизации, которые удаляют потенциально опасные теги и атрибуты. Примеры:
Пример с DOMPurify:
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);
Библиотека удаляет все <script> и опасные
атрибуты, оставляя безопасный HTML.
Popper.js часто используется для создания всплывающих подсказок и
тултипов, где содержимое может динамически обновляться. При интеграции с
innerHTML важно учитывать:
Контент тултипа должен быть безопасным Даже если Popper.js отвечает за позиционирование, любой HTML, вставляемый в тултип, следует очищать или экранировать.
const tooltipContent = escapeHTML(userInput);
tooltipElement.innerHTML = tooltipContent;Минимизация использования innerHTML
Внутри Popper.js предпочтительно использовать textContent
или заранее подготовленные элементы с DOM API.
Случаи с HTML-тултипами Если необходим HTML в тултипе (например, ссылки или стилизованные элементы), использовать проверенные шаблоны и санитизацию библиотекой.
innerHTML.textContent для текста и DOM-методы для
элементов.Эти подходы позволяют обеспечить безопасность при динамическом обновлении DOM, снизить риск XSS и сохранить контроль над HTML-структурой страницы.