Найдите DOM XSS в обработчике postMessage
Этот обработчик принимает межоконные события postMessage и переходит по запросу. Найдите клиентский (DOM) XSS и опишите исправление.
Ограничения:
- обработчик доверяет любому отправителю — нет проверки
event.origin urlберётся прямо из тела сообщения
function handleMessage(e) {
const data = JSON.parse(e.data);
if (data.type === "go_to_link") {
window.location.assign(data.url);
}
}
window.addEventListener("message", handleMessage);
Найдите и исправьте ошибку.
DOM XSS: любое окно может прислать {type:'go_to_link', url:'javascript:alert(1)'}, и обработчик выполнит это через location.assign, запустив скрипт. Два изъяна: нет белого списка event.origin и нет проверки схемы URL. Фикс: проверять e.origin по доверенному списку, затем принимать только http/https URL (отклонять javascript:/data:) перед переходом.
- ✗Принимать DOM XSS за DoS, CSRF или отсутствие экранирования вывода
- ✗Думать, что
location.assignне исполняет схемуjavascript: - ✗Чинить только одну из двух проблем (origin ИЛИ схему URL)
- →Почему проверки
event.originнедостаточно без валидации схемы URL? - →Чем DOM XSS отличается от отражённого XSS по месту исполнения?
Уязвимость
Обработчик принимает сообщение от любого окна (нет проверки e.origin) и переходит по url из тела:
window.location.assign(data.url);
location.assign("javascript:alert(1)") исполняет JS в контексте страницы. Атакующее окно шлёт {type:'go_to_link', url:'javascript:alert(document.cookie)'} — это DOM XSS.
Исправление
const TRUSTED = ["https://app.example.com"];
function handleMessage(e) {
if (!TRUSTED.includes(e.origin)) return;
const data = JSON.parse(e.data);
if (data.type === "go_to_link") {
const u = new URL(data.url, location.href);
if (u.protocol === "http:" || u.protocol === "https:") {
window.location.assign(u.href);
}
}
}
✅ Проверяем e.origin по белому списку И схему URL. ⚠️ Любой одной проверки мало.