Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як безпечно обмінюватися повідомленнями між вікнами через postMessage?

postMessage - легальний спосіб обміну даними між вікнами різних походжень: сторінка й вбудований <iframe> платіжної форми, вікно OAuth-входу й основний застосунок, віджет на чужому сайті й ваш сервер.

// відправник
iframe.contentWindow.postMessage({ type: 'resize', height: 640 }, 'https://widget.example');

// отримувач
window.addEventListener('message', (event) => {
  if (event.origin !== 'https://app.example') return;   // обов'язкова перевірка
  if (event.data?.type === 'resize') {
    iframe.style.height = `${Number(event.data.height)}px`;
  }
});

Дві обов'язкові перевірки:

1. При відправленні - конкретне targetOrigin, а не '*'.

popup.postMessage({ token }, '*');   // небезпечно

Якщо вікно встигли перенаправити на інший сайт (наприклад, фрейм завантажив сторінку нападника), повідомлення з токеном отримає чужий код. З конкретним targetOrigin браузер просто не доставить повідомлення не тому адресату.

2. При отриманні - перевірка event.origin. Будь-яка сторінка, що має посилання на ваше вікно (відкрила його через window.open чи вбудувала у фрейм), може надіслати йому повідомлення. Без перевірки обробник виконає команди нападника.

Типові помилки:

  • перевірка походження за підрядком: event.origin.includes('example.com') пропустить https://example.com.attacker.io. Лише точне порівняння з переліком;
  • довіра вмісту від довіреного походження: навіть повідомлення від свого фрейму - це дані, які могли прийти від користувача. Небезпечно передавати їх у innerHTML, eval, location.href (схема javascript:);
  • event.source без перевірки - відповідати варто лише на event.source, а не на «будь-яке вікно»;
  • чутливі дані в повідомленнях без потреби - кожне повідомлення може побачити розширення браузера чи інший слухач на тій самій сторінці;
  • слухачі, що лишилися після закриття фрейму, - накопичуються в SPA.

Структура повідомлень: тип і версія в кожному повідомленні, валідація схеми (як для API). Повідомлення - це міжсайтовий API, і до нього ті самі вимоги.

Альтернатива для однієї вкладки свого ж походження - BroadcastChannel, а для запитів між вікнами з відповіддю - MessageChannel з окремими портами: менше слухачів на глобальному window.

Докладніше в документації: MDN: Window.postMessage()

Схожі питання