Блокируйте открытый текст в приложениях Android, не полагаясь на VPN
Открытый текст в полезной нагрузке и открытый текст в пути — разные проблемы. Первую решите в приложении, вторую — туннелем или политикой устройства.
Две совершенно разные вещи называют блокировкой открытого текста на Android. Одна — политика внутри приложения, которая велит собственному сетевому стеку отказываться от обычного HTTP. Другая — устройство на уровне устройства, которое пытается защитить всё на телефоне сразу, обычно пропуская трафик через VPN. Они решают разные задачи, и вторая не может исправить первую: туннель защищает участок между телефоном и выходом, а приложение, говорящее по HTTP, продолжает говорить по HTTP со всем, что находится за этим выходом.
Две проблемы под одним именем
Первая проблема — нагрузка: приложение записывает учётные данные или токены в запрос, который не шифруется от начала до конца, поэтому каждый переход, который его видит, может его прочитать. Вторая — путь: приложение может быть безупречным, и вы всё равно хотите, чтобы местный оператор Wi-Fi не узнал ничего о том, куда оно подключается. VPN решает вторую и только вторую.
Это различие определяет, кому принадлежит исправление. Нагрузка принадлежит тому, кто выпускает приложение, потому что только этот код решает, какой URL вызывается и проверяется ли сертификат. Путь принадлежит устройству или сети, потому что речь о том, куда едут пакеты, а не о том, что они содержат.
Путь первый: приложение, которое вы контролируете
Если вы выпускаете приложение, исправление — это решение о транспорте плюс политика, которая его обеспечивает. Направьте каждую конечную точку на HTTPS, оставьте включённой проверку имени хоста и сертификата и удалите резервный путь по обычному HTTP, а не оставляйте его на расстоянии одного флага конфигурации. Перенаправление здесь не помогает: HTTP-запрос, получивший 301, уже отправил заголовки и тело открыто, поэтому учётные данные никогда не должны идти в предположении, что перенаправление их защитит.
Начиная с Android 7.0 политику выражает Network Security Configuration. Файл ниже — самая маленькая полезная версия: он отказывает в открытом тексте везде, если только исключение для конкретного домена не говорит иначе.
<network-security-config>
<base-config cleartextTrafficPermitted="false" />
</network-security-config>Сошлитесь на этот ресурс из манифеста, затем прочитайте уже существующие исключения перед выпуском. Старый домен для отладки или запись SDK платёжного провайдера могут тихо снова разрешить открытый текст для хоста, который вы пытались защитить.
Два момента о версиях стоит знать. Приложения, нацеленные на API 28 или новее, уже по умолчанию отказывают в открытом тексте, поэтому приложение, которое всё ещё говорит по обычному HTTP, либо нацелено на более старый уровень API, либо где-то имеет исключение. А когда присутствует конфигурация сетевой безопасности, более старый атрибут манифеста android:usesCleartextTraffic больше не решает вопрос, и поэтому изменение этого флага иногда выглядит так, будто ничего не делает.
Путь второй: приложение, которое вы не контролируете
Для установленного стороннего приложения вы не можете переписать его конфигурацию безопасности пользовательской настройкой. Реалистичные варианты — собственные средства безопасного подключения продукта, поддерживаемая альтернатива, уже использующая TLS, или политика управляемого устройства, ограничивающая то, что устройству разрешено запускать. Это разные обязательства, и только третье масштабируется на парк устройств.
Сетевые правила — более слабая замена, чем кажется. Разрешение только порта 443 не обеспечивает аутентифицированный TLS, потому что многие протоколы открытого текста можно перенести на этот порт, а блокировка порта 80 не покрывает открытый текст на других портах. Режим только-HTTPS в браузере тоже ограничен этим браузером, а не отдельным приложением почты или чата на том же телефоне.
Установка перехватывающего сертификата, чтобы трафик выглядел зашифрованным, — это изменение доверия, а не исправление. Он заменяет аутентификацию сервера приложения вашей, и приложение, которое изначально не проверяло сертификаты, этим не исправляется; вы лишь переместили, кто может читать поток.
Где VPN помогает, а где нет
Туннель — правильный инструмент, когда требуется, чтобы локальная сеть ничего не узнала о соединении, или чтобы приложение достигло частного сервиса, до которого иначе не добраться. Это неправильный инструмент для того, чтобы заставить HTTP-клиент говорить по HTTPS, потому что запрос покидает туннель точно таким, каким вошёл.
Android добавляет практическое ограничение: платформа запускает только один VPN-сервис одновременно. Локальное фильтрующее приложение, занимающее это место, конкурирует с удалённым туннелем, который вам действительно нужен, а переключение между ними — операция уровня устройства, а не приложения. Это единственное место — хорошая причина держать политику нагрузки в приложении, а туннель оставить для пути.
Единственный случай, когда эти двое пересекаются, — частный сервер, который вы тоже администрируете. Там туннель может сделать путь частным, даже если протокол всё ещё открытый текст, что снижает экспозицию, но не меняет того, чем является нагрузка. Относитесь к этому как к снижению риска, а не как к шифрованию данных.
Что проверить, прежде чем называть это заблокированным
Начните с умолчания, которое удивляет людей: приложение, нацеленное на API 28 или новее, должно уже отказывать в открытом тексте, поэтому проверьте целевой уровень, прежде чем добавлять конфигурацию, дублирующую умолчание. Затем намеренно проверьте случай отказа: запрос к обычному HTTP-хосту должен завершаться неудачей, а не тихо проходить через резервный путь.
adb shell dumpsys package com.example.app | grep -E 'targetSdk|versionName'
adb logcat | grep -i cleartextДля случая успеха убедитесь, что вызов HTTPS проверяет настоящую цепочку сертификатов и что прокси с недоверенным сертификатом отклоняется, а не допускается. Рукопожатие, которое проходит с любым сертификатом, ничего не доказало о безопасности транспорта.
Для стороннего приложения запишите границу, которую вы действительно можете обеспечить, будь то политика управляемого устройства, сетевое правило или ничего, и скажите это в критериях приёмки. Руководство по конфигурации безопасности Android перечисляет умолчания платформы и то, какие компоненты соблюдают политику, и именно эта часть решает, делает ли ваша конфигурация хоть что-нибудь.