В методичке много написано о внедрении шпионских метрик в клиентские приложения, что как раз является наименьшей проблемой, так как split tunneling на уровне приложений, контейнеризация и т.д. позволяют обходить их на любой платформе. В соседних темах даже звучал радикальный вариант удаления всех потенциально скомпрометированных российских приложений со смартфонов и переход на веб-версии сервисов в браузере. Я же считаю, что это не панацея.
В недавней статье с разбором шпионской метрики, встроенной в Max, было выявлено что он, помимо прочего, пытается определять доступность main.telegram.org. На уровне изолированного приложения с настроенным split tunneling такая проверка не страшна, но в будущем такие же метрики наверняка будут встроены в веб-приложения российских сервисов.
Split tunneling от такой атаки не поможет. В этой схеме вы обращаетесь на, допустим, скомпрометированный ozon.ru со своего домашнего ip адреса (если разделение туннелей происходит на вашем марштрутизаторе) или ip адреса вашего российского vps (входной ноды вашего multi-hop прокси, на которой происходит разделение), после чего скомпрометированный сайт проверяет доступность “запрещённого” сервиса, запустив вредоносный код в вашем браузере. Таким образом, вы даёте скомпрометированному ресурсу узнать ваш российский ip (так или иначе привязанный к личности) и факт, что из вашего браузера доступны “запрещённые” ресурсы.
В современных браузерах существуют способы, позволяющие веб-приложению определить доступность удалённого ресурса в обход CORS. Вот минимальный сниппет, определяющий доступность телеграм из вашего браузера. Полагаю, подобные метрики будут в скором будущем внедрены на скомпрометированных веб-сайтах.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Telegram availability check</title>
</head>
<body>
<button id="check">Check telegram availability</button>
<div id="result"></div>
<script>
function checkSiteAvailability(url, timeout = 5000) {
return new Promise((resolve) => {
const img = new Image();
let resolved = false;
const startTime = Date.now();
const timeoutId = setTimeout(() => {
if (!resolved) {
resolved = true;
resolve({
available: false,
error: 'Timeout'
});
}
}, timeout);
img.onload = () => {
if (!resolved) {
resolved = true;
clearTimeout(timeoutId);
resolve({
available: true
});
}
};
img.onerror = () => {
if (!resolved) {
resolved = true;
clearTimeout(timeoutId);
resolve({
available: false,
error: 'Failed to load'
});
}
};
let cleanUrl = url.replace(/\/$/, '');
img.src = `${cleanUrl}/favicon.ico?nocache=${Date.now()}`;
});
}
async function checkTelegramAvailability() {
const resultDiv = document.getElementById('result');
const url = "https://web.telegram.org";
resultDiv.innerHTML = `Trying ${url}...`;
const result = await checkSiteAvailability(url);
if (result.available) {
resultDiv.innerHTML = `${url} is available. Are you using a proxy?`;
} else {
resultDiv.innerHTML = `${url} is not available. Error: ${result.error || "Unexpected"}`;
}
}
document.getElementById('check').addEventListener('click', checkTelegramAvailability);
</script>
</html>
Чтобы поиграться с примером локально, сохраните сниппет в index.html и запустите веб-сервер в той же директории, например python3 -m http.server 8080. Или просто откройте файл в браузере.
Факт доступности запрещённого ресурса с устройства пользователя сам собой не доказывает факта использования средств обхода блокировок, но, учитывая комплесный подход к определению недоброжелательных пользователей в методичке Минцифры, может быть учтён в дополнение к другим косвенным доказательствам использования средств обхода.
Насколько я вижу, единственный способ избежать такой атаки - это использование двух браузеров, одного тунеллированного напрямую, а другого через удалённый прокси, даже на десктопе. Трафик до российских сервисов для второго браузера должен быть закрыт (например, с помощью blackhole outbound в xray или blocked в sing-box), чтобы предотвратить случайный клик по ссылке на скомпрометированный сайт в проксированном браузере.