Привет! Я Линар Юнусов, тестировщик из мобильной команды СберМаркета. При создании списка проверок мы попросили помощи у команды информационной безопасности, отдельная благодарность Дмитрию Терёшину за проведённую встречу с подробным разбором всех кейсов. Его интересную статью по работе утилиты CheckKarlMarx можно увидеть здесь.
В конце концов получили из кейсов самые опасные области атак на приложение с точки зрения безопасности, взяли high-сценарии и добавили их к себе в список чек-листов для регрессионного тестирования. Так родилась идея рассказать в статье, что популярного и интересного можно добавить в список кейсов для регресса в любой компании.
Речь пойдет о том, какие проверки безопасности и какие кейсы мы советуем добавить при регрессионном тестировании. Проверки, описанные в этой статье, — это не все проверки, которые проводятся у нас, их, конечно же, больше, но рассказывать обо всех проверках небезопасно, поэтому тут всего лишь небольшая их часть, которую следует учитывать при тестировании безопасности приложения. Также не забываем о документах о неразглашении определенных данных.
Динамический анализ
Для начала обсудим динамический анализ приложения, при котором проверяют приложение во время его работы. Исследуя приложение динамически, мы можем посмотреть логи, открыть и проверить содержимое KeyChain или БД, проверить уходящие данные при открытии WebView или отправке зашифрованных данных в API. Всё это представляет собой whitebox- или graybox-тестирование.
Исследуем запросы с чувствительными данными
Самый простой кейс: все запросы, которые могут хранить в себе чувствительные данные, должны иметь параметры контроля работы кэширования. Мы чаще всего используем три вида: no-cache, no-store, must-revalidate. Чувствительными данными можно считать любые данные, передающиеся в запросах об оплате, авторизации, регистрации.
Параметр must-revalidate позволяет делать запрос каждый раз по новому, чтобы не брать закэшированные данные, и поэтому применять его лучше при работе с оплатой.
Параметр no-store говорит о том, что данные из запросов не будут лежать в кэше на стороне клиента, так как эта информация чувствительна.
Такой параметр содержит запрос отправки СМС-кода.
Используемый чаще всего параметр no-cache говорит о том, что этот запрос уходит каждый раз заново и не кэширует данные.
К примеру, запрос на получение изображений должен содержать этот параметр, чтобы кэш на стороне клиента не хранил огромное количество изображений, которые могут весить очень много.
Чувствительные данные не должны передаваться третьим лицам (в сторонние сервисы, сервис аналитики). Для этого необходимо проводить динамический анализ событий, которые уходят в сторону сервисов аналитики, crashlytics, разных привязанных платформ. Для сниффинга трафика мы используем Charles. Проверяя этот кейс, можно убедиться, что чувствительные данные не были видны сотрудникам при просмотрах собираемых данных об устройствах пользователей, а также, что данные не уходят в логи используемых сервисов. Чувствительными данными считаются данные об оплате пользователя, пользовательские данные, одноразовые пароли.
Проверяем logout в приложении
Мы живем во времена, когда почти каждое второе мобильное приложение позволяет создать свой аккаунт или использовать сервисы аутентификации (Сбер ID, VK ID, Apple ID, Google Auth). После каждого входа в аккаунт на стороне клиента образуется кэш с полученными данными: адрес, номер телефона, почта, реквизиты банковских карт и т. д. А где есть кнопка входа, там должна быть кнопка выхода, и именно работа приложения после логаута пользователя тоже требует тестирования безопасности.
После логаута пользователя все данные, которые касались его аккаунта, должны быть удалены из кэша на стороне мобильного клиента. Сделано это ради того, чтобы данные нельзя было слить дальше приложения (например, в память устройства, к которой могут иметь доступ другие приложения пользователя).
В дополнении к логауту хорошей практикой считается привязать к этому запрос, который уйдет на сервер и сообщит, что токен сессии пользователя необходимо инвалидировать.
Проверить подобный кейс можно так: отправить запрос на бэкенд с токеном авторизации пользователя (полученным при активной сессии). Если нет ошибки аутентификации после логаута с токеном пользователя, значит, есть проблема на бэке и токен не инвалидируется сервером.
Разбираем БД на стороне клиента
Как же просмотреть удаленные данные после логаута? Если у вас установлен root на устройстве, то динамический анализ данных для Android возможен через простую команду:
adb pull /data/data/<package name>
Если нет рута, то всегда под рукой находится инструмент для просмотра локальной базы данных — Database Inspector из Android Studio. Там можно просмотреть, какие данные записаны в локальную базу приложения, совершить логаут и после обновления содержимого инспектора увидеть, остались ли какие-то ещё чувствительные данные. Если после логаута данные остались — токены авторизации, данные профиля, данные об оплате, — тест не пройден.
Для проверки данных на стороне iOS можно использовать Realm Studio — это инструмент, который помогает увидеть таблицы с данными в приложении, то есть даёт доступ к Keychain.
Realm Studio позволяет работать с БД на стороне симулятора или реального устройства, но на симуляторе можно в режиме реального времени редактировать данные для более удобного тестирования. Рассказ про инструменты просмотра БД стоит отдельной статьи в нашем блоге СберМаркета.
WebView, или Как открывать web на стороне мобильного клиента
Важно также не упустить из виду работу WebView, открытие ссылок внутри приложения и работу с открытием универсальных линков через приложение.
Мы пришли к следующему решению. Все ссылки, которые могут требовать данные пользователя и требуют интеграции с нашим приложением, открываются внутри приложения и используют только WebView в Android и WebKitWebView на стороне iOS. Для всех внешних ссылок мы используем SFViewController или Safari App (по желанию пользователя) и Chrome Custom Tab на Android. Это обусловлено тем, что через View-часть можно получить ID пользователя или токен авторизации. JavaScript отключен в компонентах WebView для внутренних ссылок, если в нём нет необходимости, обычно выключен по дефолту, не должно быть setJavaScriptEnabled – true. Web-часть работает через React Native Bridge — промежуточное звено между нативным кодом и js. На данном уровне Chrome Custom Tab на Android, SFViewController на iOS очень любят просить cookie-файлы, что также не приветствуется при открытии внутренних ссылок.
Это были простые функциональные проверки при динамическом анализе.
Статический анализ
Статический анализ при тестировании безопасности включает в себя проверку исходного кода приложения на захардкоженные данные в виде паролей, ссылок. Также необходимо проверить включенные флаги в конфигурационных файлах, включенные разрешения на доступы к аппаратным средствам. В коде приложения, который уходит в релиз, не должны находиться тестовые данные пользователей, данные тестовых окружений.
Анализ кода проекта
Для начала следует проверять исходный код проекта на хардкод ключей: открыть в IDE проекты и в расширенном поиске ввести ключевые слова: key, privateKey, secretKey, password, token, passphrase. Поиск по этим словам даёт доступ ко всем расширениям, enum, конфигурационным файлам, используемым переменным и константам в проекте, а это типичные места, где может находиться бэкдор. При поиске стоит обратить внимание, чтобы переменные не содержали в себе вшитые пароли, логины, ключи и коды доступа. Стандартные примеры хардкода паролей вы можете найти в интернете.
if($email == '123@spe.com' && $password == '123123') {
$this->bypass($email, $password);
}
Это самый простой бэкдор, конечно же, проверяемый отделом безопасности при код-ревью, однако чем раньше будет найдена уязвимость, тем внимательнее команда станет относиться к коду.
Дополнительные проверки:
- Кэширование клавиатуры при вводе чувствительных данных должно быть выключено. Чтобы отключить кэширование, нужно у всех объектов, работающих с чувствительными данными, выставить флаг textObject.autocorrectionType = UITextAutocorrectionTypeNo. Для проверки проще всего использовать динамический анализ, заранее удалив кэш клавиатуры на устройстве, и пройтись по чувствительным полям приложения. Клавиатура не должна подсказывать какие-либо сохраненные данные.
- Также весь трафик должен работать через TLS-протокол, это уже стандарт зашифрованного трафика.
- One Time Password будет ограничен по времени, и токен для его получения генерируется всегда уникальным.
- Сервер всегда защищен от брутфорс-атак со стороны мобильного клиента. Любой перебор паролей, One time password и другое должны быть ограничены сервером.
К примеру, мы используем подобное в нашем приложении при получении СМС-кода. Также у нас есть ограничения на количество попыток: после трёх неуспешных вводов СМС-кода пользователь блокируется на 24 часа.
- Приложение не использует устаревшие криптоалгоритмы (DES, 3DES, RC2, RC4, BLOWFISH, MD4, MD5, SHA1). Проверить данный кейс можно с помощью статического анализа, поискав в исходном коде приложения названия криптоалгоритмов. Было бы классно не забыть не использовать сторонние опенсорсные реализации криптоалгоритмов (только библиотеки, входящие в SDK).
- Чувствительные данные не пишутся в системные логи. Проверить подобный кейс можно будет при запуске Logсat на Android и через вывод логов на Xcode.
- На бэкенде реализована парольная политика (требования к паролям). То есть пароли не имеют простой генерации и сервер защищает пользователя от выбора простого набора символов/чисел.
Вместо заключения
В этой статье я постарался собрать стандартные проверки безопасности перед релизом приложения в стор. Но не стоит забывать, что всё описанное выше не всегда проводилось методом белого ящика. Для широкого анализа вашего приложения необходимо иметь устройства с root и Jailbreak. Это поможет увидеть хранимые данные во внутренней директории приложения. Существуют современные подходы к поиску уязвимостей, такие как открытые intents, что позволяет вредоносному приложению установить свой Activity поверх Activity вашего приложения, инструменты по типу Frida для работы с бэкапом вашего приложения, также поиск уязвимостей в используемых библиотеках.
Если вам интересна тема безопасности приложений, рекомендую Android глазами хакера и The Mobile Security Testing Guide. В представленных книгах есть не только большое количество новых кейсов по пентесту мобильных приложений, но и обзор разных уязвимостей мобильных операционных систем!
Я надеюсь, озвученные проверки появятся в ваших чек-листах и помогут увеличить тестовое покрытие вашего приложения! Тестирование безопасности — это интересно:)