在Android中隐藏密钥库密码的最佳方法是什么?

4

我对安卓开发和实现SSLSockets还很新,经过一番探索,我能够建立一个简单的服务器/客户端并使其工作起来。然而,我觉得实现可以有所改进,困惑于如何加载keystore密码而不是以明文存在。以下是客户端代码片段,在这里你可以看到我将密码硬编码到本地变量中。有更好的方法来加载keystore密码吗?以便在代码中没有明文呈现?

    char [] KSPASS = "password".toCharArray();
    char [] KEYPASS = "password".toCharArray();
    try {
        final KeyStore keyStore = KeyStore.getInstance("BKS");
        keyStore.load(context.getResources().openRawResource(R.raw.serverkeys), KSPASS);

        final KeyManagerFactory keyManager = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManager.init(keyStore, KEYPASS);

        final TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustFactory.init(keyStore);

        sslContext = SSLContext.getInstance("TLS");
        sslContext.init(keyManager.getKeyManagers(), trustFactory.getTrustManagers(), null);
        Arrays.fill(KSPASS, ' ');
        Arrays.fill(KEYPASS, ' ');

        KSPASS = null;
        KEYPASS = null;

更新:

客户端实际上根本不需要知道密钥库密码。我已经修改了代码,将null作为密码传递。到目前为止,与服务器的通信初始测试已经成功。在服务器端,我仍然加载密钥库密码。

        final KeyStore keyStore = KeyStore.getInstance("BKS");
        keyStore.load(context.getResources().openRawResource(R.raw.serverkeys), null);

        final KeyManagerFactory keyManager = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManager.init(keyStore, null);

        final TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustFactory.init(keyStore);

        sslContext = SSLContext.getInstance("TLS");
        sslContext.init(keyManager.getKeyManagers(), trustFactory.getTrustManagers(), null);
2个回答

8
这并不是一个容易解决的问题。例如,您可以在应用程序启动时从用户那里请求密码,以便密码不会硬编码在代码中。我认为这是最安全的方法。
如果不可能实现上述方式,则如果某人可以访问JAR文件并“看到”代码和随后的密码,则会出现问题。您可以委托给用户保护这些JAR文件。
如果这也不可能,那么您可以加密密码并将其存储在某个地方。然后在您的代码中,硬编码用于解密密码的密钥。因此,查看JAR文件的人无法看到您的真实密码,只能看到解密密钥。当然,如果有人付出了更多的努力,他可以获取密钥并尝试找到密码的位置并解密它以获得密钥,但这需要更多的努力。
最终,这取决于您有哪些安全要求。

Java很容易被反编译和阅读。当你跟踪调用时,你会很快看到那些额外的加密部分。但这是他应该承担的风险,因为未加密的网络流比这更危险。 - lhw
好的,就像提到的那样,如果攻击者付出额外的努力,他最终可以获得密钥。最好的选择是在启动时要求用户输入密码。 - Cratylus
这条评论是为了向提问者提供额外的信息。我应该指出这一点。 - lhw
让我澄清一下。这不是用户会知道的密码。想法是不要在客户端和服务器之间进行明文传输。因此,我使用了命令keytool来创建证书,给它一个密钥库密码,并添加了一个密钥并给它另一个密码。应用程序没有发送敏感数据,但我仍然不希望出现明文。签署Android应用程序是否使反编译更加困难? - mdbox
即使您混淆了代码,程序中的各种常量变量也应该是可见的(否则您的程序将无法运行)。您可以将密码加密并混淆代码。但是,您还必须考虑在哪里/如何存储解密密钥。 - Cratylus
感谢您的帮助。至于客户端,我不应该加载密码。我已经在原始帖子中添加了更新。 - mdbox

1

如果您真正想保护用户的凭据,那么每当您想要访问凭据时,您必须要求他们验证身份。然而,大多数用户会感到烦恼,如果您每次登录都要求他们输入密码,因此作为开发人员,您必须决定您关心安全性还是为用户提供简单易用的界面。

您可以考虑的一个选项是存储密码,但使用用户提供的PIN加密密码。然后,每当用户想要访问其密码时,他们只需提供PIN,您就可以使用它来解密密码。


2
这个 PIN 存储在哪里? - Trupti Nasit

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