Как стать автором
Обновить

Flutter: Все способы защиты данных

Время на прочтение9 мин
Количество просмотров14K

Как обезопасить приложение на Flutter? Все способы обеспечения безопасности данных.

Сложность: Новичок

Вступление

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

Содержание

Раздел 1: Обновление до последних версий

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

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

flutter doctor -v

Команда для обновления Flutter и Dart SDK до последних стабильных версий:

flutter upgrade

Для обновления библиотек и зависимостей вашего проекта воспользуйтесь пакетным менеджером или иным инструментом.

Раздел 2: Обфускация

Обфускация кода — это процесс изменения двоичного кода приложения, чтобы его было труднее понять людям. Обфускация меняет имена функций и классов в вашем скомпилированном коде во что-то бессмысленное для человека, но не для машины, зато людям, пытающимся реконструировать ваш код, будет гораздо труднее. Язык Dart имеет механизмы обфускации и поддерживает их для следующих платформ:

Android / iOS / macOS — поддерживается.
Linux / Windows — не поддерживается.
Web — не поддерживается, но код автоматически минимизируется.

Обфускация кода производится только для релизных версий!

Чтобы включить обфускацию, нужно при создании apk указать следующие параметры:

--obfuscate --split-debug-info=//

Для примера:

flutter build apk --obfuscate --split-debug-info=build/app/outputs/symbols

--obfuscate — отвечает за включение обфускации в вашем приложении.

--split-debug-info=// — это карта символов отладки, когда ваше приложение дает сбой, то консоль разработчика Google Play регистрирует этот сбой, чтобы была возможность проверить и отладить, но поскольку у конечного пользователя версия с включенной обфускацией, то отправляемый отчет будет написан с бессмысленными именами и не будет возможности его отладить. Для этого как раз и нужна карта символов отладки, которая будет использоваться внутри Play Console для преобразования символов отчета о сбое в удобочитаемые имена для появления возможности отладки приложения.

Наличие символов отладки внутри приложения никак не влияет и не помогает взломать ваше приложение людям извне!

Более того, наличие этого параметра может даже снизить финальный размер apk вплоть до 0.5мб.

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

Пример для JavaScript:

// Этот комментарий будет убран после минимизации
var array = [];
for (var i = 0; i < 20; i++) {
  array[i] = i;
}

Тоже самое, но после минимизации:

for(var a=[i=0];i<20;a[i]=i++);

Раздел 3: Экран авторизации

Использовать механизм регистрации-логина просто необходимо для повышения безопасности вашего приложения от нежеланного входа. В зависимости от типа вашего приложения (оффлайн или онлайн), будут различаться используемые способы для реализации авторизации.

Если у вас оффлайн приложение:

  • passcode_screen — пакет для Android и iOS, меню регистрации-логина.

  • Написать свой механизм оффлайновой авторизации.

Если у вас онлайн приложение:

  • google_sign_in — пакет для Android и iOS, вход посредством Google.

  • Используйте Firebase.

  • Используйте свой сервер.

Можно использовать не только пароль, но и биометрическую авторизацию, к примеру, по отпечатку пальца, лицу и т.д., с этим может помочь следующий плагин:

local_auth — для Android и iOS, поддерживает аутентификацию по отпечатку пальца, touch ID, face ID, пин-коду...

Раздел 4: Хэширование

Мы уже поговорили про экран авторизации, и т.к. при любом условии в нем используется какой-либо "пароль", то нам нужно его как-то защищать. Для этих целей я рекомендую ознакомиться с процессом хэширования.

Хэширование — процесс преобразования любого объема информации в уникальный набор символов, который присущ только этому массиву входящей информации. Этот набор символов и будет называться хэшем.

Пример хэширования слова "Brain" с помощью алгоритма SHA-1:

97fb724268c2de1e6432d3816239463a6aaf8450

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

Хэширование можно использовать не только для пароля, но и для любой информации, которую вам не потребуется расшифровывать обратно, а просто сравнивать с некоторым значением для подтверждения.

Чтобы воспользоваться хэшированием, вы можете использовать следующие плагины:

crypto — поддерживаемые алгоритмы: SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256, MD5, HMAC (HMAC-MD5, HMAC-SHA1, HMAC-SHA256).

hash — поддерживаемые алгоритмы: SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, HMAC, MD5.

Пример функции хэширования строки алгоритмом SHA-512 с использованием плагина crypto (язык Dart):

  static String hashSHA512(String text) {
    return sha512.convert(utf8.encode(text)).toString();
  }

Также рекомендую к прочтению обзорную статью на плагин crypto: "Flutter: обзор алгоритмов хэширования на основе плагина crypto".

Раздел 5: Базы данных

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

Локальные (оффлайн) базы данных:

  1. Shared Preferences — обычное хранилище для настроек приложения у платформы Android, также плагин включает в себя стандартное хранилище у iOS. Слабые механизмы защиты данных. Подходит для хранения пар ключ-значения небольших объемов данных.

  2. Flutter Secure Storage — улучшенная версия Shared Preferences, имеет шифрование, но оно по умолчанию выключено. Также подходит для хранения пар ключ-значения небольших объемов данных.

  3. Hive — NoSQL база данных, имеющая встроенный механизм шифрования AES-256.

  4. Isar — NoSQL база данных, улучшенная версия Hive, добавлены новые возможности и увеличена производительность, но не имеет встроенного механизма шифрования.

  5. ObjectBox — NoSQL база данных, основными положительными сторонами этой базы данных является скорость и возможность синхронизации данных между устройствами и серверами, не имеет шифрования.

  6. SQFlite — SQL база данных, аналог SQLite для Flutter, не имеет шифрования.

Таким образом, мы можем взять базу данных со встроенной защитой и использовать её, или же взять без встроенной защиты и самостоятельно шифровать отправляемые и расшифровывать получаемые данные. Также хотел бы обратить внимание на плагин Flutter Secure Storage, он идеально подойдет для дополнительной защиты ключей от основной базы данных, паролей и т.д., которые мы храним локально на устройстве.

Раздел 6: Шифрование

Шифрование — это процесс кодирования информации с целью предотвращения несанкционированного доступа. В случае кражи или утечки зашифрованные данные будут недоступны для прочтения без соответствующего ключа.

Для реализации шифрования во Flutter предлагаю использовать следующий пакет:

encrypt — поддерживает алгоритмы Salsa20, RSA, AES (режимы CBC, CFB-64, CTR, ECB, OFB64, OFB-64/GCTR, SIC).

Пример использования плагина (язык Dart):

import "package:encrypt/encrypt.dart";
import "package:encrypt/encrypt.dart" as encrypt;
import "package:flutter_secure_storage/flutter_secure_storage.dart";

class AES {
  static const storage = FlutterSecureStorage(
      aOptions: AndroidOptions(encryptedSharedPreferences: true));
  static late final key;
  static late final iv;
  static final enc =
      encrypt.Encrypter(encrypt.AES(Key.fromBase64(key), mode: AESMode.cbc));

  static void initAES() async {
    storage.write(key: "password", value: null);
    storage.write(key: "key", value: encrypt.Key.fromSecureRandom(32).base64);
    storage.write(key: "iv", value: encrypt.IV.fromSecureRandom(16).base64);
    key = await storage.read(key: "key");
    iv = await storage.read(key: "iv");
  }

  static void readAES() async {
    key = await storage.read(key: "key");
    iv = await storage.read(key: "iv");
  }

  static encryptAES(text) {
    return enc.encrypt(text, iv: IV.fromBase64(iv)).base64;
  }

  static decryptAES(text) {
    return enc.decrypt(Encrypted.fromBase64(text), iv: IV.fromBase64(iv));
  }
}

В примере выше используется алгоритм AES CBC, а также дополнительная база данных Flutter Secure Storage со своим собственным включенным шифрованием для хранения ключей от основного механизма шифрования. Приписки "base64" и "fromBase64" используются для работы со строками.

Раздел 7: Рут-устройства

Root или суперпользователь — это специальная учётная запись в системе, обладатель которой имеет возможность выполнить абсолютно любые операции в системе.

Плюсы:

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

  • Можно настраивать гаджет как угодно пользователю: увеличивать громкость динамика, проводить системную настройку камеры, редактировать чувствительность микрофона, редактировать файловую систему, сменить системный шрифт, анимации...

  • Возможность тонкой настройки и разгона/замедления работы процессора.

  • Кардинальная очистка встроенной памяти (скрытый кэш) с помощью специальных утилит.

  • Использование всех функций программ, требующих root-права для полноценной работы.

  • Полная блокировка рекламы.

  • Все возможности для взлома приложений.

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

Минусы:

  • Сложности в процессе получения root-прав, однако это в то же время и плюс, так как неопытный пользователь тем самым не сможет легко сломать устройство, что убережёт его от необходимости перепрошивки.

  • Шанс снижения безопасности устройства или поломки его операционной системы.

  • Любые программы, в том числе вирусы, могут получить доступ к root правам и причинить вред устройству.

  • Невозможность устанавливать OTA-обновления системы (обновление по воздуху).

  • Root-права действительны только до следующей перепрошивки или сброса (есть также Temporary Root, действующий до первой перезагрузки).

  • Пользователь лишится технической поддержки и гарантии от производителя устройства.

Т.к. у нас стоит цель — защитить наше приложение, то мы должны отказаться от поддержки рут-устройств. Для этого нам нужно знать, есть ли у устройства пользователя рут-права, в этом нам помогут следующие плагины:

root (только Android).

root_check (только Android).

flutter_jailbreak_detection (Android и iOS).

Если у пользователя все-таки есть расширенные права, то теперь мы можем накладывать на него любые ограничения в нашем приложении или же попросту сразу завершать работу приложения:

SystemNavigator.pop() — только для Android.

exit(0) — для Android и iOS (iOS может начать подозревать ваше приложение, использование нежелательно).

У iOS нет проверенных инструментов для намеренного выхода из приложения, но можно использовать следующий плагин:

minimize_app — для Android и iOS, позволит закидывать рабочее приложение в фоновый режим (минимизировать его).

Раздел 8: Запрет на создание скриншотов, запись видео и скрывать экран свернутого приложения

Бывают такие случаи, когда необходимо отключить пользователю возможность делать скриншот (снимок экрана), записывать экран с вашим приложением или же убрать видимость экрана приложения в свернутом режиме, в целях безопасности от его же глупости или для защиты контента. Чтобы реализовать такие ограничения во Flutter, можно использовать следующий плагин:

flutter_windowmanager — позволяет быстро и оперативно контролировать флаги, используемые вашим приложением, только для Android.

Пример использования плагина (язык Dart):

    static bool isSecureMode = true;

    if (isSecureMode == true) {
      FlutterWindowManager.addFlags(FlutterWindowManager.FLAG_SECURE);
    }
    else {
      FlutterWindowManager.clearFlags(FlutterWindowManager.FLAG_SECURE);
    }

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

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

Android — Java/Kotlin.
iOS — Objective-C/Swift.
Windows — C++.
macOS — Objective-C.
Linux — C.

Раздел 9: Размытие

Для Flutter написан такой специфический плагин как flutter_blurhash, обычно его используют для красивых переходов при загрузке ресурсов из сервера на устройство пользователя, но также его можно использовать и для защиты контента.

bool hideImages = false;

child: hideImages ? BlurHash(hash: "LNG[ySoeIURj9XWBX5WC0Kt6Rjxa") : 
Image.network("https://www.meme-arsenal.com/memes/aeddbdf283906f8794642e6eda5b1327.jpg")

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

Хэш от любой картинки можно получить с помощью этого сайта.

Таким образом получится размытие картинки при переключении переменной наtrue, и обратный процесс наfalse.

Заключение

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

Теги:
Хабы:
Всего голосов 7: ↑4 и ↓3+1
Комментарии5

Публикации

Истории

Работа

Swift разработчик
26 вакансий
iOS разработчик
16 вакансий

Ближайшие события