Безопасность PlainApp: подробный разбор
Как PlainApp защищает ваши данные в локальной сети Wi-Fi — с доказательствами из открытого исходного кода.
Почему безопасность локальной сети важна?
Когда вы управляете телефоном на Android через браузер на ПК, ваши SMS, фотографии, контакты и файлы передаются по сети Wi-Fi. Большинство приложений отправляют всё это в виде открытого текста. Любой, кто находится в той же сети, может это увидеть.
Вы можете подумать: «Это мой домашний Wi-Fi, кто будет подслушивать?» Но задумайтесь:
- Публичный Wi-Fi — Кафе, аэропорты, гостиницы — любой поблизости может перехватить трафик
- Общие сети — Соседи по комнате, гости или скомпрометированные IoT-устройства
- Уязвимости роутера — Устаревшая прошивка с известными эксплойтами
Если приложение отправляет ваши SMS в виде открытого текста по HTTP, любой с бесплатным инструментом вроде Wireshark может их прочитать. Это не теория — это элементарно просто.
Именно так работает большинство приложений для управления телефоном. Откройте Chrome DevTools (F12 → вкладка Network) при использовании их веб-интерфейса, и вы увидите каждый API-запрос в открытом JSON — тексты SMS, пути к файлам, имена контактов и всё остальное.
Чем PlainApp отличается
PlainApp применяет несколько уровней шифрования и аутентификации. Вот что делает каждый уровень простым языком.
GraphQL API — запрашивайте только то, что нужно
Большинство приложений используют устаревшие REST API: один URL на ресурс, возвращающий всё подряд, нужно вам это или нет. PlainApp использует GraphQL — современный подход, при котором браузер запрашивает ровно те данные, которые ему нужны, и ничего лишнего.
Почему это важно:
- Меньше данных раскрывается — Если вам нужно только имя файла — только оно и передаётся
- Одна точка входа — Вместо десятков URL используется единственный /graphql, что сокращает поверхность атаки
- Права на уровне запроса — Каждый запрос проверяет свои права доступа (например, чтение SMS требует разрешения READ_SMS даже после входа в систему)
Зашифрованные API-вызовы (XChaCha20-Poly1305)
Это главное отличие PlainApp от большинства конкурентов.
Каждый API-запрос и ответ — включая HTTP и WebSocket трафик — шифруется XChaCha20-Poly1305, как в HTTP, так и в HTTPS режиме. Это современный алгоритм шифрования AEAD, используемый WireGuard VPN, Cloudflare и библиотекой Google Tink.
Простыми словами:
- 1Ваш браузер формирует запрос (например, «покажи мои SMS»)
- 2Добавляет временную метку и случайный nonce для защиты от повторного воспроизведения
- 3Шифрует весь payload в нечитаемые бинарные данные с помощью XChaCha20-Poly1305
- 4Зашифрованные бинарные данные передаются по сети — без base64, без JSON, чистый бинарный формат
- 5Только ваш телефон может расшифровать и проверить их
Даже если кто-то перехватит трафик, он увидит лишь бессмысленные двоичные данные, а не читаемый JSON.
О шифровании:
- 256-битный ключ (чрезвычайно надёжный)
- 192-битный nonce (защищает от определённых типов атак, которым подвержены другие шифры)
- Встроенное обнаружение подмены — если кто-то изменит данные при передаче, расшифровка не пройдёт
- На стороне Android: используется Google Tink
- На стороне веба: используется @noble/ciphers (тщательно проверенная JavaScript-библиотека для криптографии)
Цифровые подписи (Ed25519) — межустройственная связь
Когда два устройства PlainApp обмениваются данными (например, чат телефон-телефон), одного шифрования недостаточно — каждое устройство должно убедиться, что сообщение действительно пришло от другого устройства и не было подделано.
временная метка
Принимающее устройство проверяет подпись по открытому ключу отправителя и отклоняет запросы с временной меткой старше 5 минут. Это предотвращает как подделку, так и атаки повторного воспроизведения.
Безопасное сопряжение устройств (обмен ключами ECDH)
Когда два устройства PlainApp сопрягаются друг с другом (например, два телефона), им нужен общий ключ шифрования. Но отправка ключа по сети сводила бы всю защиту на нет.
PlainApp решает эту задачу с помощью обмена ключами ECDH (Elliptic Curve Diffie-Hellman) — той же математики, что используется в TLS, Apple Secure Enclave и WebAuthn:
- 1Каждое устройство генерирует пару ключей (открытый + закрытый)
- 2Устройства обмениваются только открытыми ключами
- 3Каждое устройство комбинирует свой закрытый ключ с открытым ключом другого
- 4Оба получают одинаковый общий секрет — при этом он ни разу не передаётся по сети
Зашифрованные URL — скрытие путей к файлам
Вот деталь, которую большинство людей не замечают: URL-адреса тоже раскрывают информацию.
Когда вы скачиваете файл, URL сообщает серверу, какой файл вам нужен. Во многих приложениях URL выглядит так:
/fs?path=/sdcard/DCIM/Camera/photo_2024.jpgЛюбой, кто перехватывает трафик (или просматривает историю браузера), может точно увидеть, к какому файлу вы обращались, и структуру папок вашего телефона.
PlainApp шифрует путь к файлу в URL:
/fs?id=AxK9f2mQ7vR3xP8nWz...Параметр id — это путь к файлу, зашифрованный алгоритмом XChaCha20-Poly1305 с помощью случайного ключа, называемого URL Token. По умолчанию этот ключ постоянный и сохраняется после перезапуска приложения, поэтому ранее отправленные ссылки продолжают работать. Без ключа никто не сможет угадать реальный путь, перечислить ваши файлы или сформировать URL для скачивания.
HTTPS с самоподписанными сертификатами
PlainApp генерирует самоподписанный TLS-сертификат на вашем телефоне. Это создаёт зашифрованный HTTPS-туннель — ту же технологию, которую используют банки и веб-сайты.
Сертификат использует:
- ECDSA с кривой P-256 (как у крупнейших сайтов)
- Подпись SHA256
- Хранится в закрытом каталоге приложения
В сочетании с шифрованием XChaCha20 на уровне приложения это даёт два независимых уровня защиты. Взлом одного бесполезен без взлома другого.
Защита входа в систему
PlainApp ограничивает количество попыток входа для защиты от подбора пароля:
- 5 попыток за 60 секунд на один IP-адрес
- После этого подключения отклоняются
- Устаревшие записи об ограничениях автоматически очищаются
HTTP и HTTPS: честное сравнение
PlainApp поддерживает режимы HTTP и HTTPS. Вот честная разница между ними:
| Режим HTTP | Режим HTTPS | |
|---|---|---|
| URL-пути к файлам | Зашифрованы (XChaCha20) | Зашифрованы (XChaCha20) |
| API-вызовы | Зашифрованы (XChaCha20) | Зашифрованы (XChaCha20 + TLS) |
| Скачивание файлов | Не зашифровано при передаче | Зашифровано через TLS |
| Для кого подходит | Для новичков (без предупреждения SSL в браузере) | Для пользователей, заботящихся о конфиденциальности |
В обоих режимах API-вызовы шифруются алгоритмом XChaCha20-Poly1305 — ваши SMS, контакты и другие данные всегда зашифрованы, независимо от HTTP или HTTPS.
Режим HTTP существует потому, что самоподписанные сертификаты вызывают предупреждение в браузере («Ваше подключение не является защищённым»). Для менее технически подкованных пользователей это предупреждение выглядит пугающе. HTTP позволяет избежать этого неудобства.
Однако в режиме HTTP передача файлов не шифруется. Если вы находитесь в общей или публичной сети, всегда используйте HTTPS.
Рекомендация: используйте HTTPS при любой возможности. Примите предупреждение браузера о самоподписанном сертификате — это нормально и ожидаемо для приложения в локальной сети.
Безопасность цепочки поставок — меньше зависимостей, меньше рисков
Угроза безопасности, о которой многие пользователи не задумываются: атаки на цепочку поставок. Когда приложение использует сотни сторонних библиотек, любая из них может быть скомпрометирована — внедряя вредоносный код, который крадёт данные, майнит криптовалюту или открывает бэкдоры.
Это особенно опасно в экосистеме JavaScript. За последние годы популярные npm-пакеты, такие как event-stream, ua-parser-js и colors, были захвачены для внедрения вредоносного кода в миллионы проектов. Если веб-интерфейс приложения для управления телефоном подключает сотни JS-пакетов, каждый из них — потенциальный вектор атаки.
PlainApp придерживается осознанного подхода: использовать как можно меньше зависимостей и писать собственный код, когда это оправданно.
Android-приложение (plain-app)
- Без фреймворков внедрения зависимостей (без Hilt, без Dagger) — используются простые синглтоны
- Криптография обеспечивается только 3 проверенными библиотеками: Google Tink, Bouncy Castle и встроенным Java Cryptography Extension
- Сервер работает на Ktor (официальный Kotlin-фреймворк от JetBrains) — никаких малоизвестных сторонних серверных библиотек
Веб-интерфейс (plain-desktop)
Всего 28 runtime-зависимости — значительно меньше, чем у типичных веб-приложений. Ряд функций, которые обычно требуют npm-пакетов, реализован с нуля:
| Функция | Обычное приложение | PlainApp |
|---|---|---|
| Звуки уведомлений | howler.js / tone.js | Собственный синтезатор на Web Audio API |
| Генерация UUID | npm-пакет uuid | Собственная реализация RFC 4122 |
| Загрузка файлов | uppy / axios | Собственная порционная загрузка с очередью |
| WebRTC-видео | Twilio / Daily.co SDK | Собственный код PeerConnection |
| HTTP-клиент | axios / ky | Встроенный браузерный fetch |
Криптография на стороне веба использует @noble/ciphers — тщательно проверенную JavaScript-библиотеку для криптографии без зависимостей — вместо больших и громоздких альтернатив.
Почему это важно
Каждая добавленная зависимость — это код, который вы не контролируете. Подход PlainApp означает:
- Меньше мест для сокрытия вредоносного кода
- Меньшая поверхность атаки
- Проще провести аудит (весь код открыт)
- Нет риска из-за заброшенных или захваченных npm-пакетов
Типичные ошибки конкурентов
Речь не о конкретных приложениях. Речь о распространённых паттернах в этой категории:
| Аспект безопасности | PlainApp | Типично для конкурентов |
|---|---|---|
| API-трафик | Зашифрован (XChaCha20) в режимах HTTP и HTTPS | Открытый JSON по HTTP |
| WebSocket трафик | Зашифрованные бинарные фреймы (XChaCha20) | Текстовый JSON или нет WebSocket |
| Обработка токена аутентификации | Используется как ключ шифрования, никогда в заголовках | Отправляется в HTTP-заголовках (легко перехватить) |
| URL файлов | Зашифрованные идентификаторы путей | Пути в открытом виде |
| Обмен ключами | ECDH (P-256) | Отсутствует |
| Подпись запросов | Ed25519 (только между устройствами) | Нет |
| Защита от повторного воспроизведения | 30 с + nonce (Web); 5 мин + подпись (устройства) | Нет |
| Защита входа | Ограничение попыток + двухфакторное подтверждение | Без ограничений |
| Маршрутизация данных | 100% локально, без облака | Некоторые передают через облако |
| Зависимости | Минимум проверенных библиотек | Сотни npm-пакетов |
| Исходный код | Открытый (GPL-3.0) | В основном закрытый |
Самый простой способ проверить любое приложение: откройте Chrome DevTools (F12) → вкладку Network во время работы с приложением. Если вы можете прочитать ответы API как JSON — шифрования нет.
Проверьте сами
PlainApp полностью открыт. Каждое утверждение в этой статье можно проверить в коде.
github.com/plainhub/plain-app (GPL-3.0)Автоматизированный, отслеживаемый и устойчивый к подмене конвейер релиза
Все установочные пакеты автоматически собираются инфраструктурой GitHub и F-Droid. Сборки отслеживаемы, безопасны и не содержат следов ручного вмешательства. PlainApp — одно из немногих Android-приложений, где есть и проверяемые сборки (SLSA), и релизы, проверенные VirusTotal.
Автоматические сборки на GitHub и F-Droid
Релизные артефакты создаются CI-конвейерами, а не вручную локально. Каждый артефакт можно связать с исходными коммитами и воспроизводимыми workflow сборки.
SLSA Provenance (Уровень 3) + проверка VirusTotal
Каждый релиз включает attestations SLSA provenance и результаты VirusTotal, что делает цепочку поставок аудируемой и позволяет пользователям проверять целостность перед установкой.
Часто задаваемые вопросы
Правда ли PlainApp шифрует данные в режиме HTTP?
Да. Все API-вызовы (SMS, контакты, список файлов и т.д.) шифруются алгоритмом XChaCha20-Poly1305 как в режиме HTTP, так и в HTTPS. В режиме HTTP не шифруется только скачивание файлов. Для полной защиты используйте HTTPS.
Почему браузер показывает предупреждение о безопасности?
PlainApp использует самоподписанный TLS-сертификат для шифрования. Поскольку он не выдан публичным центром сертификации, браузер показывает предупреждение. Это нормально и ожидаемо для приложения в локальной сети. Нажмите «Дополнительные» и «Перейти на сайт», чтобы продолжить.
Может ли кто-то в той же сети Wi-Fi увидеть мои данные?
С PlainApp — нет. API-вызовы зашифрованы алгоритмом XChaCha20-Poly1305, а в режиме HTTPS передача файлов также защищена TLS. С большинством конкурентов — да, их API-вызовы отправляются открытым текстом в формате JSON.
Как PlainApp соотносится с VPN?
VPN шифрует трафик между вашим устройством и VPN-сервером. PlainApp шифрует трафик между телефоном и браузером в локальной сети. Они решают разные задачи — PlainApp защищает локальное управление устройством, а VPN — интернет-трафик.
Код действительно открытый?
Да. PlainApp распространяется по лицензии GPL-3.0. Полный исходный код доступен на github.com/plainhub/plain-app. Вы можете изучить каждую реализацию шифрования, собрать из исходников или внести свой вклад.
Верните себе контроль над своим телефоном.
Никаких облачных посредников. Никаких ежемесячных платежей. Только ваш телефон и браузер.