Прямая без препятствий. Часть 2. Защита мобильных приложений — выход найден?
В современных мобильных операционных системах нам по умолчанию недоступны права суперпользователя, а более-менее привилегированный доступ для приложений получить просто невозможно без использования уязвимостей. Поэтому невозможно сделать единое приложение, которое будет защищать все мобильное устройство из пользовательского пространства. Остается единственный выход — встраивать защиту прямо в защищаемое приложение.
Меня зовут Николай Анисеня, и я продолжаю рассказывать о безопасности мобильных приложений. В предыдущей статье мы подробно поговорили о состоянии защищенности приложений и девайсов на настоящий момент. Если коротко — приятных новостей мало. Но выход есть. В новой статье расскажу о перспективах защиты.
Работа на уровне исходного кода
Один из способов встраивать защиту в приложение — это ее непосредственная реализация в коде защищаемого приложения. Встречается как использование собственных разработок, так и использование коммерческих и опенсорсных SDK.
Из плюсов такого подхода — высокая степень контроля результата. Разработчики сами создают, отлаживают и документируют все механизмы защиты, контролируют все места встраивания защиты и получают предсказуемый результат.
К минусам такого подхода можно отнести тот факт, что на практике мало кто из разработчиков встраивает защиту действительно качественно. Необходимость вручную расставлять проверки по всему коду излишне нагружает команду разработки, и, как итог, в большинстве случаев разработчики ограничиваются небольшим количеством мест в коде, в которых есть интеграция методов защиты.
Отдельно к минусам использования SDK можно отнести тот факт, что SDK сам по себе доступен для реверс-инжиниринга: его можно исследовать отдельно от защищаемого приложения, что дает атакующему дополнительные возможности и облегчает процесс. Плюс ко всему сам SDK и, возможно, вспомогательные плагины, будут иметь доступ к исходному коду приложения, что может быть неприемлемо для некоторых компаний.
Работа на уровне компилятора
Некоторые протекторы имеют возможность встраивать защиту на уровне компилятора. Речь в данном случае идет в большей степени про техники обфускации, хотя для встраивания RASP данный подход тоже может использоваться.
Из плюсов — это мощный инструмент для обфускации, а также высокая гарантия стабильности приложения. Также к плюсам можно отнести меньшую нагрузку на разработку: нет необходимости вручную интегрировать защиту, достаточно только сконфигурировать параметры компиляции.
К минусам можно отнести все ту же необходимость конфигурировать защиту, что нагружает разработку, хоть и в меньшей степени, чем при работе с SDK. Доступ к исходникам у протектора также остается. Сам протектор тоже во многом подвержен реверс-инжинирингу: ничто не мешает атакующему заполучить коммерческую версию, чтобы исследовать ее работу.
Работа без исходников
Еще один способ встраивать защиту — работать с исполняемыми файлами. Плюс такого подхода в том, что протектор можно реализовать полностью прозрачным для разработки — от программиста не потребуется выполнять сложную настройку или писать дополнительный код. Кроме того, протектор не имеет доступа к исходному коду защищаемого приложения.
Минусы: нарушение стабильности и стоимость разработки такого протектора. В работе с исполняемыми файлами есть риск нарушить стабильную работу приложения. Более того, для тех, кто разрабатывает протектор с использованием такого подхода, разработка оказывается очень дорогой и требовательной к экспертизе. Крутые эксперты, большая команда разработки и тестирования с выстроенными процессами, оборудование или аренда тестовых устройств, а также их поддержка, все вместе — это очень дорого.
On-premise-решения
Протекторы, поставляемые в виде SDK, compile toolchain или в виде десктопного приложения, проводят все манипуляции локально. Плюс такого подхода — больше гарантий защиты от утечки исходного кода.
Минусы — удобство реверс-инжиниринга самой защиты в отрыве от защищаемого приложения, возможность конфигурировать защиту с вырожденными параметрами для более детального изучения.
SaaS-решения
Облачные протекторы, как правило, реализуют всю логику по внедрению защиты на стороне сервера. Из плюсов — реализация концепции zero trust. Протектор не знает ничего об исходниках — работает только с бинарными файлами, при этом держит свою логику максимально в секрете и не позволяет проводить реверс-инжиниринг защиты в отрыве от защищаемого приложения.
Этот подход не применяется для работы с исходниками, поэтому минусы тут следующие: необходимость передавать скомпилированные бандлы стороннему серверу, а также невозможность использования в средах сборки без доступа к интернету.
Централизованный подход
Один из вариантов реализации протектора — это сбор необходимой телеметрии (следов root/jailbreak, признаков использования эмулятора, кастомной прошивки, отладки, применения известных хакерских инструментов и т. д.) с устройства и приложения, а затем — принятие решения о блокировке. Плюс такого подхода в возможности использования собранной телеметрии для других целей (например, для античит- и антифрод-систем).
Минусом можно считать наличие единой точки отказа. В этом случае атакующему достаточно найти то место в коде, которое отвечает за принятие решения о блокировке приложения, и «запатчить» его. После этого любая телеметрия больше не будет иметь значения: приложение будет доступно для исследования.
Распределенный подход
Противоположный подход — модульная реализация каждой защитной техники, при которой каждый модуль действует независимо и самостоятельно принимает решение об аварийном завершении работы приложения. Этот подход также допускает многократное встраивание дублирующих защитных функций.
Плюсы подхода — отсутствие единой точки отказа. Минусы — сложная детальная настройка, если по каким-то причинам нам нужно принимать решение о блокировке по совокупности факторов.
Вариативность
Нередко злоумышленники могут потратить много времени на изучение одной конкретной версии мобильного приложения: какая в нем защита и как ее обойти. Научившись ее преодолевать, атакующий может доработать свой способ уже для свежей версии приложения с помощью сравнения двух версий. На практике очень часто после глубокого изучения защиты на старой версии приложения обойти защиту в новой версии атакующему удается гораздо быстрее.
Противодействовать такому сравнительному анализу можно, если использовать принцип вариативности. Строится он на том, что каждый билд приложения собирается с разной конфигурацией защиты, что усложняет атакующему поиск похожих паттернов в новой версии и буквально отбрасывает злоумышленника обратно к старту.
Этот принцип отлично сочетается с распределенным подходом, однако возможности вариативности могут сильно отличаться в продуктах разных производителей.
Гибридный подход
Очевидна идея реализации протектора с использованием всех этих подходов. Действительно, распределив логику между разными подходами, можно уменьшить влияние минусов каждого из них и получить их плюсы. Совместное использование нескольких подходов может дать гораздо более сильный и стабильный результат на выходе.
Сейчас большинство протекторов декларируют гибридный подход. Однако на практике все сильно зависит от реализации. При недостаточной экспертизе вместо объединения плюсов различных подходов можно получить совокупность их недостатков. Гибридный подход — самый требовательный к ресурсам и экспертизе R&D-команды, которая занимается его разработкой, поэтому это может отразиться на цене такой защиты.
Проблемы реализации защиты кода
Разнообразие технологий
В мире мобильной разработки очень много вариантов для выбора языка программирования и фреймворков. Помимо классических Java/Kotlin для Android и ObjectiveC/Swift для iOS, существуют еще кросс-платформенные фреймворки: React Native (JavaScript), Flutter (Dart), Xamarin (C#), Cordova и другие. Кроме этого, обе популярные платформы допускают разработку на C/C++. Для полноценной защиты разных приложений протектору необходимо уметь работать с особенностями того или иного языка программирования или фреймворка, а это требует поддержания большого штата высококлассных экспертов, разработчиков и тестировщиков.
Стабильность
При внедрении защиты в исполняемые файлы можно их повредить, что может привести к нестабильной работе приложения. Однако даже при работе на уровне исходников не исключены ложные срабатывания защитных механизмов. Все это сказывается на стабильности мобильного приложения. С точки зрения усложнения реверс-инжиниринга надежнее всего аварийно завершать работу мобильного приложения в случае обнаружения атак. Если показывать пользователю сообщение о том, что его устройство скомпрометировано, это также будет подсказкой для атакующего, откуда начать поиски в коде.
Производительность
Различные тяжеловесные техники обфускации, такие как шифрование строк, кода, экзотическое воздействие на control-flow graph (граф потока управления), — все это очень дорогостоящие операции. Сбор телеметрии, фоновые проверки RASP тоже отбирают ресурсы у основной бизнес-логики. Может случиться так, что агрессивные настройки защиты сделают приложение невозможным для использования на слабых или устаревших устройствах.
Ревью
Компании Google и Apple не особо рады, если вы применяете технологии защиты кода. Дело в том, что данные техники используются не только для защиты хороших приложений, но и для сокрытия вредоносной нагрузки от средств анализа кода. Разные магазины приложений имеют разные, но схожие рекомендации в отношении того, что запрещено использовать в приложении: виртуализация, доступ к приватным API, динамическая загрузка кода и прочее. Но познавать все тонкости процесса ревью приходится на практике, так как в действительности эти правила постоянно меняются. Компаниям, разрабатывающим протекторы, приходится тратить дополнительные ресурсы на изучение этих процессов в различных магазинах приложений, чтобы гарантировать своим клиентам возможность загрузки приложения в маркеты. Если вы хотите использовать протектор, важно выбирать достаточно экспертную команду, чтобы использование протектора было максимально «бесшовным».
Итог
На наш взгляд, самым перспективным и современным подходом к реализации протектора мобильных приложений является гибридный подход. Совершенно точно необходимо сочетание централизованных и распределенных методов реализации механизмов защиты, а также высокая вариативность. Концепция zero trust и реализация в виде SaaS являются предпочтительными с точки зрения безопасности.
На мой взгляд, выделять RASP отдельно не совсем эффективно. Наш многолетний опыт подсказывает, что реально бороться с атакующим можно, только препятствуя статическому и динамическому анализу одновременно. А это означает, что применение техник RASP попросту лишено смысла, если они используются в отрыве от техник обфускации и других статических преобразований для харденинга кода мобильного приложения. Именно поэтому средства защиты мобильных приложений не должны быть только обфускаторами, только RASP или только харденингом. Это должен быть сервис-протектор, который вберет в себя все эти техники.
При этом защита должна быть для разработчика простой в использовании и прозрачной. Для лучшего контроля стабильности допустимо наличие вспомогательных инструментов, работающих с исходным кодом.
Хочется верить, что использование протекторов мобильных приложений станет новым стандартом в мобильной разработке уже в течение ближайших лет. Хорошая защита кода может снизить риски, уберечь ваш бизнес от потерь в результате реализации недопустимых событий, связанных с реверс-инжинирингом, а также высвободить ресурсы вашей команды на задачи, которые нельзя поручить продукту или сервису.