web-dev-qa-db-ja.com

Androidにアクセストークンとシークレットを安全に保存する方法は?

oAuthを使用して、Googleからメールと連絡先を取得します。毎回ログインしてアクセストークンとシークレットを取得することをユーザーに要求したくありません。アプリケーションにデータベースまたはSharedPreferencesのいずれかで保存する必要がありますが、セキュリティの面で少し心配です。トークンを暗号化および復号化できることを読んでいますが、攻撃者にとっては簡単ですAPKとクラスを逆コンパイルして、暗号化キーを取得するだけです。
Androidにこれらのトークンを安全に保存する最良の方法は何ですか?

105
yeahman

それらを共有設定として保存します。これらはデフォルトでプライベートであり、他のアプリはそれらにアクセスできません。ルート化されたデバイスでは、ユーザーがそれらを読み取ろうとしているアプリへのアクセスを明示的に許可した場合、アプリはそれらを使用できる可能性がありますが、それに対して保護することはできません。暗号化に関しては、ユーザーに毎回復号化パスフレーズを入力するように要求する必要があります(したがって、資格情報をキャッシュする目的を無効にします)。

実際のユーザー名パスワードの代わりにトークンを保存することには、いくつかの利点があります。

  • サードパーティのアプリはパスワードを知る必要がなく、ユーザーは元のサイト(Facebook、Twitter、Gmailなど)にのみパスワードを送信することを確認できます。
  • 誰かがトークンを盗んだとしても、パスワードを見ることができません(ユーザーが他のサイトでも使用している可能性があります)
  • トークンには一般に有効期間があり、一定の時間が経過すると有効期限が切れます
  • トークンが侵害された疑いがある場合、トークンを取り消すことができます
105
Nikolay Elenkov

AccountManager に保存できます。これらの人々によると、ベストプラクティスと見なされています。

enter image description here

公式の定義は次のとおりです。

このクラスは、ユーザーのオンラインアカウントの一元化されたレジストリへのアクセスを提供します。ユーザーはアカウントごとに資格情報(ユーザー名とパスワード)を1回入力し、「ワンクリック」承認でアプリケーションにオンラインリソースへのアクセスを許可します。

AccountManagerの使用方法に関する詳細なガイド:

ただし、最後にAccountManagerはトークンをプレーンテキストとしてのみ保存します。そのため、AccountManagerに保存する前に秘密を暗号化することをお勧めします。 AESCrypt または AESCrypto のようなさまざまな暗号化ライブラリを利用できます

別のオプションは Conceal library を使用することです。 Facebookにとって十分に安全であり、AccountManagerよりもはるかに使いやすいです。 Concealを使用してシークレットファイルを保存するコードスニペットを次に示します。

byte[] cipherText = crypto.encrypt(plainText);
byte[] plainText = crypto.decrypt(cipherText);
15
aldok
  1. Android Studioのプロジェクトペインから、[プロジェクトファイル]を選択し、プロジェクトのルートディレクトリに "keystore.properties"という名前の新しいファイルを作成します。

enter image description here

  1. 「keystore.properties」ファイルを開き、ファイルにアクセストークンとシークレットを保存します。

enter image description here

  1. ここで、appモジュールの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を逆コンパイルしても、あなたが外部ファイルからそれらをロードしているとき、彼らはあなたのアクセストークンとシークレットを決して取得しません。

SharedPreferences ではない 安全な場所そのもの。ルート化されたデバイスでは、すべてのアプリケーションのSharedPrefereces xmlを簡単に読み取り、変更できます。したがって、トークンは比較的頻繁に期限切れになるはずです。ただし、トークンが1時間ごとに期限切れになっても、新しいトークンはSharedPreferencesから盗まれます。 Android KeyStoreは、トークンを暗号化してSharedPreferencesやデータベースに保存するために使用される暗号化キーの長期保存と取得に使用する必要があります。キーは、アプリケーションのプロセスなので、それらは より難しく 侵害されます。

場所よりも関連性が高いのは、それ自体が安全である方法です。暗号で署名された短命JWTを使用し、Android KeyStoreを使用して暗号化し、安全なプロトコルで送信する

5
apex39

2つのオプションに従うことで、アクセストークンを保護できます。

  1. アクセストークンをAndroidリバースしないキーストアに保存します。
  2. トークンとNDKを保存する計算でNDK関数を使用し、逆変換が非常に困難なC++コードを使用する
1
M.Noman