【问题标题】:If I use SSLSocket in Android and hard code the passcode to the truststore in the source code is that insecure?如果我在 Android 中使用 SSLSocket 并硬编码源代码中信任库的密码是不安全的吗?
【发布时间】:2013-08-06 18:21:29
【问题描述】:

我正在使用 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);

【问题讨论】:

  • 当您说“不安全”时,您是担心有人解密和读取您的网络通信,还是担心其他程序(或个人)冒充您的应用?

标签: java android ssl encryption


【解决方案1】:

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

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

来自Keystore.load(InputStream, char[]) documentation

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

您可以使用null 作为密码(在这种情况下,您将始终能够加载证书),或者您使用具有实际密码的非空char 数组(在这种情况下,错误的密码会失败,出现类似“java.io.IOException: Keystore was tampered with or password is wrong”)。

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


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

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


编辑(根据您的评论):

我担心有人重新编译应用程序,检索 密码和信任库,并使用它连接到我的服务器。 如果有可能,那么它有点违背了 TLS 的目的 第一名。

从这条评论中,您无法清楚了解信任库的用途(例如,请参阅this question)。

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

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

【讨论】:

    【解决方案2】:

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

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

    解决方案:

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

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

    【讨论】:

      猜你喜欢
      • 2018-10-25
      • 2013-10-16
      • 2011-10-12
      • 2011-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-12
      • 1970-01-01
      相关资源
      最近更新 更多