Как сайты отличают настоящий смартфон от арендованного Android: строки GPU-рендерера, отсутствие датчиков, однородность железа и отсутствие веб-аттестации.
«Облачный телефон» — это реальный (или виртуализированный) экземпляр Android, работающий на удалённом сервере и управляемый через транслируемый экран или удалённый API, а не через устройство у вас в руках. Такие инстансы арендуют поминутно, разворачивают тысячами и сбрасывают до чистого состояния по требованию — они стали новой альтернативой подмене отпечатка десктопного браузера: запрос выглядит так, будто пришёл с настоящего мобильного телефона, потому что технически какой-то его слой действительно им является. Обнаружить такие сессии — не значит поймать ложь в строке user-agent; речь о том, согласуется ли всё, что сообщает мобильный браузер, с реальным физическим телефоном. В этом материале разберём сигналы, которые отвечают на этот вопрос.
Ключевые выводы
- Облачные и эмулированные инстансы Android обычно не могут предъявить настоящий GPU. Там, где физический телефон через
WEBGL_debug_renderer_infoсообщаетAdreno,MaliилиPowerVR, виртуализированный сообщает программный или проброшенный рендерер вродеSwiftShader,llvmpipeилиvirtio-gpu. - Реальные телефоны выдают показания акселерометра и гироскопа с индивидуальным калибровочным шумом даже лёжа неподвижно на столе; за облачным инстансом не стоит никакого физического чипа для этих Sensor API, поэтому он либо ничего не сообщает, либо выдаёт подозрительно постоянное значение.
- Один арендованный инстанс — это мобильный посетитель. Тысячи «разных пользователей», сообщающих одинаковые
hardwareConcurrency,deviceMemoryи разрешение экрана, — это корреляция масштаба фермы, а не совпадение. - Нативные Android-приложения могут потребовать вердикт Play Integrity, подтверждённый железом, который облачному инстансу сложно предоставить; у открытого веба нет аналога, и именно поэтому обнаружение на стороне браузера опирается на проверки согласованности, разобранные в этом материале.
- Собственные значения рендерера GPU, доступности датчиков и
hardwareConcurrencyможно увидеть с помощью проверки отпечатка от BrowserInsight.
От десктопных профилей к арендованным Android-инстансам
Инструменты для подмены отпечатка годами фокусировались на десктопном браузере: подменить user-agent, пропатчить хеш canvas, внедрить правдоподобную строку GPU — и надеяться, что все кусочки сойдутся друг с другом. Обнаружение подтянулось следом — обнаружение антидетект-браузеров теперь регулярно ловит именно такие слепленные из заплаток десктопные профили, проверяя согласованность их сигналов между собой. Облачный телефон обходит эту борьбу иначе: вместо того чтобы подделывать мобильный отпечаток с десктопной машины, он где-то в дата-центре запускает настоящий (или виртуализированный) стек Android и предъявляет реальный, неподделанный браузер этой сессии как «устройство». User-agent не лжёт. Не хватает того, что несёт в себе физический телефон, а серверная стойка — нет: чипа GPU, аппаратуры движения и естественного разнообразия железа, которое даёт один телефон на одного пользователя.
Именно на этот неустаревающий вопрос отвечает статья — не о том, какой поставщик сдаёт такие инстансы в аренду или как сделать ферму убедительной, а о том, как сайт изнутри браузерной сессии определяет, стоит ли за запросом физический телефон или виртуализированный заменитель.
Сигнал 1: строка рендерера GPU
Каждый мобильный GPU — это физический чип с названием, и это название появляется в расширении WebGL WEBGL_debug_renderer_info точно так же, как и на десктопе — о том, насколько жёстко строка рендерера привязана к железу под ней, читайте в статье «Невозможные отпечатки: несовместимые GPU, ОС и шрифты». Реальный Android-телефон сообщает строку вендора из одного из небольшого набора семейств мобильных GPU:
const gl = document.createElement('canvas').getContext('webgl');
const dbg = gl.getExtension('WEBGL_debug_renderer_info');
gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL);
// Реальный телефон: "Adreno (TM) 740" или "Mali-G715-Immortalis" или "PowerVR Rogue GE8320"
// Облачный инстанс: "ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero)), SwiftShader driver)"
// Эмулированный Android: "llvmpipe (LLVM 15.0.7, 256 bits)" или строка проброса virtio-gpu
SwiftShader, llvmpipe и virtio-gpu — это программные рендереры или рендереры уровня виртуализации: они существуют именно потому, что у машины, на которой работает браузер, нет выделенного мобильного GPU, которому можно было бы передать работу. Размещённый на сервере Android-инстанс либо откатывается к одному из них, либо пробрасывает строку GPU хост-машины, принадлежащую десктопной видеокарте класса NVIDIA или AMD, — а это уже само по себе улика: ни один телефон в мире не поставляется с чипом NVIDIA GeForce. В любом случае строка рендерера называет железо, которого в реальном телефоне быть не может.
Одна оговорка не даёт считать этот признак самодостаточным: далеко не каждый хостящийся Android-инстанс работает на серверном x86-железе. Часть провайдеров собирает свои парки на ARM-серверных платах, часть просто ставит физические смартфоны в стойку в дата-центре и открывает к ним удалённый доступ — и такие инстансы вполне могут сообщить совершенно настоящую строку Adreno или Mali, потому что рендерингом действительно занимается реальный мобильный GPU. Вывод работает только в одну сторону: программный или виртуализационный рендерер — сильное свидетельство виртуализованного стека, а вот правдоподобный мобильный рендерер не доказывает, что за сессией стоит физический телефон в чьих-то руках. Из-за этой асимметрии основную нагрузку берут на себя сигналы ниже — всякий раз, когда строка GPU выглядит чистой.
Сигнал 2: датчики движения, которых не существует
Реальные телефоны несут в себе акселерометр и гироскоп, и — как рассказано в статье «Фингерпринтинг сенсоров: акселерометр и гироскоп» — эти чипы оставляют в показаниях устойчивую, индивидуальную для устройства калибровочную подпись даже когда телефон неподвижно лежит на столе. У облачного или эмулированного инстанса такого чипа нет нигде в цепочке железа. Чтение API DeviceMotionEvent или создание объекта Accelerometer из семейства Sensor API на таком инстансе обычно даёт одну из двух улик. Либо показания так и не приходят: обработчик devicemotion вовсе не срабатывает или срабатывает с полями ускорения, целиком заполненными null, а конструктор Accelerometer завершается ошибкой, потому что платформа не сообщает о таком датчике. Либо слой эмуляции подставляет синтетические значения — и тогда они возвращаются подозрительно чистыми: постоянное показание без того небольшого дрейфа по каждой оси, который дают производственные допуски настоящего чипа. У физического телефона уровень шума никогда не бывает идеально ровным; у скриптового значения по умолчанию — часто бывает.
Сигнал 3: однородность железа в масштабе фермы
Любая отдельно взятая сессия облачного телефона, проверенная изолированно, может выглядеть правдоподобно — ферму устройств выдаёт именно паттерн, повторяющийся во множестве сессий. У реальной популяции мобильных посетителей есть естественное разнообразие железа: разные чипсеты сообщают разное число ядер в hardwareConcurrency, разные уровни deviceMemory и разброс разрешений экрана по поколениям телефонов. Ферма устройств разворачивает множество инстансов из одной и той же горстки образов виртуальных машин, поэтому сотни или тысячи сессий, выдающих себя за разных пользователей, одновременно сходятся к идентичному числу ядер, уровню памяти, размеру экрана и строке рендерера GPU. Сама по себе ни одна отдельная сессия не выглядит невозможной — систему обнаружения интересует именно корреляция между сессиями, та же логика рассуждений на уровне агрегата, которую обнаружение ботов по поведению применяет к паттернам взаимодействия, а не к статическим свойствам устройства.
Сигнал 4: согласованность касаний, указателя и viewport
У реального телефона сигналы касания и viewport по конструкции согласуются друг с другом: navigator.maxTouchPoints сообщает ненулевое значение, CSS-медиафича (pointer: coarse) совпадает, а размеры viewport укладываются в диапазон реально выпускаемого экрана при правдоподобном device-pixel-ratio. Инфраструктура облачных телефонов, транслирующая удалённый экран или предоставляющая браузер через API удалённого управления, может сбоить по любому из этих пунктов: управляемый мышью слой, подающий синтетические события касания, viewport, подогнанный под окно трансляции, а не под физические размеры настоящего экрана, или device-pixel-ratio, не соответствующий ни одному реально продающемуся телефону. Ни один из этих признаков сам по себе не приговор — изменённый размер окна браузера может выглядеть необычно и на реальном телефоне, — но в сочетании с несовпадающей строкой GPU и отсутствующими датчиками они дополняют ту же картину.
Почему у веба нет резервной аттестации
У нативных Android-приложений в распоряжении гораздо более сильный инструмент: аттестация устройства. Приложение может вызвать Play Integrity API от Google и получить вердикт, подтверждённый железом — подписанный доверенной средой выполнения, — утверждающий, что устройство и приложение подлинные и не изменены, вместо того чтобы делать вывод по куче сигналов, которые можно подделать. В обновлении Google об обнаружении угроз в Play Integrity вердикт deviceIntegrity описан как ответ на вопрос, работает ли приложение на подлинном, сертифицированном Play Protect устройстве Android, — планка, которую арендованный облачный инстанс, как правило, не берёт: за ним нет подтверждённого железом ключа настоящего устройства, а значит, нет и корректного токена аттестации.
У открытого веба нет ничего равнозначного. Предложенный Google API Web Environment Integrity — браузерный аналог Play Integrity — был отозван до выхода, так что сегодня ни один браузер не выдаёт сайту токен аттестации. Именно поэтому обнаружению облачных телефонов на стороне браузера приходится опираться на описанные выше проверки согласованности: без криптографического доказательства для проверки сайту остаётся делать вывод «настоящий телефон или виртуализированный заменитель», исходя из того, согласуются ли GPU, датчики, профиль железа и сигналы касания друг с другом так, как согласуются они у настоящего телефона.
| Сигнал | Настоящий телефон | Облачный / эмулированный инстанс |
|---|---|---|
| Строка рендерера GPU | Строка вендора Adreno, Mali, PowerVR | SwiftShader, llvmpipe, virtio-gpu или строка десктопной NVIDIA/AMD |
| Датчики движения | Живые показания с индивидуальным калибровочным шумом | Отсутствуют, выбрасывают исключение или подозрительно постоянное синтетическое значение |
| Профиль железа между сессиями | Естественно разнообразные число ядер, уровень памяти, размер экрана | Множество сессий сходятся к идентичным значениям |
| Касание / viewport | Ненулевые точки касания, грубый указатель, viewport реального устройства | Несовпадающий тип указателя, нестандартный viewport или pixel ratio |
| Аттестация (только нативное приложение) | Валидный токен Play Integrity / App Attest | Не проходит или не может выдать токен |
Место этого сигнала среди смежных
Этот материал посвящён именно тому, как отличить виртуализированную Android-сессию от настоящей, — он пересекается с несколькими соседними темами, но не совпадает с ними. Фингерпринтинг мобильного браузера: как отслеживают Android и iOS охватывает более широкий набор сигналов, которые выдаёт любой телефон, настоящий или нет. Невозможные отпечатки: несовместимые GPU, ОС и шрифты разбирает противоречия GPU/ОС/шрифтов десктопного уровня — смежную, но отдельную проверку. Аттестация устройств: Play Integrity против App Attest освещает криптографическое доказательство для нативных приложений, которого нет у веба. А обнаружение антидетект-браузеров касается подмены десктопного отпечатка, а не арендованной мобильной инфраструктуры. Обнаружение облачных телефонов находится на пересечении: мобильные сигналы, проверенные на внутреннюю согласованность и согласованность между сессиями, при отсутствии какой-либо аттестации, на которую можно было бы опереться.
Проверьте собственные сигналы
Проверка отпечатка от BrowserInsight показывает настоящую строку рендерера GPU вашего устройства, доступность датчиков движения, hardwareConcurrency и deviceMemory — те же свойства, что разобраны в этом материале. Запустив её с реального телефона, а затем в браузере внутри удалённой или виртуализированной Android-сессии, вы сразу увидите разницу между ними.
Часто задаваемые вопросы
Облачный телефон — то же самое, что мобильный эмулятор?
Не совсем, хотя со стороны браузера сайты часто не могут их различить. Облачный телефон обычно транслирует или проксирует реальную (либо виртуализированную) систему Android, работающую на удалённом серверном железе; мобильный эмулятор целиком работает на десктопной машине, симулируя Android без какой-либо физической мобильности. У обоих, как правило, нет настоящего мобильного GPU и датчиков движения, поэтому оба вызывают одни и те же сигналы обнаружения, разобранные здесь.
Может ли провайдер облачных телефонов подделать настоящую строку рендерера GPU?
Сообщить такую строку он может, но фактический пиксельный вывод теста рендеринга WebGL всё равно исходит от того железа, что реально работает под капотом, — та же асимметрия, из-за которой подделка GPU обнаруживается на десктопе. Заявленная строка рендерера, не совпадающая с рендер-выводом, или описывающая чип с характеристиками семейства GPU, не согласующимися с остальным отпечатком, сама по себе является уликой.
Все ли системы обнаружения проверяют датчики движения?
Нет — доступ к датчикам во многих контекстах нужно запрашивать или он закрыт разрешением, поэтому не каждый стек обнаружения читает его при каждом визите. Там, где он доступен, это высоконадёжный сигнал именно потому, что убедительно подделать калибровочный шум намного сложнее, чем статическое свойство вроде строки user-agent.
Почему у веба нет аналога Play Integrity?
Google предлагала браузерный аналог, Web Environment Integrity, но отозвала его до выхода — после сопротивления производителей браузеров и защитников приватности, обеспокоенных риском привратничества: возможностью для сайтов отказывать в обслуживании браузерам без аттестации. Магазины нативных приложений применяют Play Integrity и App Attest на уровне платформы так, как открытый веб — по замыслу — не делает.
Заключение
Облачному телефону не нужно лгать в user-agent, чтобы выглядеть мобильным посетителем, — в этом и весь смысл: запускается настоящая сессия мобильного браузера. Что сложно подделать убедительно, так это железо под капотом: строку рендерера настоящего чипа GPU, живой калибровочный шум датчиков движения и естественное разнообразие, которое даёт популяция индивидуально принадлежащих людям телефонов вместо горстки клонированных образов виртуальных машин. Поскольку веб-нативной аттестации, на которую можно опереться, не существует, эта проверка согласованности GPU, датчиков и профиля железа — самый сильный сигнал, доступный обнаружению на стороне браузера, и это та же логика «согласуется ли всё со всем», что ловит поддельные десктопные профили, просто применённая к другому набору сугубо мобильных сигналов.
Рекомендуем прочитать:
- Фингерпринтинг мобильного браузера: как отслеживают Android и iOS
- Фингерпринтинг сенсоров: акселерометр и гироскоп
- Невозможные отпечатки: несовместимые GPU, ОС и шрифты
- Аттестация устройств: Play Integrity против App Attest
- Как сайты обнаруживают антидетект-браузеры и подмену отпечатков
- Поведенческое обнаружение ботов: нечеловеческие движения мыши


