如何在 android 中安全地保存 Oauth 访问令牌
How to save Oauth Access token securely in android
身份验证后我从服务器获得了访问令牌 "uyhjjfjfgg567f8fhjkkf"
现在我想将其安全地保存在设备中。我查看了 android 开发者网站中的 Keystore 和 Keychain。我不清楚它是如何工作的以及我们应该如何从密钥库中检索令牌。
KeyPairGenerator kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
kpg.initialize(new KeyGenParameterSpec.Builder(
alias,
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setDigests(KeyProperties.DIGEST_SHA256,
KeyProperties.DIGEST_SHA512)
.build());
KeyPair kp = kpg.generateKeyPair();
/*
* Load the Android KeyStore instance using the the
* "AndroidKeyStore" provider to list out what entries are
* currently stored.
*/
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
Enumeration<String> aliases = ks.aliases();
您不需要保存访问令牌,因为它的寿命很短。留在记忆中就足够了。
您确实需要保留刷新令牌,为此您有几个选择:
- 在文件中
- 要么直接在内部存储的文件中
- 或使用
SharedPreferences
- 或在数据库中
- 使用
AccountManager
考虑使用 StoredCredential
. For the flow itself, I recommend you to use Google AppAuth library。
当然,你也可以使用密码对密钥进行加密:
private static byte[] encrypt(byte[] key, byte[] text) throws GeneralSecurityException {
final SecretKeySpec skeySpec = new SecretKeySpec(key, KEY_ALGORITHM);
final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, sInitVectorSpec);
return cipher.doFinal(text);
}
并且密钥可以存储在KeyStore
。
我们使用自定义 SharedPreference 实例,在添加时加密键和值,并在请求时解密。
SecurePreferences preferences = ...
preferences.edit().putString( "key", "value" ).apply(); // key and value are encrypted automatically
String value = preferences.getString( "key", null ); // key and value are decrypted automatically
我只建议在值被加密时使用 SharedPreferences,因为即使 xml 文件仅对应用程序可用,它也可以在获得 root 权限的设备上访问。
如果您已经在使用 SqlLiteDB,我可能会使用它。不然的话,只存一个token就有点重了。
编辑:
oauth 令牌与用于签署应用程序的密钥和密钥库完全无关。
oauth 令牌是服务器在验证用户凭据后在应用程序内提供的令牌。
密钥库包含 1 个或多个用于对应用程序进行数字签名的证书。这是为了防止其他人上传与您的包名相同的应用程序并替换它。
身份验证后我从服务器获得了访问令牌 "uyhjjfjfgg567f8fhjkkf"
现在我想将其安全地保存在设备中。我查看了 android 开发者网站中的 Keystore 和 Keychain。我不清楚它是如何工作的以及我们应该如何从密钥库中检索令牌。
KeyPairGenerator kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
kpg.initialize(new KeyGenParameterSpec.Builder(
alias,
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setDigests(KeyProperties.DIGEST_SHA256,
KeyProperties.DIGEST_SHA512)
.build());
KeyPair kp = kpg.generateKeyPair();
/*
* Load the Android KeyStore instance using the the
* "AndroidKeyStore" provider to list out what entries are
* currently stored.
*/
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
Enumeration<String> aliases = ks.aliases();
您不需要保存访问令牌,因为它的寿命很短。留在记忆中就足够了。
您确实需要保留刷新令牌,为此您有几个选择:
- 在文件中
- 要么直接在内部存储的文件中
- 或使用
SharedPreferences
- 或在数据库中
- 使用
AccountManager
考虑使用 StoredCredential
. For the flow itself, I recommend you to use Google AppAuth library。
当然,你也可以使用密码对密钥进行加密:
private static byte[] encrypt(byte[] key, byte[] text) throws GeneralSecurityException {
final SecretKeySpec skeySpec = new SecretKeySpec(key, KEY_ALGORITHM);
final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, sInitVectorSpec);
return cipher.doFinal(text);
}
并且密钥可以存储在KeyStore
。
我们使用自定义 SharedPreference 实例,在添加时加密键和值,并在请求时解密。
SecurePreferences preferences = ...
preferences.edit().putString( "key", "value" ).apply(); // key and value are encrypted automatically
String value = preferences.getString( "key", null ); // key and value are decrypted automatically
我只建议在值被加密时使用 SharedPreferences,因为即使 xml 文件仅对应用程序可用,它也可以在获得 root 权限的设备上访问。
如果您已经在使用 SqlLiteDB,我可能会使用它。不然的话,只存一个token就有点重了。
编辑:
oauth 令牌与用于签署应用程序的密钥和密钥库完全无关。
oauth 令牌是服务器在验证用户凭据后在应用程序内提供的令牌。
密钥库包含 1 个或多个用于对应用程序进行数字签名的证书。这是为了防止其他人上传与您的包名相同的应用程序并替换它。