Вступление
При разработке мобильного приложения следует учитывать, что данные, которыми оперирует это приложение, могут представлять определенный интерес для третьих лиц. Степень ценности этих данных варьируется в широких пределах, тем не менее, даже наиболее простая приватная информация, например, пароль входа в приложение, требует проработки ее защиты. Особенно это важно в свете распространения мобильных приложений на все сферы электронных услуг, включая финансовые, банковские операции, хранение и передачу личных данных и так далее.
Все нижесказанное — исключительно мой опыт, безусловно, данные могут быть неточными, поэтому буду благодарен за любые поправки и дополнения к статье. Я не нашел исчерпывающих статей в сети на подобную тематику, которые бы собирали всю нужную (хотя бы базовую) информацию в одном месте, поэтому решил обобщить свой опыт в этой области на текущий момент времени. Всем интересующимся — добро пожаловать под кат.
Защита мобильного приложения
Основные направления атаки на мобильное приложение:
- Декомпиляция файла приложения (.ipa для Apple iOS и .apk для Google Android) и разбор локально сохраненных данных. Защита этого, наиболее важного в настоящее время, уровня целиком лежит на плечах мобильного разработчика.
- Перехват данных, передаваемых по сети (MITM-атаки). Большинство мобильных приложений являются клиент-серверными, следовательно, постоянно передают и принимают большие объемы информации. И хотя современная мобильная и веб-разработка активно завершают переход на HTTPs-протокол общения, тем не менее, не стоит полагаться на единственный рубеж защиты в виде защищенного канала связи.
Перечень основных уязвимостей приложений
Рассмотрим уязвимости общего характера, без привязки к конкретной платформе. Здесь и далее используется аббревиатура КВД — критически важные данные пользователей. К КВД относятся любые данные, которые не должны быть доступны третьей стороне, это касается как персональных данных пользователя (дата рождения, адрес проживания, личная переписка), так и его приватных данных (пароли, данные кредитных карт, номера банковских счетов, номера заказов и так далее).
| Уязвимость | Опасность | Описание | Защита |
|---|---|---|---|
| Использование незащищенных локальных хранилищ | Очень высокая | Встречается повсеместно, выражается в хранении КВД в незащищенных или слабо защищенных локальных хранилищах, специфических для конкретной платформы. Вскрытие третьей стороной — элементарное, и, как правило, не требуется наличие специальных навыков. | Хранить КВД можно только в защищенных хранилищах платформы. |
| Хранение КВД в коде | Высокая | Уязвимость касается хранения КВД внутри кода (в статических константных строках, в ресурсах приложения и т.п.). Яркие примеры: хранение соли для пароля (password salt) в константе или макросе, которая применяется по всему коду для шифрования паролей; хранение приватного ключа для асимметричных алгоритмов вроде AES; хранение паролей и логинов для серверных узлов или баз данных. Легко вскрывается третьей стороной при наличии навыков декомпиляции. | Не хранить никакие КВД в коде или ресурсах приложения. |
| Использование самописных алгоритмов шифрования и защиты | Высокая | Выражается в попытке разработчика изобрести "свой личный, не известный никому, а поэтому супер-защищенный алгоритм шифрования". Любое отклонение от существующих, многократно проверенных и изученных, математически доказанных алгоритмов шифрования в 99% случаев оборачивается быстрым взломом подобной "защиты". | Следует подбирать подходящий алгоритм только из отлаженных и актуальных общеизвестных криптографических алгоритмов. |
| Применение асимметричных алгоритмов | Средняя | Вытекает из первого пункта. Для асимметричных алгоритмов это актуально в случае, если приватная информация алгоритма вынужденно сохраняется в коде или ресурсах мобильного приложения (чаще всего так и бывает). Для симметричных — всегда есть риск вскрытия данных, если станет известен сам алгоритм (что, в свою очередь, вскрывается реверсивной инженерией). | В мобильной разработке желательно применять только современные симметричные алгоритмы, обладающие высокой стойкостью с взлому методом грубой силы. |
| Передача КВД во внешнюю среду в открытом виде | Средняя | Выражается в передаче КВД без применения шифрования по любому доступному каналу связи с внешней средой, будь то передача данных стороннему приложению или передача в сеть. Может быть вскрыто опосредованно путем вскрытия не приложения, а его хранилища, или целевого приложения. Взлом требователен к наличию навыков у атакующего, при условии, что хранилище является защищенным. | Любые КВД перед выходом за пределы приложения должны быть зашифрованы. Локальные хранилища платформы не являются областью приложения, они тоже должны получать на вход только зашифрованные данные. |
| Игнорирование факта наличия рутованных или зараженных устройств | Средняя | Рутованные устройства — это девайсы, где выполнена модификация для получения прав суперпользователя на любые операции, изначально запрещенные производителем операционной системы. Выполняется пользователем на своем устройстве самостоятельно, и не обязательно добровольно (клиент может быть не в курсе, что устройство взломано). Установка приложения на рутованный девайс нивелирует все штатные средства защиты операционной системы. | Сводить наличие КВД в приложении к возможному минимуму, применять шифрование КВД независимо от места, где предполагается их хранить. Не полагаться только на штатные механизмы защиты ОС в критически важных секциях приложения (применять дополнительное усиление при необходимости). |
| Хранение КВД в защищенных хранилищах, но в открытом виде | Средняя | Разработчик зачастую склонен сохранять КВД в защищенные системные хранилища без дополнительной защиты, поскольку системные механизмы хорошо сопротивляются взлому. Однако уровень их стойкости падает до минимума в случае, если устройство рутованное. | КВД не должны использоваться в приложении без дополнительного шифрования. Как только надобность в "открытых" КВД отпала — они немедленно должны быть либо зашифрованы, либо уничтожены. |
| Перевод части функционала во встроенные веб-движки | Средняя | Чаще всего выглядит как передача КВД во встроенный браузер, где загружается внешняя веб-страница, выполняющая свою часть функционала. Уровень защиты в этом случае резко снижается, особенно для рутованных устройств. | Не использовать встроенный браузер и встроенный веб-движок в операциях с КВД. На крайний случай — шифровать КВД перед передачей. |
| Реверсивная инженерия алгоритмов, представляющих интеллектуальную ценность | Низкая, зависит от ценности алгоритма | Если при разработке приложения внутри компании используются некие собственные алгоритмы, которые могут представлять высокую ценность для потенциальных конкурентов или взломщиков, то эти алгоритмы должны быть защищены от постороннего доступа. | Автоматическая или ручная обфускация кода. |
Специфика разработки мобильных приложений
Есть несколько общих для всех мобильных платформ моментов, которые следует соблюдать при разработке.
Защита пользовательским кодом
- Если приложение защищено пользовательским паролем (PIN-кодом, сканом отпечатка пальца, графическим паролем и т.д.), то при уходе приложения в фон ("сворачивании") оно должно немедленно отображать окно ввода этого защитного кода, перекрывая собой весь экран приложения. Это исключает возможность для злоумышленника получить приватную информацию в случае кражи устройства, пока приложение все еще запущено и находится в спящем режиме.
- Любой пользовательский код должен иметь ограниченное количество попыток ввода (например, 5 раз), затем, в случае неудачи, приложение должно автоматически разлогиниваться (или и вовсе блокироваться, зависит от конкретного приложения).
- В настоящее время при использовании цифровых кодов строго рекомендуется использовать ограничение на длину кода в минимум 6 цифр (больше можно, меньше — нельзя).
Функционирование клиент-серверного приложения
- Для клиент-серверных приложений очень полезно применять сессионный механизм с ограниченным временем жизни сессии. Это позволит избежать "простаивания" приложения в незащищенном режиме, если пользователь просто забыл закрыть его и оставил устройство в свободном доступе. Следует учитывать, что срок действия сессии и ее идентификатор относятся к КВД, со всеми вытекающими отсюда последствиями.
- Клиент-серверное приложение не должно осуществлять работу с КВД в локальном режиме. Любое действие, требующее использования КВД, должно проходить синхронизацию с сервером. Исключение из этого правила составляет только пользовательский защитный код входа, задаваемый лично пользователем и сохраненный в защищенном локальном хранилище.
Работа с датами
- При оперировании важными для работы приложения датами, вроде времени уничтожения сессии, не следует опираться на относительное время. То есть, передаваемые с сервера данные не должны содержать дату в виде "плюс N секунд/часов/дней от текущего момента". В силу наличия потенциально высоких задержек в передаче данных по сети от мобильного приложения к серверу и обратно, подобный способ синхронизации будет обладать слишком большой погрешностью. Кроме того, атакующий (или просто недобросовестный пользователь) может попросту сменить локальный пояс на устройстве, нарушив таким образом логику работы ограничительных механизмов приложения. Всегда нужно передавать только абсолютное значение времени.
- Абсолютные значения следует передавать с применением универсальных способов обмена подобной информацией, без привязки к часовому поясу конкретного пользовательского устройства. Чаще всего, оптимальным вариантом является поведение приложения, при котором данные отображаются пользователю в его локальном часовом поясе, но их хранение и передача осуществляется в формате, не привязанном к тайм-зоне. Подходящими форматами для дат и времени являются либо универсальный UNIX timestamp, сохраненный в переменной 64-битного целого знакового типа (UNIX timestamp — это количество секунд, прошедшее с 1 января 1970 года), либо, на крайний случай, строка в формате ISO-8601 с нулевой тайм-зоной. Предпочтителен именно UNIX timestamp, он позволяет избежать потенциальных ошибок и проблем с конвертацией строк в дату и обратно на разных мобильных платформах.
Дополнительные рекомендации
- Приложение не должно без особой необходимости отображать приватную пользовательскую информацию большими, яркими, хорошо читаемыми шрифтами, без явной на то необходимости и без отдельного запроса пользователя, чтобы исключить возможность чтения этих данных издали с экрана устройства.
- Не стоит слепо доверять библиотекам с открытым исходным кодом, которые предлагают некую защиту приватным данным пользователей. Исключение составляют библиотеки, проверенные временем и используемые в крупных проектах корпораций (например, шифрование в открытом движке БД Realm). Штатных механизмов защиты операционной системы и общедоступных проверенных криптографических алгоритмов в абсолютном большинстве случаев будет более, чем достаточно.
- В релизных сборках приложений должно быть отключено логгирование данных в системную консоль, специфические логи для разработчиков могут присутствовать, но желательно в закрытом виде, во избежание доступа третьих лиц к закрытой служебной информации, которая может присутствовать в логах.
Специфическая информация по платформе iOS
| Хранилище данных | Уровень защиты | Комментарий |
|---|---|---|
| NSUserDefaults | Отсутствует | Используется только для хранения безопасных для функционирования приложения данных, не связанных с приватной информацией. Чаще всего туда записывают только клиентские настройки интерфейса. Для других данных это хранилище не подходит, так как вскрывается оно за несколько секунд. |
| Бинарные файлы (NSKeyedArchiver) | Зависит от разработчика | Сами по себе являются физическими файлами и могут быть элементарно доступны третьей стороне. Уровень защиты зависит исключительно от примененных к данным алгоритмов шифрования. Это не самое удобное место для хранения данных, поэтому без особой необходимости (чаще всего это возможность передавать эти данные, к примеру, по электронной почте) лучше подобный способ не применять. |
| Базы данных | Зависит от разработчика | Современные БД поддерживают внутреннее шифрование данных. Разработчику понадобится найти баланс между шифрованием и производительностью, включить шифрование базы для критических данных, а также дополнительно применять шифрование для КВД перед записью в базу. |
| Связка ключей (Keychain) | Максимальная (кроме джейлбрейка) | Наиболее удачное место для хранения любых КВД. Однако, учитывая, что устройство может быть рутованным, все КВД должны быть зашифрованы дополнительно перед сохранением в Keychain. Кроме того, нужно с осторожностью использовать облачную синхронизацию из-за возможности автоматического сохранения Keychain в облаке. В случае, если приложение использует Cloud Kit, необходимо внимательно следить за данными, которые не должны синхронизироваться (если таковые имеются), и исключать их из набора копируемых данных. |
Специфическая информация по платформе Android
Я слабо разбираюсь в платформе Android, поэтому нижеизложенный список — это краткое тезисное изложение базовых материалов, которые мне удалось найти:
- Наиболее удачным вариантом пользовательского кода является графический код, цифровой (6 цифр или более) — как дополнительный вариант.
- Запрос разрешений (permissions) на определенные виды активности приложения обязателен и должен выполняться явно для пользователя с разъяснением, для чего именно будет использовано разрешение. Запрашивать определенное разрешение нужно только в случае прямой необходимости его использования, также, запрос на разрешение нужно показывать именно в тот момент, когда оно понадобилось, не ранее. Кроме того, если целевая версия Android SDK равна 23 (или новее) — то следует проводить запрос разрешений только через систему разрешений совместимости (Compatibility Permissions System).
- HTTP-клиент должен быть настроен на принудительное использование защищенного канала связи (HTTPs).
- В релизной сборке приложения должны быть отключены все отладочные функции, например, опция debuggable, во избежание возможности подключения к программе внешним отладочным приложением.
- На экранах приложения, где размещается приватная информация пользователя, будет не лишним принудительный запрет на программное создание скриншотов окна приложения, а также отключение показа скриншотов в диспетчере задач.
- Любая приватная информация может дополнительно предваряться запросом личного ключа пользователя, заданного им для входа в приложение (если таковой имеется).
- Внутри кода приложения для резолвинга путей рекомендуется пользоваться
getCanonicalPathвместоgetAbsolutePath. - Используемые в приложении открытые компоненты (например, Service или Content Provider) должны быть обязательно закрыты с помощью флага
exported = falseв манифесте приложения (Android Manifest). Это позволит запретить доступ к этим компонентам из другого приложения.
Кроме того, нужно с осторожностью использовать доступные хранилища информации:
| Хранилище данных | Уровень защиты | Комментарий |
|---|---|---|
| Shared Preferences | Отсутствует | Должно использоваться только по прямому назначению, а именно — для хранения общедоступных незащищенных пользовательских настроек. Остальные данные здесь размещаться не должны. |
| Базы данных (SQLite) | Зависит от разработчика | Представляет собой обыкновенные файлы, так что все КВД перед записью должны быть соответствующим образом зашифрованы. База допускает возможность автоматического шифрования, его включение будет хорошим усилением защиты данных. В качестве ключа шифрования наиболее целесообразно применять код защиты, задаваемый лично пользователем приложения (код, в свою очередь, должен быть зашифрован и сохранен в Account Manager, см. описание ниже). |
| Account Manager | Высокая (только до API v.18) | Здесь следует размещать все КВД, но предварительно обязательно нужно выполнить дополнительное шифрование данных. |
| KeyStore | Максимальная (кроме рутованных устройств) | Аналогично Account Manager, но настоятельно рекомендуется пользоваться этим хранилищем вместо него, в случае, если KeyStore доступно разработчику (API v.18, Android 4.3 и новее). |
Заключение
Также стоит упомянуть, что количество применяемых уровней защиты зависит от конкретного приложения. К примеру, если приложение вообще не является клиент-серверным, не содержит никаких КВД, а также не оперирует ценными внутренними алгоритмами, то вообще нет смысла навешивать на него какую-либо защиту. Если же приложение ориентировано, например, на выполнение банковских операций, или хранение пользовательских паролей, то степень его безопасности должна быть наивысшей. Однако перечисленные ранее общие уязвимости мобильного сектора достаточно легко могут быть исключены из приложения, чаще всего это не вносит особых дополнительных затрат, если применение требуемого уровня защиты было начато на ранних этапах разработки приложения. А вот внедрение защиты пост-фактум в уже работающее приложение вполне может быть сопряжено со значительными затратами сил и времени разработчиков. Поэтому выбор и согласование уровня защищенности, а также перечня КВД в разрабатываемом приложении, должны выполняться на самых ранних этапах проектирования.
ссылка на оригинал статьи https://habrahabr.ru/post/327760/
Добавить комментарий