XSS (Cross-Site Scripting) — это тип уязвимости веб-приложений, при которой злоумышленник может внедрять вредоносный скрипт в страницы, просматриваемые другими пользователями. Эти скрипты исполняются в браузере жертвы с правами пользователя, что позволяет похищать данные, изменять содержимое страницы или выполнять нежелательные действия от имени пользователя.
Существуют три основных типа XSS:
Любой сценарий, где данные извлекаются из внешнего источника и вставляются на страницу без фильтрации, потенциально опасен. Примеры источников:
Ключевой фактор — отсутствие экранирования специальных
символов HTML и JavaScript. Символы <,
>, ", ', &
могут позволить внедрить теги <script> или
обработчики событий, такие как onclick, что приведет к
выполнению произвольного кода.
Intro.js позволяет создавать интерактивные туры по интерфейсу
веб-приложения, вставляя подсказки (tooltips) и выделяя элементы
страницы. Для вставки текста используется свойство
intro:
introJs().setOptions({
steps: [
{
element: '#step1',
intro: 'Добро пожаловать на сайт!'
}
]
}).start();
Если значение intro формируется из пользовательского
ввода, любая HTML-теговая или скриптовая вставка может стать
уязвимостью XSS:
let userInput = getUserInput(); // допустим, пользователь ввел <img src=x oner ror=alert(1)>
introJs().setOptions({
steps: [
{
element: '#step1',
intro: userInput
}
]
}).start();
В этом случае скрипт <img src=x oner ror=alert(1)>
выполнится в браузере любого посетителя.
<,
>, &, " и '
отображались как текст, а не как код:function escapeHtml(text) {
return text
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
let safeInput = escapeHtml(getUserInput());
introJs().setOptions({
steps: [
{ element: '#step1', intro: safeInput }
]
}).start();
Использование textContent вместо
innerHTML Внутри шагов Intro.js библиотека по
умолчанию вставляет HTML. Для кастомных контейнеров, если есть
возможность, следует использовать textContent вместо
прямого внедрения HTML.
Валидация и фильтрация данных Для полей, где допустим только текст, ограничить разрешенные символы и блокировать теги HTML.
Применение Content Security Policy (CSP) CSP позволяет запрещать выполнение встроенного JavaScript, что ограничивает последствия возможного XSS:
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none';
intro использовать
безопасные шаблонизаторы или функции, которые автоматически экранируют
данные.Динамический шаг с безопасной обработкой ввода пользователя:
const userNotes = fetchUserNotes(); // массив заметок
const steps = userNotes.map(note => ({
element: '#note-' + note.id,
intro: escapeHtml(note.text)
}));
introJs().setOptions({ steps }).start();
В этом примере любая попытка вставить HTML или скрипт пользователем
нейтрализуется функцией escapeHtml.
Добавление элементов с заранее определенным HTML, исключая пользовательский ввод:
introJs().setOptions({
steps: [
{
element: '#feature1',
intro: 'Используйте эту кнопку для сохранения данных.'
}
]
}).start();
Здесь все строки заданы разработчиком, что полностью исключает риск XSS.
Если структура шагов сохраняется в базе данных для последующего отображения, необходимо:
<script> и обработчики
событийIntro.js взаимодействует с DOM напрямую, выделяя элементы и вставляя подсказки. Если пользователь может контролировать селекторы элементов или содержимое шага, возможен DOM-based XSS. Примеры опасных сценариев:
localStorage или
sessionStorage без фильтрацииЗащита: никогда не использовать пользовательский ввод напрямую для селекторов или HTML-контента.
intro.Такой подход минимизирует риск внедрения вредоносного кода и обеспечивает безопасное использование интерактивных туров.