惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

雷峰网
雷峰网
宝玉的分享
宝玉的分享
I
InfoQ
P
Privacy International News Feed
V
V2EX
IT之家
IT之家
S
SegmentFault 最新的问题
D
Darknet – Hacking Tools, Hacker News & Cyber Security
V2EX - 技术
V2EX - 技术
C
CERT Recently Published Vulnerability Notes
C
Check Point Blog
The Register - Security
The Register - Security
爱范儿
爱范儿
博客园 - 三生石上(FineUI控件)
AWS News Blog
AWS News Blog
M
MIT News - Artificial intelligence
C
Cyber Attacks, Cyber Crime and Cyber Security
F
Fortinet All Blogs
B
Blog
N
Netflix TechBlog - Medium
B
Blog RSS Feed
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Last Week in AI
Last Week in AI
T
Threatpost
Forbes - Security
Forbes - Security
U
Unit 42
A
Arctic Wolf
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
P
Palo Alto Networks Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Recorded Future
Recorded Future
L
Lohrmann on Cybersecurity
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
P
Proofpoint News Feed
月光博客
月光博客
Spread Privacy
Spread Privacy
MongoDB | Blog
MongoDB | Blog
Jina AI
Jina AI
I
Intezer
V
Visual Studio Blog
阮一峰的网络日志
阮一峰的网络日志
The Hacker News
The Hacker News
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
L
LangChain Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园_首页
MyScale Blog
MyScale Blog
腾讯CDC
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
量子位

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Android Kiosk: как купить сухарики, когда ларёк закрыт
RaccoonSecurity · 2026-06-16 · via Все публикации подряд на Хабре

Несколько месяцев назад моему коллеге предстоял долгий перелёт — около 8 часов. Ему быстро стало скучно, и он обратил внимание на экран мультимедийной системы в спинке кресла напротив. Коллега запустил карту полёта и обнаружил, что это Android‑устройство с включённым Kiosk Mode. Этот режим должен помешать (или, по крайней мере, стать серьёзной проблемой) исследованию устройства, но на практике всё оказалось совсем наоборот. Коллега смог без каких‑либо трудностей обойти Kiosk Mode на планшете и прочитать файл /etc/shadow. Именно так появилась идея изучить Kiosk Mode глубже и разобраться: действительно ли он так безопасен?

В этой статье я постараюсь объяснить, как устроен Kiosk Mode в Android изнутри, расскажу об основных компонентах, необходимых приложению, чтобы превратить ваше устройство в kiosk‑девайс, а также приведу несколько примеров реальной эксплуатации kiosk‑устройств и приложений.

Данный материал впервые был представлен в качестве доклада на zeronight.

Что такое Kiosk Mode

Начнём с простого: что вообще такое Kiosk Mode?

Kiosk Mode — это режим на различных платформах (Windows, Linux, Android), предназначенный для ограничения возможностей пользователя на устройстве одним или несколькими приложениями. Говоря простыми словами, при использовании Kiosk Mode мы пытаемся «запереть» пользователя в заранее выбранных приложениях. При этом очень важно, чтобы пользователь оставался в этих приложениях. Выход из Kiosk Mode в самом безвредном случае полностью «ломает» функционал устройства, а в худшем — может привести к финансовым потерям или компрометации всей локальной сети, в которой находится kiosk‑устройство.

Kiosk Mode довольно широко распространён, хотя в сообществе ИБ о нём говорят не очень часто. Он используется в POS‑терминалах (недавно вышла статья, где автор подробно разбирает такое использование Kiosk Mode), постаматах, кассах самообслуживания, в общественном транспорте, в ресторанах в качестве электронного меню, в промышленных терминалах и в корпоративных устройствах. Но несмотря на важность безопасности Kiosk Mode, ею часто пренебрегают.

В данной статье не будет рассматриваться реализация Kiosk Mode под Linux или Windows: я сконцентрируюсь только на реализации Kiosk Mode в Android.

Устройства с Kiosk Mode можно условно поделить на две группы: Single App и Multi App.

Как можно понять из названия, Single App используется, когда возможности пользователя ограничены одним конкретным приложением. Single App обычно применяется для цифровых вывесок, мобильных POS‑систем, терминалов в аэропортах, терминалов в индустрии гостеприимства, а также терминалов бронирования билетов. Несмотря на то, что режим Single App проще как в установке на устройство, так и в администрировании, он используется реже.

В режиме Multi App доступ пользователя к устройству ограничен несколькими приложениями; при этом он может свободно переключаться между ними, что кратно расширяет функциональность устройства с Kiosk Mode. Multi App Kiosk обычно используется в сфере услуг, в образовательных целях, а также в компаниях, занимающихся доставкой и производством.

Kiosk-приложение на Android

В этой статье я не буду подробно описывать процесс разработки приложения для Kiosk Mode. Информацию для этого раздела я взял из Github‑статьи mrugacz95. Здесь я расскажу только об основных механизмах обеспечения «изоляции» пользователя, используемых в kiosk‑приложениях на Android.

В приложении, которое полностью ограничивает возможности пользователя, можно выделить три основных компонента:

  1. Home Launcher — это главный экран Android: на нём расположены иконки приложений, виджеты и прочие объекты, которые пользователь может туда поместить. Если наше приложение не будет лаунчером по умолчанию, то после перезагрузки Kiosk Mode перестанет работать и устройство вернётся к своим стандартным функциям.

  2. Screen Pinning. Закрепление экрана — это функция, позволяющая отображать одно приложение до момента его открепления. Она появилась в Android 5.0 и изначально предназначалась для передачи телефона другим людям без риска утечки информации. После включения этой функции на устройстве происходят следующие изменения: статус‑бар полностью скрывается, отключаются кнопки «Домой» и «Недавние приложения», а также вводится запрет на запуск новых действий другими приложениями.

  3. Device Admin. Приложение становится администратором устройства. Если пропустить этот шаг, мы не сможем полностью ограничить пользователя в доступе к уведомлениям и строке состояния, а также не сможем менять системные настройки из приложения, что для kiosk‑устройств крайне полезно.

Home Launcher

Чтобы сделать приложение лаунчером, нужно выдать ему интенты, написать соответствующий intentFilter и выдать необходимые привилегии с помощью addPersistentPreferredActivity.

Далее необходимо отключить Keyguard (экран блокировки). Это позволит нашему приложению запускаться сразу, обходя экран блокировки. Кроме того, необходимо предотвратить выключение экрана. Для этого следует выставить флаг FLAG_KEEP_SCREEN_ON для текущего окна (window принадлежит классу Acitivity и указывает на текущее окно).

Screen Pinning

Для функционирования Screen Pinning в Android существует специальный механизм Lock Task Mode (режим закрепления задач). Он позволяет закрепить Activity поверх экрана. Для закрепления приложения используются две функции: setLockTaskPackages() в DevicePolicyManager и startLockTask() в Activity.

setLockTaskPackages разрешает приложению закрепляться, а startLockTask обеспечивает закрепление. Финальным шагом закрепления приложения является добавление кода, обеспечивающего включение полноэкранного режима для нашего приложения.

Это основные механизмы, необходимые для включения Kiosk Mode со стороны разработчика приложений. Теперь давайте углубимся в Kiosk Mode и посмотрим изнутри, как работает изоляция приложений.

Kiosk Mode изнутри

setLockTaskPackages

Как уже было сказано в предыдущем разделе, функция setLockTaskPackages нужна для того, чтобы система позволила приложению закрепиться. Для этого используется механизм политик, а точнее DevicePolicyEngine (DPE) — внутренний механизм Android, который регламентирует управление политиками.

Суть работы DPE довольно проста:

  1. Каждый администратор по‑своему настраивает систему (например, разрешает или запрещает включение камеры).

  2. DPE на основе заранее заданных правил определяет, какая политика будет принята, после чего формирует итоговую политику, которая будет применена системой.

Например, в случае с камерой более приоритетным для Android является запрет. Поэтому, если два разных администратора устройства, равные в правах, потребуют одновременно разрешить и запретить доступ к камере, DPE применит политику запрета.

setLockTaskPackages как раз и задаёт такую политику. Сама функция реализована в DevicePolicyManagerService и используется для создания политики «это приложение (или эти приложения) могут быть закреплены». Ниже представлен исходный код функции.

Проанализировав эту функцию, можно заметить два основных вызова: getLocalPolicySetByAdmin и setLocalPolicy.

getLocalPolicySetByAdmin используется для чтения политики, заданной администратором для текущего пользователя. Использование этой функции позволяет обновлять политики, не заменяя собой «вклад» других администраторов: мы меняем только своё локальное значение, а затем DPE объединяет все источники и пересчитывает итоговую политику, которая будет использована далее. Заодно по этому значению удобно понять, было ли фактическое изменение: если изменения не было, можно избежать лишних действий и уведомлений.

setLocalPolicy — центральная точка записи локальной политики от конкретного администратора. Метод добавляет «вклад» администратора в политику, пересчитывает итоговое значение с учётом «вклада» других администраторов и при необходимости применяет изменения к системе, уведомляет администратора и распространяет политику на наследуемые профили.

Запуск Lock Task Mode

Запуск Lock Task Mode происходит в функции startLockTask из класса Activity, которая, в свою очередь, обращается к startLockTaskModeByToken. Это приводит к вызову функции startLockTaskMode в классе LockTaskController. Именно её и стоит рассмотреть подробнее.

Сперва следует обратить внимание на проверку параметра isSystemCaller. Он определяет, кто пытается закрепить приложение. При вызове из startLockTask этот параметр всегда равен false. Функционал внутри блока if (!isSystemCaller) отвечает за всплывающее окно, в котором пользователь устройства должен подтвердить закрепление (функция showScreenPinningRequest).

После подтверждения закрепления со стороны пользователя функция startLockTaskMode вызывается снова, но параметр isSystemCaller уже будет передан как true, и будет вызвана основная функция закрепления приложения — setLockTaskMode в классе LockTaskController.

При анализе setLockTaskMode основное внимание стоит уделить трём функциям: findTaskToMoveToFront, resumeFocusedTasksTopActivities и executeAppTransition.

Немного об окнах в Android

Для дальнейшего понимания процесса необходимо сделать небольшое отступление и объяснить, зачем в Android нужен класс Task и как он связан с приложениями, которые видит пользователь.

Task — это контейнер стека Activity. Этот класс хранит упорядоченный набор ActivityRecord. Когда пользователь переключается между приложениями или между экранами внутри одного приложения, система выбирает верхний (последний) ActivityRecord в этом списке. Этот верхний ActivityRecord считается текущим: его Activity должна оказаться на экране в состоянии RESUMED, а записи ниже в этом же списке переводятся в состояния PAUSED или STOPPED.

При обычном вызове startActivity() в список ActivityRecord текущего Task добавляется новая запись сверху, и тем самым верх стека меняется. При нажатии Back верхняя запись удаляется из списка, и её место занимает предыдущая запись. Если включены специальные правила (например, singleTop), новый элемент может не добавляться: вместо этого система использует существующий верхний ActivityRecord и обновляет его Intent. Если используется CLEAR_TOP или singleTask, система находит нужный ActivityRecord внутри списка этого Task, удаляет все записи выше него и делает найденную запись верхней. Если пользователь открывает другое приложение, стек не перестраивается: просто активным становится верхний Task.

Также Task является узлом в дереве WindowManager. Это означает, что Task существует как оконный контейнер (WindowContainer), который участвует в компоновке, отрисовке и Z‑порядке — очерёдности наложения элементов по оси глубины экрана (что выводится на передний план, а что остаётся на заднем). Если два окна или контейнера перекрываются, элемент с более высоким Z‑порядком будет находиться на переднем плане и обычно именно он получает фокус ввода.

В иерархии WMS (WindowManagerService) Task располагается ниже RootTask. Общая иерархия внутри WMS выглядит так: DisplayContent → TaskDisplayArea → RootTask → Task → ActivityRecord → окна/Surface.

RootTask — это верхнеуровневый контейнер задач в WindowManager. Он группирует обычные Task по режиму и политике отображения (например, fullscreen, split‑screen, PiP, freeform). Именно RootTask определяет общий оконный режим и границы для своих дочерних задач, а также управляет их порядком отображения на дисплее.

Как узел WM‑дерева Task задаёт границы для всего содержимого, наследует или переопределяет оконный режим (fullscreen, split‑screen, freeform) и является единицей, которую можно целиком перемещать в Z‑порядке (например, move‑to‑front — поднять задачу над соседями в том же RootTask). Кроме того, на уровне Task удобно применять групповые операции для отрисовки: показывать временную поверхность (starting window или snapshot), выполнять анимации и трансформации, а также делать reparenting — переносить задачу в другой RootTask или даже в другой DisplayContent (перенос на другой дисплей).

Возвращение в Kiosk Mode

Теперь, когда мы понимаем, как работает показ Activity в Android, можно вернуться к Kiosk Mode, а точнее к функции findTaskToMoveToFront.

findTaskToMoveToFront реализует фазу move‑to‑front для Task: она переводит выбранный Task на передний план и гарантирует, что его верхняя ActivityRecord будет показана на нужном дисплее, в нужном оконном режиме (обычно fullscreen), а также станет первой по фокусу и вводу. Этапы, которые выполняются в findTaskToMoveToFront, можно описать так:

  1. Reparenting — если Task находится в неподходящем оконном режиме (split‑screen, PiP) или на другом дисплее, его переносят в целевой полноэкранный root, чтобы получить единое фокусное окно.

  2. Подготовка перехода в WM — перед фактическим поднятием на передний план нужные ActivityRecord помечаются для корректной анимации и правильных Surface‑транзакций.

  3. Move‑to‑front и focus Task поднимается на вершину в иерархии задач, а фокус ввода переводится на его верхнюю Activity.

  4. Starting window (при необходимости) — если верхняя Activity ещё не готова к отрисовке, открывается стартовое окно, чтобы избежать «чёрного экрана».

  5. Передача управления фазе RESUME — после того как Task стал первым в очереди и получил фокус ввода, управление передаётся логике, которая переводит верхнюю Activity в состояние RESUMED.

resumeFocusedTasksTopActivities проходит по всем зонам дисплея (если их несколько) и для каждой области проверяет, какой RootTask сейчас считается главным и должен получать фокус.

После этого метод не пытается напрямую перевести в состояние RESUMED конкретную Activity, а просто делегирует работу на нижний уровень: выбранному RootTask передаётся команда «переведи в состояние RESUMED верхний ActivityRecord» и дальше уже внутри этого RootTask выбирается нужный Task, а внутри него — верхний ActivityRecord.

Внутри корня resumeTopActivityUncheckedLocked выполняет несколько проверок (состояние дисплея, состояние контейнера), после чего выбирается конкретная верхняя ActivityRecord и инициируется её переход в стадию RESUME.

Ключевая работа выполняется в TaskFragment.resumeTopActivity. Если Activity уже находится в состоянии RESUMED и привязана к процессу, метод просто актуализирует её видимость и завершает выполнение. В противном случае он переводит предыдущую Activity в состояние PAUSED и инициирует вызов onResume для текущей верхней Activity. Для этого в процесс предыдущей Activity передаётся PauseActivityItem, а в процесс новой Activity — ResumeActivityItem.

После того как Activity приложения будет подготовлена и перейдёт в состояние RESUMED, WindowManager переходит к стадии визуального применения изменений. Для этого вызывается executeAppTransition. Сначала метод сообщает TransitionController, что текущий DisplayContent готов запускать переходы, затем проверяет, задан ли вообще переход в mAppTransition. Если переход задан, он помечается как готовый к выполнению, после чего вызывается mWindowPlacerLocked.requestTraversal.

Вызов requestTraversal запускает следующий этап расстановки окон и поверхностей (layout и surface placement): на этом шаге изменения отображаются на экране и воспроизводится анимация (при её наличии).

Популярные ошибки при создании kiosk‑устройств

Теперь, когда мы в общих чертах разобрались, как работает Kiosk Mode, пора поговорить о том, как сделать свои kiosk‑приложения безопаснее (и на что обращать внимание в чужих решениях). В этом разделе будут рассмотрены часто встречающиеся ошибки в конфигурации приложений и устройств, работающих в режиме Kiosk Mode.

Лишние приложения в списке разрешённых приложений

Как было показано выше, при конфигурации kiosk‑устройств необходимо явно задавать список приложений, разрешённых к запуску. Довольно часто в этот список добавляют лишние приложения (например, браузер Chrome), что для Android‑устройства, основанного на Linux, может оказаться критичным. Доступ к браузеру открывает множество возможностей: от выхода из kiosk‑режима до исполнения кода на устройстве. Именно эта проблема была обнаружена в реализации Kiosk Mode упомянутого в начале статьи приложения: посредством нехитрых манипуляций с WebView приложения был запущен браузер и получен доступ к файловой системе. Кроме того, непроверенные сторонние приложения могут содержать собственные уязвимости и тем самым позволять обходить ограничения режима или менять системные настройки.

Недостаточная изоляция и экспорт компонентов

В конфигурациях Kiosk Mode с несколькими приложениями (Multi App) довольно часто возникает необходимость в их взаимодействии. Например, может потребоваться сервис для изменения системных настроек. Такой сервис обычно обладает большими привилегиями, чем обычные kiosk‑приложения. Если не ограничить к нему доступ извне (например, оставить компонент экспортируемым), атакующий может установить своё приложение или отправить кастомные интенты и использовать привилегированные компоненты: отключить Kiosk Mode или получить доступ к конфиденциальной информации.

Включённые параметры разработчика и ADB

К сожалению, иногда при работе с kiosk‑устройствами разработчики забывают отключить параметры разработчика или ADB. Поскольку у пользователя почти всегда есть физический доступ к kiosk‑устройству, разрешённая отладка может стать серьёзной проблемой. Она позволяет устанавливать и запускать сторонние APK, а также вмешиваться в работу системы.

Например, в случае CVE-2023-41255 и CVE-2023-43488 на промышленных терминалах Bosch ctrlX WR21 в системе был оставлен файл su, что позволяло почти без усилий получить root‑доступ.

Использование HTTP и отсутствие шифрования

Некоторые приложения в мультимедийных киосках используют открытые протоколы для получения конфигурации. Например, в CVE-2023-45220 и CVE-2023-45321 клиентское приложение на Android передавало по HTTP IP‑адрес и учётные данные для подключения к MQTT‑брокеру. Злоумышленник, находящийся в той же подсети, мог перехватить эти данные и получить контроль над системой.

Другой пример — отсутствие проверки сервера при подключении к MQTT (CVE-2023-45851): клиент соединялся с брокером без аутентификации, из‑за чего его можно было заставить подключиться к вредоносному серверу и принимать поддельные команды.

Открытые USB‑порты и клавиатурные атаки

При наличии открытых USB‑портов атакующий может использовать техники класса BadUSB: подключить устройство, которое эмулирует клавиатуру, автоматически вводит команды, запускает приложения или открывает системные экраны. В результате можно вывести устройство из kiosk‑режима, получить доступ к системным настройкам или запустить вредоносный код.

Разумеется, это не все ошибки. На практике их гораздо больше, и перечислить все почти невозможно. Я лишь хотел показать наиболее популярные и часто встречающиеся проблемы. А теперь я приведу несколько примеров уязвимостей в kiosk‑устройствах.

Уязвимости в kiosk‑устройствах

CVE-2023-21189 / CVE-2025-26428

В методе startLockTaskMode для задачи которая уже закреплена, код продолжал выполнять логику закрепления, не проверяя список mLockTaskModeTasks на наличие этой задачи. В результате, находясь в режиме Kiosk Mode, можно было вызвать stopLockTaskMode и повторно показать диалог «Закрепить приложение», а затем обойти ограничения Kiosk Mode и разблокировать устройство.

Уязвимость была исправлена лишь в одном из последних коммитов Android 15 с помощью дополнительной проверки:

CVE-2025-5344

Компания Bluebird выпускает множество различных устройств: телефоны, платёжные терминалы, мобильные компьютеры, корпоративные планшеты, интерактивные киоски самообслуживания, RFID‑устройства, Bluetooth‑сканеры штрихкодов, автомобильные и телематические устройства (vehicle gateway), а также мобильные принтеры. Среди них есть несколько устройств, работающих в режиме Kiosk Mode, в которых используется специальный Home Launcher.

В этом лаунчере был реализован AIDL‑сервис для управления настройками системы, который был экспортирован без надлежащей защиты. В результате любое приложение или локальный процесс на устройстве могли подключиться к этому сервису и изменять системные настройки. Эта уязвимость позволяла отключать политики безопасности или изменять критически важные параметры системы, такие как режим разработчика или доступ к shell.

CVE-2023-45844

Bosch Rexroth выпускает промышленные HMI‑панели ctrlX‑HMI‑WR21, которые работают на Android и часто используются как операторские терминалы в режиме Kiosk Mode: пользователю показывают только веб‑интерфейс через Google Chrome/Chromium. В уязвимых прошивках таких устройств ограничения реализованы так, что в браузере доступен стандартный системный путь установки приложений: пользователь с физическим доступом может довести Chrome до запуска системного установщика пакетов Android (Package Installer) и тем самым установить произвольный APK, хотя в Kiosk Mode такая возможность должна быть заблокирована. После установки своего приложения злоумышленник фактически «ломает» модель Kiosk Mode: может запускать код вне разрешённого сценария и добираться до критичных настроек устройства.

Вывод

К устройствам, работающим в режиме Kiosk Mode, нельзя относиться легкомысленно. Ошибка в конфигурации, лишнее приложение в allowlist, экспортированный компонент, включённый ADB или слабая сетевая защита способны свести на нет всю модель изоляции.

Именно поэтому безопасность kiosk‑устройств следует рассматривать как полноценную задачу защиты всей платформы, а не как простую настройку интерфейса или ограничение пользовательского доступа. Компрометация такого устройства нередко выходит далеко за пределы одного приложения или одного экрана: в ряде случаев она может привести к компрометации всей локальной сети организации, а выход из Kiosk Mode — открыть злоумышленнику широкие возможности для дальнейших действий.

Надеюсь, эта статья оказалась для вас полезной или хотя бы интересной и мне удалось немного погрузить вас в мир Android‑устройств, работающих в режиме Kiosk Mode.