【问题标题】:How to import self-signed SSL certificate to Volley on Android 4.1+如何在 Android 4.1+ 上将自签名 SSL 证书导入 Volley
【发布时间】:2014-02-25 16:46:33
【问题描述】:

我开发了使用 Volley 的 android 应用程序。 所有通信都是通过 HTTPS 连接完成的。 因为我是在本地环境下测试的,所以我使用Tomcat的自签名证书。

以前,我只有 android 2.33.0 设备。现在我也有了 4.1 和 4.4

我的实现使用这种方法:http://developer.android.com/training/articles/security-ssl.html(部分未知的证书颁发机构) 在 Android 最高 4.1 的设备上,它可以完美运行。带有自定义证书的 SSLSocketFactory 被传递给 Volley:

Volley.newRequestQueue(getApplicationContext(), new HurlStack(null, socketFactory));

但是在 Android 4.1+ 上会发生什么? 为什么它不起作用? 我也尝试过像这样的 NullX509TrustManager

private static class NullX509TrustManager implements X509TrustManager {
    @Override
    public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType)
            throws CertificateException {
    }

    @Override
    public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType)
            throws CertificateException {
    }

    @Override
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return null;
    }
}

但是还是不行……

【问题讨论】:

    标签: android ssl ssl-certificate x509certificate android-volley


    【解决方案1】:

    信任所有 SSL 证书:- 如果您想在测试服务器上进行测试,您可以绕过 SSL。 但不要将此代码用于生产。

    public static class NukeSSLCerts {
    protected static final String TAG = "NukeSSLCerts";
    
    public static void nuke() {
        try {
            TrustManager[] trustAllCerts = new TrustManager[] { 
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() {
                        X509Certificate[] myTrustedAnchors = new X509Certificate[0];  
                        return myTrustedAnchors;
                    }
    
                    @Override
                    public void checkClientTrusted(X509Certificate[] certs, String authType) {}
    
                    @Override
                    public void checkServerTrusted(X509Certificate[] certs, String authType) {}
                }
            };
    
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String arg0, SSLSession arg1) {
                    return true;
                }
            });
        } catch (Exception e) { 
        }
    }
    

    }

    请在 Activity 或您的应用程序类中的 onCreate() 函数中调用此函数。

    NukeSSLCerts.nuke();
    

    这可以用于 Android 中的 Volley。 更多参考。 https://newfivefour.com/android-trust-all-ssl-certificates.html

    【讨论】:

      【解决方案2】:

      我已经用这里提到的解决方案解决了它:

      http://developer.android.com/training/articles/security-ssl.html

      主机名验证的常见问题

      通过添加自定义主机名验证器,它在 Volley 项目中为我的主机名返回 true 并编辑 HurlStack openConnection 方法:

      if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {            
          ((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory);
          ((HttpsURLConnection)connection).setHostnameVerifier(new CustomHostnameVerifier());         
      }
      

      【讨论】:

      • 我不明白
      【解决方案3】:

      如果您已经有一个 .crt 文件并希望将其附加到 Volley,那么可以按照以下 2 个简单步骤进行操作。

      第 1 步:将此方法写入您的代码。

      public SSLSocketFactory getSocketFactory(Context context)
              throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
      
          // Load CAs from an InputStream (could be from a resource or ByteArrayInputStream or ...)
          CertificateFactory cf = CertificateFactory.getInstance("X.509");
      
          InputStream caInput = new BufferedInputStream(context.getResources().openRawResource(R.raw.myFile));
                                                         // I paste my myFile.crt in raw folder under res.
          Certificate ca;
      
          //noinspection TryFinallyCanBeTryWithResources
          try {
              ca = cf.generateCertificate(caInput);
              System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
          } finally {
              caInput.close();
          }
      
          // Create a KeyStore containing our trusted CAs
          String keyStoreType = KeyStore.getDefaultType();
          KeyStore keyStore = KeyStore.getInstance(keyStoreType);
          keyStore.load(null, null);
          keyStore.setCertificateEntry("ca", ca);
      
          // Create a TrustManager that trusts the CAs in our KeyStore
          String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
          TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
          tmf.init(keyStore);
      
          // Create an SSLContext that uses our TrustManager
          SSLContext sslContext = SSLContext.getInstance("TLS");
          sslContext.init(null, tmf.getTrustManagers(), null);
      
          return sslContext.getSocketFactory();
      }
      

      第 2 步:在您使用 Volley 发出任何请求之前,只需在下面添加此行。

      HttpsURLConnection.setDefaultSSLSocketFactory(getSocketFactory(context));
      

      Android Studio 将要求您将该行包含在 try/catch 中,以获取我们方法抛出的所有异常。所以就让它这样做吧。

      编码愉快!

      【讨论】:

        【解决方案4】:

        我找到的最简单的方法是adding this class 并从onCreate 方法执行它

        new NukeSSLCerts().nuke();
        

        相信所有的 SSL 证书会让 volley 得到信任

        【讨论】:

        • 正是“信任所有 SSL 证书会使 volley”,记住这对于生产环境是不安全的。
        • @BhavinPatel 通常我们使用不同的环境来开发应用程序。我们可以有,开发环境,登台,测试,UAT,SIT 环境等等。环境因每个项目而异。但是在开发阶段结束时——包括测试的所有阶段——我们应该上线,这意味着真实的客户和使用,这被称为生产环境。希望这可以帮助。谢谢。
        • @user1510006 明白了。
        • @user1510006 永远欢迎先生。
        猜你喜欢
        • 2017-09-01
        • 1970-01-01
        • 2016-06-30
        • 1970-01-01
        • 2021-09-29
        • 2012-11-01
        • 2013-01-24
        • 2014-04-19
        • 2011-03-16
        相关资源
        最近更新 更多