Безопасность IOS-приложений (часть 25) – Методы написания безопасного кода

Безопасность IOS-приложений (часть 25) – Методы написания безопасного кода

В этой статье мы рассмотрим некоторые техники, которые следует использовать при разработке IOS-приложений для того, чтобы сделать их более безопасными.

Автор: Пратик Джианчандани (Prateek Gianchandani)

В этой статье мы рассмотрим некоторые техники, которые следует использовать при разработке IOS-приложений для того, чтобы сделать их более безопасными.

Локальное хранение данных

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

  • Конфиденциальную информацию (пароли, сессии и т. д.) никогда не следует хранить на устройстве. Если других вариантов нет, тогда следует использовать keychain. В этом случае, вы можете быть уверены, что злоумышленник не сможет добраться до этой информации до тех пор, пока не будет сделать джейлбрейк на пользовательском устройстве. Кроме того, 70% пользователей уже обновились до IOS 7, и на данный момент (10 декабря 2013 года) не существует публичного джейлбрейка для этой операционной системы. Некоторые могут возразить о том, что хранение информации в keychain не так просто, как, скажем, в NSUserDefaults. Однако мы всегда можем воспользоваться средствами от сторонних разработчиков, чтобы облегчить свою работу. Например, в этой статье демонстрируется использование обертки PDKeychainBindings и то, насколько просто при помощи нее сохранять информацию в keychain (см. нижеследующий код).

    PDKeychainBindings *bindings = [PDKeychainBindings sharedKeychainBindings];
    [[[Model sharedModel] currentUser] setAuthToken:[bindings objectForKey:@"authToken"]];


    Однако не забывайте, что на джейлбрейковом устройстве информация, которая хранится в keychain, не защищена. Кроме того, крайне желательно использовать свои собственные алгоритмы для шифрования строк, которые будут храниться в keychain. Подобные меры позволят усилить уровень безопасности приложения, так как даже если злоумышленник получит информацию из keychain, ему нужно будет ее расшифровать.

  • Никогда не следует использовать NSUserDefaults для хранения конфиденциальной информации (паролей, аутентификационных токенов и т. д.), поскольку эта информация хранится в незашифрованном виде в plist-файле, который можно найти в Library -> Preferences -> $AppBundleId.plist внутри вашего приложения. Любой может воспользоваться утилитой iExplorer и получить plist-файл даже на устройстве, где нет джейлбрейка.
  • Также не следует использовать plist-файлы для хранения конфиденциальной информации, поскольку к ней легко можно получить доступ даже на устройстве без джейлбрейка. Все содержимое plist-файла хранится в незашифрованном формате.
  • Файлы Core Data также хранятся как незашифрованные базы данных. Фреймворк Core Data использует sql-запросы для хранения данных и, следовательно, все файлы хранятся с расширением .db. При помощи утилит наподобие sqlite3 любой может получить доступ к этой информации.

Безопасность на транспортном уровне

  • Запретите использование самоподписанных сертификатов в окончательной версии приложения. Большинство разработчиков разрешают использование самоподписанных сертификатов в отладочном режиме, однако не следует этого делать в рабочей версии приложения.
  • Не используйте уникальные параметры устройства (MAC-адрес, IP-адрес, UDID) при формировании идентификаторов сессий, аутентификационных токенов и т. д.
  • Алгоритмы аутентификации старайтесь выносить на сервер, поскольку злоумышленник может манипулировать вашим приложением во время его работы.
  • Надежная проверка входных данных должна проходить и на клиенте и на сервере. Злоумышленник всегда может модифицировать запрос, используя Burpsuite. Важно проверять параметры, посылаемые на сервер, во избежание инъекций.

Использование шифрования

  • Шифруйте важные файлы перед сохранением их на устройстве. При этом вам не обязательно быть экспертом в шифровании, и вы вполне можете использовать сторонние библиотеки. Я написал статью «Encrypting images and saving them in App Sandbox», где используется библиотека RNCryptor, которая доступна на Github. Ту же самую технику можно использовать при шифровании любых других файлов. Следующий кусок кода показывает, насколько просто это сделать.

    UIImage *imageToEncrypt = [UIImage imageNamed:@"SomeImage"]; NSString *imagePath = [NSHomeDirectory()
    stringByAppendingPathComponent:@"Documents/encryptedImage.png"];
    NSData *data = UIImagePNGRepresentation(fetchedImage); NSError *error;
    NSData *encryptedData = [RNEncryptor encryptData:data withSettings:kRNCryptorAES256Settings password:@"
    ABC123" error:&error]; [encryptedData writeToFile:imagePath atomically:YES];


    При шифровании файлов SQlite обратите внимание на SQLCipher.

Добавление проверок для защиты от динамического анализа

  • Помните о том, что у злоумышленника есть полный контроль над копией бинарного файла вашего приложения. Однако можно значительно затруднить ему жизнь при анализе файла. Один из таких способов – запрет отладки приложения. Более подробно об этом рассказывалось в двадцать третьей статье этой серии. Для этого файл main.m должен выглядеть примерно так:


    Рисунок 1: Модифицированный файл main.m для запрета отладки приложения

    Эти изменения запрещают подключения отладчика к приложению. В одной из статей мы уже рассматривали, как сохранить все вызовы при помощи Snoop-it (см. девятую статью этой серии). Ниже приводится скриншот из этой статьи.


    Рисунок 2: Вызовы функций

    Если мы внесем вышеуказанные изменения в файл main.m, то создать подобный журнал будет невозможно, поскольку при этом Snoop-it использует отладчик. Теперь при попытке сохранить вызовы функций произойдет немедленное завершение приложения. Помните о том, что эта проверка не защитит вас от использования утилиты Cycript.

Дополнительные меры безопасности

  •  Текстовые поля, используемые для паролей, следует использовать со специальной опцией (для этого следует установить флажок Secure), поскольку в обычном режиме IOS кеширует вводимую информацию. Также отключите функцию AutoCorrection для этих текстовых полей (см. рисунок ниже).


    Рисунок 3: Установка всех необходимых настроек для текстового поля
  • Очищайте Pasteboard, как только приложение переходит в фоновый режим. Это можно сделать путем изменения метода - (void)applicationDidEnterBackground:(UIApplication *)application в AppDelegate. Если вы используйте собственный Pasteboard, вставьте вместо [UIPasteboard generalPasteboard] ваш собственный Pasteboard.

    – (void)applicationDidEnterBackground:(UIApplication *)application
    {
    // Use this method to release shared resources, save user data, invalidate timers,
    and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    [UIPasteboard generalPasteboard].items = nil;
    }
  • Проверяйте входные данные перед осуществлением при помощи URL-схем любых критически важных действий. Как известно, любое приложение может зарегистрировать URL-схему. Например, приложение Skype может зарегистрировать схему skype://, и любое другое приложение может использовать эту схему с определенным параметром, что позволяет общаться приложениям между собой. Ранее в Skype была уязвимость, когда пользователь мог сделать вызов при помощи такого url: skype://123123123?call

    Поскольку Skype не оповещал пользователя перед совершением вызова, вызовы посылались напрямую. Параметры схемы также следует проверять. Вы можете добавить такой метод - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url в AppDelegate

    – (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
    //Validate input from the url
    return YES;
    }
  • Некоторые приложения используют компонент UIWebViews, предназначенный для отображения содержимого URL. В 2011 году были найдены уязвимости UIWebViews в популярных приложениях. Также UIWebViews поддерживает javascript, и на данный момент не существует публично доступного API для отключения javascript в UIWebview. Таким образом, если любые пользовательские входные данные используются для наполнения содержимого UIWebview, эту фишку может использовать злоумышленник для выполнения javascript-кода в UIWebview. Даже если входные данные не контролируются пользователем, злоумышленник может манипулировать содержимым, добавляя его во время выполнения приложения, то есть, по сути, запускать любой javascript-код. Из-за ограничений, накладываемых компанией Apple, возможности разработчика в этой области сильно ограничены. Однако все же есть некоторые способы защиты: а) Загрузка данных по протоколу HTTPs; б) Загружаемый контент не должен зависеть от информации, вводимой пользователем; в) Проверка содержимого при помощи функции dataWithContentsOfURL, принадлежащей классу NSData.

Домашний Wi-Fi – ваша крепость или картонный домик?

Узнайте, как построить неприступную стену