oAuthを使用してGoogleからメールと連絡先を取得します。アクセストークンとシークレットを取得するためにログインするたびにユーザーに依頼したくありません。私が理解したことから、データベースまたはのいずれかにアプリケーションとともにそれらを保存する必要がありますSharedPreferences
。しかし、私はそれに関するセキュリティの側面について少し心配しています。トークンを暗号化および復号化できることを読みましたが、攻撃者がapkとクラスを逆コンパイルして暗号化キーを取得するのは簡単です。
これらのトークンをAndroidに安全に保存するための最良の方法は何ですか?
4 に答える
それらを共有設定として保存します。これらはデフォルトでプライベートであり、他のアプリはそれらにアクセスできません。ルート権限を取得されたデバイスでは、ユーザーがそれらを読み取ろうとしているアプリへのアクセスを明示的に許可している場合、アプリはそれらを使用できる可能性がありますが、それを防ぐことはできません。暗号化に関しては、ユーザーに毎回復号化パスフレーズを入力するように要求するか(したがって、資格情報をキャッシュする目的を無効にする)、キーをファイルに保存する必要があり、同じ問題が発生します。
実際のユーザー名パスワードの代わりにトークンを保存することには、いくつかの利点があります。
- サードパーティのアプリはパスワードを知る必要はなく、ユーザーはパスワードを元のサイト(Facebook、Twitter、Gmailなど)にのみ送信することを確認できます。
- 誰かがトークンを盗んだとしても、パスワードは表示されません(ユーザーが他のサイトでも使用している可能性があります)
- トークンには通常、有効期間があり、一定の時間が経過すると期限切れになります
- トークンが侵害された疑いがある場合は、トークンを取り消すことができます
それらはAccountManagerに保存できます。これらの人によると、それはベストプラクティスと考えられています。
公式の定義は次のとおりです。
このクラスは、ユーザーのオンラインアカウントの一元化されたレジストリへのアクセスを提供します。ユーザーはアカウントごとに1回クレデンシャル(ユーザー名とパスワード)を入力し、「ワンクリック」承認でアプリケーションにオンラインリソースへのアクセスを許可します。
AccountManagerの使用方法の詳細なガイドについては、以下を参照してください。
ただし、最終的に、AccountManagerはトークンをプレーンテキストとしてのみ保存します。したがって、AccountManagerに保存する前に、シークレットを暗号化することをお勧めします。AESCryptやAESCryptoなどのさまざまな暗号化ライブラリを利用できます
別のオプションは、ライブラリを隠すことです。Facebookにとっては十分に安全であり、AccountManagerよりもはるかに使いやすいです。これは、Concealを使用してシークレットファイルを保存するためのコードスニペットです。
byte[] cipherText = crypto.encrypt(plainText);
byte[] plainText = crypto.decrypt(cipherText);
SharedPreferences自体は安全な場所ではありません。ルート権限を取得されたデバイスでは、すべてのアプリケーションのSharedPreferecesxmlを簡単に読み取って変更できます。したがって、トークンは比較的頻繁に期限切れになるはずです。ただし、トークンが1時間ごとに期限切れになった場合でも、SharedPreferencesから新しいトークンが盗まれる可能性があります。Android KeyStoreは、トークンをSharedPreferencesやデータベースなどに保存するためにトークンを暗号化するために使用される暗号化キーの長期保存と取得に使用する必要があります。キーはアプリケーションのプロセス内に保存されないため、侵害される可能性は低くなります。
場所よりも関連性が高いのは、暗号化された短命のJWTを使用し、Android KeyStoreを使用して暗号化し、安全なプロトコルで送信するなど、それ自体を安全にする方法です。
- Android Studioの[プロジェクト]ペインで、[プロジェクトファイル]を選択し、プロジェクトのルートディレクトリに「keystore.properties」という名前の新しいファイルを作成します。
- 「keystore.properties」ファイルを開き、アクセストークンとシークレットをファイルに保存します。
次に、読み取りアクセストークンとシークレットをアプリモジュールの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"] } }
次のように、コードでアクセストークンとシークレットを使用できます。
String accessToken = BuildConfig.ACCESS_TOKEN; String secret = BuildConfig.SECRET;
このように、プロジェクト内にアクセストークンとシークレットをプレーンテキストで保存する必要はありません。したがって、誰かがAPKを逆コンパイルしても、外部ファイルからロードしているため、アクセストークンとシークレットを取得することはありません。