Как безопасно хранить токен доступа и секрет в Android?

124

Я собираюсь использовать oAuth для получения писем и контактов из Google. Я не хочу каждый раз просить пользователя войти в систему, чтобы получить токен доступа и секрет. Насколько я понял, мне нужно хранить их вместе с моим приложением либо в базе данных, либо SharedPreferences. Но меня немного беспокоят аспекты безопасности. Я читал, что вы можете шифровать и расшифровывать токены, но злоумышленнику легко просто декомпилировать ваш apk и классы и получить ключ шифрования.
Как лучше всего безопасно хранить эти токены в Android?

Да, чувак
источник
1
Как сохранить ключ и секрет потребителя (их жесткое сохранение не защищено)? мне нужно, чтобы они запросили accesstoken и secret .. как это делают другие существующие приложения, использующие oauth? хм, наконец, с oauth, вам нужно позаботиться о гораздо большем количестве проблем безопасности для меня .... мне нужно надежно хранить токен / секрет потребителя, а также accesstoken и секрет ... наконец, не было бы проще просто сохранить имя пользователя / пароль пользователя в зашифрованном виде? ... в конце концов, не лучше ли последнее? Я до сих пор не могу понять, насколько лучше
oauth
подскажите .. в каком файле хранится токен доступа ?? Я новичок в Android и пробовал запустить пример приложения Plus, но нигде не нашел [метод GoogleAuthUtil.getToken ().]
Абхишек Кошик

Ответы:

116

Сохраните их как общие настройки . По умолчанию они являются частными, и другие приложения не могут получить к ним доступ. На устройствах с root-доступом, если пользователь явно разрешает доступ к какому-либо приложению, которое пытается их прочитать, приложение может использовать их, но вы не можете защитить от этого. Что касается шифрования, вы должны либо требовать от пользователя вводить парольную фразу для дешифрования каждый раз (таким образом нарушая цель кэширования учетных данных), либо сохранять ключ в файл, и вы получите ту же проблему.

Хранение токенов вместо фактического пароля пользователя дает несколько преимуществ:

  • Сторонним приложениям не нужно знать пароль, и пользователь может быть уверен, что они отправят его только на исходный сайт (Facebook, Twitter, Gmail и т. Д.)
  • Даже если кто-то украдет токен, он не увидит пароль (который пользователь может использовать и на других сайтах).
  • Токены обычно имеют время жизни и истекают через определенное время.
  • Токены могут быть отозваны, если вы подозреваете, что они были скомпрометированы
Николай Еленков
источник
1
спасибо за ответ! но как я могу узнать, скомпрометирован ли мой потребительский ключ? lol, будет сложно сказать ... хорошо, о хранении токена доступа и секрета, хорошо, я сохраняю их в общих настройках и зашифровываю их, но как насчет ключа и секрета потребителя? Я не могу хранить их в общих предпочтениях (мне нужно было бы явно написать ключ и секрет потребителя в коде, чтобы сохранить его в общих предпочтениях) .. не знаю, понимаете ли вы, о чем я.
yeahman
2
Вы должны либо поместить в приложение (несколько) запутанный способ, чтобы они не были сразу видны после декомпиляции, либо использовать собственное веб-приложение прокси авторизации, которое имеет ключ и секрет. Поместить их в приложение, очевидно, проще, и если вы думаете, что риск того, что кто-то попытается взломать ваше приложение, достаточно низок, используйте этот подход. Кстати, указанные выше пункты относятся к паролю пользователя. Если вы обнаружите, что ваш ключ / секрет потребителя был скомпрометирован, вы также можете отозвать их (хотя это, конечно, сломает ваше приложение).
Николай Еленков
1
@NikolayElenkov: Вы написали: «Что касается шифрования, вы должны либо требовать от пользователя вводить кодовую фразу для дешифрования каждый раз (таким образом, уничтожая цель кеширования учетных данных), либо сохранять ключ в файл, и вы получите ту же проблему». , Что, если взломщики перевернут ваше приложение, чтобы понять, как работает шифрование? Ваша защита может быть сломана. Рекомендуется ли хранить такую ​​информацию (токен, шифрование ...) с использованием собственного кода?
anhldbk
1
Если данные приложения очищаются, токен обновления теряется, что, вероятно, не то, что хотел пользователь.
rds
2
В наши дни это уже не лучший способ хранить токены!
Рахул Растоги
20

Вы можете сохранить их в AccountManager . По мнению этих парней, это считается лучшей практикой.

введите описание изображения здесь

Вот официальное определение:

Этот класс обеспечивает доступ к централизованному реестру онлайн-учетных записей пользователя. Пользователь вводит учетные данные (имя пользователя и пароль) один раз для каждой учетной записи, предоставляя приложениям доступ к онлайн-ресурсам с утверждением «одним щелчком».

Подробное руководство по использованию AccountManager:

Однако в конечном итоге AccountManager сохраняет ваш токен только в виде простого текста. Поэтому я бы посоветовал зашифровать ваши секреты, прежде чем сохранять их в AccountManager. Вы можете использовать различные библиотеки шифрования, такие как AESCrypt или AESCrypto.

Другой вариант - использовать библиотеку Conceal . Это достаточно безопасно для Facebook и намного проще в использовании, чем AccountManager. Вот фрагмент кода для сохранения секретного файла с помощью Conceal.

byte[] cipherText = crypto.encrypt(plainText);
byte[] plainText = crypto.decrypt(cipherText);
aldok
источник
2
Хороший совет, что вобще. Выглядит очень просто в использовании. И для многих случаев использования.
Лагос
Не удалось найти Conceal по ссылке. Может быть деактивирован
user1114
12

SharedPreferences не является безопасным местом. На устройстве с рутированным доступом мы легко можем читать и изменять файлы SharedPrefereces xml всех приложений. Таким образом, токены должны истекать относительно часто. Но даже если токен истекает каждый час, новые токены все равно можно украсть из SharedPreferences. Android KeyStore следует использовать для длительного хранения и извлечения криптографических ключей, которые будут использоваться для шифрования наших токенов, чтобы хранить их, например, в SharedPreferences или в базе данных. Ключи не хранятся в процессе приложения, поэтому их сложнее взломать.

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

apex39
источник
10
Тогда где их хранить?
Милинд Мевада
@MilindMevada с помощью диспетчера учетных записей Android (с ручным шифрованием, поскольку диспетчер учетных записей хранит только простой текст) или хранилища ключей Android
Эзра Лазуарди
1
  1. На панели «Проект» Android Studio выберите «Файлы проекта» и создайте новый файл с именем «keystore.properties» в корневом каталоге проекта.

введите описание изображения здесь

  1. Откройте файл «keystore.properties» и сохраните в нем свой токен доступа и секрет.

введите описание изображения здесь

  1. Теперь загрузите прочитанные токен доступа и секрет в файл build.gradle вашего модуля приложения . Затем вам нужно определить переменную BuildConfig для вашего токена доступа и секрета, чтобы вы могли напрямую обращаться к ним из своего кода. Ваш build.gradle может выглядеть следующим образом:

    ... ... ... 
    
    android {
        compileSdkVersion 26
    
        // Load values from keystore.properties file
        def keystorePropertiesFile = rootProject.file("keystore.properties")
        def keystoreProperties = new Properties()
        keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
    
        defaultConfig {
            applicationId "com.yourdomain.appname"
            minSdkVersion 16
            targetSdkVersion 26
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    
            // Create BuildConfig variables
            buildConfigField "String", "ACCESS_TOKEN", keystoreProperties["ACCESS_TOKEN"]
            buildConfigField "String", "SECRET", keystoreProperties["SECRET"]
        }
    }
  2. Вы можете использовать свой токен доступа и секрет в своем коде следующим образом:

    String accessToken = BuildConfig.ACCESS_TOKEN;
    String secret = BuildConfig.SECRET;

Таким образом, вам не нужно хранить токен доступа и секрет в виде обычного текста внутри вашего проекта. Таким образом, даже если кто-то декомпилирует ваш APK, он никогда не получит ваш токен доступа и секрет, поскольку вы загружаете их из внешнего файла.

Захидур Рахман Фейсал
источник
1
Похоже, нет никакой разницы, что создание файла свойств вместо жесткого кодирования.
Dzshean
Я хочу написать токен во время выполнения, возможно, мой токен меняется каждый раз, когда я открываю свое приложение.
Рехан Сарвар
1
Это очень хороший способ хранить некоторые токены, например токены доступа к API. если вы хотите сохранить учетные данные пользователя, NDK - лучший способ.
Эрик
8
Это совершенно не то, как вы должны хранить конфиденциальную информацию в своем приложении! Даже если репозиторий не содержит данных с использованием этого подхода (данные вводятся в процесс сборки), он генерирует файл BuildConfig, содержащий токен / секрет в виде обычного текста, чтобы все могли видеть его после простой декомпиляции.
Hrafn
Я согласен с @Hrafn. Такое решение можно легко реконструировать (путем декомпиляции apk и т. Д.). И другая проблема заключается в каком-то протоколе, таком как OAuth2.0, токен доступа является временным. Это означает, что вам нужно запросить новый токен доступа, когда срок действия текущего токена доступа истек.
Эзра Лазуарди
-3

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

  1. Используйте сохраните свой токен доступа в хранилище ключей Android, которое не будет обратным.
  2. Используйте функцию NDK с некоторыми вычислениями, которые сохраняют ваш токен и NDK с кодом C ++, который очень трудно отменить
M.Noman
источник