4

我正在使用 java 的 SSLSocket 将 android 应用程序安全地连接到服务器。证书位于信任库中。但是连接似乎需要信任库的密码,因此它目前被硬编码到设备中。我对 PKI 了解不多,但这似乎并不安全。我将信任库与原始资源文件夹中的应用程序捆绑在一起。是否有更好的方法来安全地允许应用程序使用 TLS 连接到服务器?我对 TLS/SSL 非常陌生,因此我将不胜感激任何帮助或建议。

这是代码的客户端。

        store = KeyStore.getInstance("BKS"); 
        InputStream in = appcontext.getResources().openRawResource(R.raw.truststore);
        store.load(in, "PASSWORD".toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        tmf.init(store);
        sslcontext = SSLContext.getInstance("TLS");
        sslcontext.init(null, tmf.getTrustManagers(), new SecureRandom());

        SSLSocketFactory sslsocketfactory = sslcontext.getSocketFactory();

        // connect to socket
        SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(
                "192.168.1.16", 9999);
4

2 回答 2

5

我还没有在 Android 上尝试过,但这是它在纯 Java 中的工作方式。

您在这里使用您的密钥库作为信任库,因此(希望)它不包含任何私钥或秘密材料。在这种情况下,密码的目的是验证商店的完整性。

Keystore.load(InputStream, char[])文档中:

可以给出密码来解锁密钥库(例如,密钥库驻留在硬件令牌设备上),或检查密钥库数据的完整性。如果没有为完整性检查提供密码,则不执行完整性检查。

要么null用作密码(在这种情况下,您将始终能够加载证书),要么使用char具有实际密码的非空数组(在这种情况下,不正确的密码将失败,例如“ java.io. IOException:密钥库被篡改,或密码不正确“)。

在这里使用密码是为了提高安全性(防止信任库被篡改)。话虽如此,如果您将此信任库和此应用程序捆绑在一起,那么能够替换信任库的攻击者很可能也可以访问密码(通过反编译)。(我对 Android 应用程序分发不太熟悉,但如果应用程序已签名,那么篡改您的信任库等原始资源也可能会使签名无效,因此这可能是一种更现实的保护方式。否则,我想您可以要求用户每次都输入信任库的密码,但这似乎不切实际。)


这不是您问题的一部分,但为了保护 SSL/TLS 连接,您还需要验证服务器发送的证书对于您尝试访问的主机名是否有效,在SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("192.168.1.16", 9999);.

最近在 Java的这个问题中讨论了这一点。(不幸的是,您将无法在 Android 上使用新的 Java 7 API 自动为您执行此操作,因此您必须更手动地检查证书。您可能也对这个最近的问题感兴趣。)


编辑(根据您的评论):

我担心有人重新编译应用程序、检索密码和信任库并使用它连接到我的服务器。如果有可能,那么它首先会破坏 TLS 的目的。

从这条评论中不清楚您是否了解信任库的目的(例如,请参阅这个问题)。

客户端应用程序中的信任库的目的不是向服务器验证您的应用程序,而是确保您的客户端可以验证它连接到的服务器的身份,这样它就不会被欺骗连接到中间人攻击者。这与您的服务器如何信任您的应用程序/客户端/用户无关,而是关于您的应用程序如何信任您的服务器。

向服务器验证应用程序用户将是密钥库的目的。这对于验证用户来说很好(但如果每个用户都有不同的证书会更有意义)。确保连接只能来自您的应用程序是另一个更困难的问题(如果您无法始终完全控制客户端硬件,则会导致失败)。在您的应用程序中使用通用客户端证书可以为您节省一些时间,但任何掌握了客户端代码的人最终都可以对其进行逆向工程。我不会花太多时间在上面。您可能对这些问题感兴趣:

于 2013-08-05T22:53:38.090 回答
0

问题: 任何获得 apk 文件的人都可以读取源代码中包含的任何内容。因此,如果您在源代码(或您的资源文件)中包含您的密码和信任库,任何拥有该 apk 的人都可以读取它。

事实上,无法保证连接到你服务器的应用程序是你自己的应用程序。想象一个经过修改的 Dalvik VM,它会等到您的应用程序运行完毕SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("192.168.1.16", 9999);,然后传递sslsocket给另一个应用程序。

解决方案:

  1. 将您的可信代码移至服务器。例如,如果您的应用程序中有一个名为addNewProductDirectlyToDatabaseOnServer的方法,请将其替换为一个名为 的方法addNewProductToServer,并让它为您的服务器调用一个 REST API,这会添加一个新用户,而不会让恶意应用程序直接控制您的数据库。
  2. 使用密码对个人用户进行身份验证。这不是绝对必要的,但它有助于确保正确的人正在访问您的服务器,并且如果一个坏人得到了某人的密码(或者如果某人变成了一个坏人),您可以通过禁用他们的密码来撤销他们对服务器的访问/登录。

如果您有兴趣了解有关攻击者如何将您的源代码从您的 apk 文件中提取出来的更多信息,我建议您查看以下工具:

于 2013-08-06T22:03:35.310 回答