共享首选项安全性

5
我正在开发一个Android模块,需要使用共享首选项存储JWT令牌以进行自动登录和其他一些操作。我使用类似“token”之类的键来存储它。
问题是:
如果开发人员导入我的模块并找到键,他可以轻松读取我的JWT令牌,这对我来说不太好。
你能提供一些替代方案吗?
编辑:我的最低API级别必须为14。

1
我从未尝试过,但昨天刚好搜索到了这个,看看吧 https://github.com/sveinungkb/encrypted-userprefs - Antonios Tsimourtos
偏好设置存储的目录是受保护的。只要设备没有被root,你就没问题。 - Mister Smith
@MisterSmith,是的,我知道。但是如果使用我的模块的开发者知道jwt的密钥,他可以轻松地从他的应用程序中读取它。 - Robert Banyai
3个回答

1

你的第一个想法听起来很有趣! - Robert Banyai

0

在保存到共享首选项之前,您可以加密令牌,需要使用时可以解密并使用。

我建议您在保存到共享首选项时使用不可预测的密钥,而不是"token"

这里有一个加密类,可以在Android应用程序中用于加密和解密数据。

public final class Encryption {
    private static final String CHIPHER_TRANSFORMATION = "AES/ECB/PKCS5Padding";
    private static final String GENERATE_KEY__ALGORITHM = "PBKDF2WithHmacSHA1";
    private static final String GENERATE_KEY_ALGORITHM = "AES";
    public static final int CRYPTO_TYPE_ENCRYPT = 0;
    public static final int CRYPTO_TYPE_DECRYPT = 1;

    public static String crypto(String inString, int type, String hashKey, String salt, String charset) {
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance(CHIPHER_TRANSFORMATION);
            byte[] inputByte = inString.getBytes(charset);
            switch (type) {
                case CRYPTO_TYPE_DECRYPT:
                    cipher.init(Cipher.DECRYPT_MODE, initKey(hashKey, salt));
                    return new String(cipher.doFinal(Base64.decode(inputByte, Base64.DEFAULT)));
                case CRYPTO_TYPE_ENCRYPT:
                    cipher.init(Cipher.ENCRYPT_MODE, initKey(hashKey, salt));
                    return new String(Base64.encode(cipher.doFinal(inputByte), Base64.DEFAULT));
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }

        return null;
    }

    private static SecretKey getSecretKey(char[] password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
        SecretKeyFactory factory = SecretKeyFactory.getInstance(GENERATE_KEY__ALGORITHM);
        KeySpec spec = new PBEKeySpec(password, salt, 1024, 128);
        SecretKey tmp = factory.generateSecret(spec);
        return (new SecretKeySpec(tmp.getEncoded(), GENERATE_KEY_ALGORITHM));
    }

    private static SecretKey initKey(String hashKey, String salt) {
        try {
            return getSecretKey(hashKey.toCharArray(), salt.getBytes());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return null;
    }
}

正如我之前所说,如果我使用AES,我必须在某个地方存储我的密码或密钥,因此问题将被迭代。 - Robert Banyai
Java代码可以很容易地被反编译。因此,这只能防止非经验丰富的攻击者的攻击。 - Robert
是的,你说得对,但我认为在安卓中没有一种百分之百安全的方式来处理共享首选项。 - savepopulation

-1

Android Keystore 系统允许您将私钥存储在容器中,使其更难从设备中提取。一旦密钥位于密钥库中,它们可以用于使用私钥材料进行加密操作而保持不可导出。(注:一个问题,它是在API级别18中引入的)

使用 Android Keystore 系统的 Android 安全共享首选项
https://github.com/ophio/secure-preferences

请参阅本文,了解详细信息:
https://medium.com/@vashisthg/android-secure-shared-preferences-10f8356a4c2b#.8nf88g4g0

另一个解决方案[API级别8]: Android 对模糊的共享首选项

[ObscuredSharedPreferences.java] https://github.com/RightHandedMonkey/WorxForUs_Library/blob/master/src/com/worxforus/android/ObscuredSharedPreferences.java

希望这能对你有所帮助!


我编辑了我的问题,我必须使用API 14。谢谢你的回答。 - Robert Banyai
1
Android Keystore 在应用程序级别上工作。由于我们正在讨论第三方应用程序中的模块,因此该应用程序可以访问模块可以访问的所有密钥。因此,在这种情况下它将无济于事。 - Robert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接