Данная статья является переводом соответствующей статьи Aditya Agrawal. Оригинал доступен по ссылке.

Недостаточная защита на транспортном уровне (небезопасная передача данных) занимает 3-е место в OWASP Mobile Top 10.

Почти все приложения Android передают данные между клиентом и сервером. Большинство приложений отдают предпочтение передаче данных через защищённый канал для предотвращения перехвата злоумышленником. В этом посте я попробую выделить некоторые проблемы, относящиеся к небезопасной передаче данных, способы эксплуатации этих проблем, а также пути их устранения.

Распространённые сценарии:

  • Отсутствие проверки сертификата: приложение Android не может проерить подлинность предъявленного ему сертификата. Большинство приложений игнорируют предупреждения и принимают самоподписанные (self-signed) сертификаты. Некоторые приложения вместо этого передают трафик через HTTP-соединение.
  • Уязвимая установка соединения (handshake): приложение и сервер производят установку соединения SSL/TLS, но используют для этого небезопасный набор алгоритмов, который уязвим к MITM-атакам. Таким образом, любой злоумышленник может с лёгкостью расшифровать данные, передаваемые через это соединение.
  • Утечка конфиденциальной информации: в большинстве случаев это происходит, когда приложения производят аутентификацию через безопасный канал, но в дальнейшем — через небезопасный канал. Это не добавляет приложению безопасности, т.к. остальные чувствительные данные (например, куки с сессиями) могут быть перехвачены злоумышленником.

В этом случае источниками угроз являются:

  • Пользователи в локальной сети (сеть Wi-Fi, в которой можно перехватывать трафик);
  • Сетевые устройства (роутеры, сотовые вышки, прокси и т.д.);
  • Вредоносное ПО, находящееся на устройстве;
  • Хакеры, которые пытаются атаковать используемые вами веб-сервисы.

Для демонстрации мы будем использовать приложение HerdFinancial из проекта OWASP GoatDroid.

  • Сначала внесём в приложение информацию о целевом сервере
  • 10_1 Теперь требуется установить в наше устройство/эмулятор Android прокси, чтобы перехватывать трафик между приложением и сервером. Если вы используете Genymotion, то зайдите в «Settings» -> «Wi-Fi», выберите сеть WiredSSID, и выберите пункт «Modify Network».
    10_2
  • В настройках прокси выберите «Manual» и введите IP-адрес и порт, на которые настроен Burp Suite или OWASP Zap.
    10_3
  • Теперь трафик устройства можно перехватывать с помощью Burp Suite или OWASP Zap
    10_410_5

Но, если попытаться запустить другие приложения типа Google Play Store или Facebook, то трафик увидеть не получится. Возможная причина этого в том, что Burp генерирует самоподписанные сертификаты для каждого хоста (например, google.com), и некоторые приложения не передают данные через канал, установленный с помощью этого сертификата. Как в примере выше, приложение Android передаёт данные через такой канал, что приводит к перехвату информации. Это самый худший сценарий, при котором приложение принимает любые сертификаты. Чтобы предотвратить подобное, в некоторых приложениях используют прикрепление сертификатов (certificate pinning).

Что такое прикрепление сертификатов?

По умолчанию, при установке соединения SSL клиент (приложение Android) проверяет, что сертификат сервера имеет проверяемую доверенную цепочку сертификатов до доверенного (корневого, root) сертификата и совпадает с запрашиваемым именем хоста. Это приводит к проблеме MITM-атаки (атаки типа «Человек посередине»).

При использовании прикрепления сертификатов приложение Android само содержит сертификат сервера и передаёт данные только тогда, когда предъявляется такой же сертификат.

  • Существуют редкие приложения, которые используют для передачи данных собственные протоколы вместо HTTP/HTTPS либо из-за требований, либо для предотвращения перехвата с использованием обычных техник;
  • Существуют ещё более редкие приложения, которые шифруют данные перед тем, как помещать их в тело HTTP(s)-запроса, который, в конце концов, передаётся на сервер через соединение SSL.

Facebook и другие приложения, разработчики которых заботятся о безопасности, используют как прикрепление сертификатов, так и шфирование тела HTTP(s)-запроса.

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

Первый сценарий

В разделе «Security» в настройках («Security» -> «Trusted Credentials») есть возможность просмотра всех доверенных сертификатов, установленных в системе.

Чтобы обойти защиту по первому сценарию, при котором приложение доверяет сертификатам только из списка доверенных. Требуется добавить сертификат Burp в список доверенных.

Для этого откройте браузер и наберите: «http://burp». На открытой странице перейдите по ссылке «CA Certificate» и загрузите сертификат.
10_6

10_7
Затем откройте файловый менеджер и откройте папку, в которую был загружен сертификат. Выберите этот файл и введите «Burp» в поле для имени.

10_8

10_9

Теперь, открыв список доверенных сертификатов в настройках, можно найти установленный сертификат PortsWigger.
10_10

Таким образом, мы установили сертификат в список доверенных, что поможет нам перехватывать трафик большинства приложений.

Второй сценарий

Существует два способа обойти защиту с использованием прикрепления сертификатов: изменив исходный код или с использованием приложения Android-SSL-Trust-Killer. Изменение исходого кода может быть достаточно утомительным, т.к. во многих приложениях Android шифрование реализовано по-своему.
Вместо этого мы пойдём по более простому пути, установив на устройство приложение Android-SSL-Trust-Killer, которое будет обходить прикрепление сертификатов практически для всех приложений.

  • Убедитесь, что на устройстве/эмуляторе установлен Cydia Substrate;
  • Загрузите Android-SSL-Trust-Killer;
  • Установите его с помощью ADB:
    adb install Android-SSL-Trust-Killer.apk
  • Перезагрузите устройство/эмулятор с помощью Cydia Substrate

Теперь с помощью Burp Suite можно перехватывать трафик большинства приложений.
10_11

Однако, если просматривать в Burp Suite запросы/ответы, можно заметить, что часть трафика в теле запроса/ответа невозможно прочитать, например, запрос, приведённый ниже, относится к приложению Gmail для Android.
10_12

Это данные, которые были зашифрованы перед помещением в тело запроса. В этом случае получить доступ невозможно, т.к. этот слой защиты сложно обойти.

Как всё это исправить

  • Применяйте SSL/TLS для каналов передачи данных, которые мобильное приложение использует для передачи конфиденциальной информации API бекенда или веб-сервису.
  • Используйте надёжные, стандартные наборы криптографических алгоритмов с соответствующей длиной ключа.
  • Используйте сертификаты, подписанные доверенными центрами сертификации, а также прикрепление сертификатов.
  • Оповещайте пользователей (через UI), если приложение обнаружит неправильный сертификат;
  • Если есть возможность, применяйте дополнительное шифрование любой конфиденциальной информации перед передачей через SSL. При обнаружении новых уязвимостей в SSL в будущем, это шифрование обеспечит конфиденциальность передаваемой информации.
  • После цикла разработки удалите весь код, который может позволить приложению принять любой сертификат, например, org.apache.http.conn.ssl.AllowAllHostnameVerifier или SSLSocketFactory.ALLOWALLHOSTNAME_VERIFIER.
  • Если при разработке используется класс SSLSocketFactory, убедитесь, что метод checkServerTrusted реализован так, что сертификат сервера проверяется корректно.