2013-06-11 107 views
43

我想使用這個代碼,以使一個HTTPS請求,HTTPS請求:製作採用Android凌空

RequestQueue queue = Volley.newRequestQueue(getApplicationContext()); 
request = new Request<String>(Request.Method.GET,"https://devblahblahblah.com/service/etc",errListener); 

,但我收到此錯誤:

com.android.volley.NoConnectionError: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

有兩點要注意:

  1. HTTPS證書有效。在瀏覽器中輕鬆打開,不會有任何警告。
  2. 上述代碼適用於HTTP鏈接。

我實際上需要知道在Android Volley框架中是否有任何開關/選項,我可以使用該開關/選項成功打開HTTPS URL?

+1

我的猜測是,你需要配置這一點,你會如果直接使用'HttpUrlConnection'以同樣的方式。見http://commonsware.com/blog/2013/03/04/ssl-android-basics.html和http://nelenkov.blogspot.ie/2011/12/using-custom-certificate-trust-store-on html的 – CommonsWare

+4

我發現一個叫做'HurlStack'類延伸'HttpStack'這是一個可選的參數去'Volley.newRequestQueue'。的構造函數'HurlStack'接受類型SSLSocketFactory'的'的參數,它用它的Javadoc:「SSL工廠使用HTTPS連接」,但還沒有嘗試過呢。 –

回答

14

也許這個鏈接將有助於您:Using Android Volley With Self-Signed SSL Certificate

+1

請檢查進口是否正確。可能您將內置的HttpClient類與演示中的類混合在一起。 – Ognyan

+0

對不起,我沒有期待這麼快的回覆,你說的是正確的問題。感謝您製作如此龐大的圖書館。 – SteveGSD

+0

鏈接可能被破壞了...請問您可以檢查嗎? @Ogre_BGR – rafid059

47

也許下面這些代碼將有助於你:

1.創建一個HttpsTrustManager類,它實現X509TrustManager

public class HttpsTrustManager implements X509TrustManager { 

    private static TrustManager[] trustManagers; 
    private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{}; 

    @Override 
    public void checkClientTrusted(
      java.security.cert.X509Certificate[] x509Certificates, String s) 
      throws java.security.cert.CertificateException { 

    } 

    @Override 
    public void checkServerTrusted(
      java.security.cert.X509Certificate[] x509Certificates, String s) 
      throws java.security.cert.CertificateException { 

    } 

    public boolean isClientTrusted(X509Certificate[] chain) { 
     return true; 
    } 

    public boolean isServerTrusted(X509Certificate[] chain) { 
     return true; 
    } 

    @Override 
    public X509Certificate[] getAcceptedIssuers() { 
     return _AcceptedIssuers; 
    } 

    public static void allowAllSSL() { 
     HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { 

      @Override 
      public boolean verify(String arg0, SSLSession arg1) { 
       return true; 
      } 

     }); 

     SSLContext context = null; 
     if (trustManagers == null) { 
      trustManagers = new TrustManager[]{new HttpsTrustManager()}; 
     } 

     try { 
      context = SSLContext.getInstance("TLS"); 
      context.init(null, trustManagers, new SecureRandom()); 
     } catch (NoSuchAlgorithmException e) { 
      e.printStackTrace(); 
     } catch (KeyManagementException e) { 
      e.printStackTrace(); 
     } 

     HttpsURLConnection.setDefaultSSLSocketFactory(context 
       .getSocketFactory()); 
    } 

} 

2.增加HttpsTrustManager.allowAllSSL()你犯了一個HTTPS請求之前:

HttpsTrustManager.allowAllSSL(); 
String tag_string_req = "string_req"; 
StringRequest strReq = new StringRequest(Request.Method.POST, 
     your_https_url, new Response.Listener<String>() { 
    @Override 
    public void onResponse(String response) { 
     Log.d(TAG, "response :"+response); 
    } 
}, new Response.ErrorListener() { 
    @Override 
    public void onErrorResponse(VolleyError error) { 
     VolleyLog.d(TAG, "Error: " + error.getMessage()); 
    } 
}){ 
    @Override 
    protected Map<String, String> getParams() { 
     Map<String, String> params = new HashMap<String, String>(); 
     params.put("username", "max"); 
     params.put("password", "123456"); 
     return params; 
    } 
}; 
AppController.getInstance().addToRequestQueue(strReq, tag_string_req); 
+15

這是一切都很好,除非你沒有實際驗證服務器證書。除非您想讓用戶知道各種SSL攻擊,否則請務必不要在生產環境中進行部署。 – asgs

+3

這不適用於生產。 –

+0

這看起來像是一個簡單的解決方案,用於在本地主機上籤署自我證書 –

8

您可以add this class並從onCreate執行它方法

new NukeSSLCerts().nuke(); 

它將排除信任所有SSL證書。

+1

這是太危險了... – Rocel

+0

其他方式是certbot,提供免費簽名的證書,但只有90天,我們必須在每90天更新一次 –

+1

發展的完美 –

1

到目前爲止,唯一的答案是關於添加不可信證書作爲解決方案,但由於您的瀏覽器沒有投訴,通常意味着Volley無法找到完成完整信任鏈的中間證書。

它發生在我身上的LetsEncrypt證書。大多數瀏覽器已經有這樣的中間證書,所以在瀏覽器上看起來一切正常,但是Volley顯然缺少一些東西。

解決方案
中間證書添加到Web服務器的配置。對於Apache你可以按照這個參考:
https://access.redhat.com/solutions/43575

對於LetsEncrypt它專門爲這個文件:/etc/letsencrypt/live/your.website.com/chain.pem 因此,除了你的CertificateFile和KeyFile時,你應該已經工作,你現在有這個第三行:

SSLCertificateChainFile /etc/letsencrypt/live/your.website.com/chain.pem 

只需添加該行,重新啓動Apache並且Volley不再抱怨,並且您沒有引入任何安全漏洞!

0

發生這種情況的原因很多,其中包括:

  • 頒發服務器證書的CA是未知的
  • 服務器證書不是由CA簽名,但自簽署
  • 的服務器配置缺少中間CA

Official doc from android

解決方案: 可以請求

1

內提供證明文件,如果您使用的凌空欲HTTPS請求或SSL認證服務,那麼你可以選擇這種最簡單的方法: - >

步驟 - > 1.將.cer文件保存到res/raw /文件夾中。

步 - > 2.使用此方法,並與你的.CER文件替換.CER文件名,並同時更換您的主機名。

private SSLSocketFactory getSocketFactory() { 

    CertificateFactory cf = null; 
    try { 

     cf = CertificateFactory.getInstance("X.509"); 
     InputStream caInput = getResources().openRawResource(R.raw.cert_name); 
     Certificate ca; 
     try { 

      ca = cf.generateCertificate(caInput); 
      Log.e("CERT", "ca=" + ((X509Certificate) ca).getSubjectDN()); 
     } finally { 
      caInput.close(); 
     } 


     String keyStoreType = KeyStore.getDefaultType(); 
     KeyStore keyStore = KeyStore.getInstance(keyStoreType); 
     keyStore.load(null, null); 
     keyStore.setCertificateEntry("ca", ca); 


     String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); 
     TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); 
     tmf.init(keyStore); 


     HostnameVerifier hostnameVerifier = new HostnameVerifier() { 
      @Override 
      public boolean verify(String hostname, SSLSession session) { 

       Log.e("CipherUsed", session.getCipherSuite()); 
       return hostname.compareTo("10.199.89.68")==0; //The Hostname of your server. 

      } 
     }; 


     HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier); 
     SSLContext context = null; 
     context = SSLContext.getInstance("TLS"); 

     context.init(null, tmf.getTrustManagers(), null); 
     HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory()); 

     SSLSocketFactory sf = context.getSocketFactory(); 


     return sf; 

    } catch (CertificateException e) { 
     e.printStackTrace(); 
    } catch (NoSuchAlgorithmException e) { 
     e.printStackTrace(); 
    } catch (KeyStoreException e) { 
     e.printStackTrace(); 
    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } catch (KeyManagementException e) { 
     e.printStackTrace(); 
    } 

    return null; 
} 

Step - > 3.將這一行替換爲「RequestQueue queue = Volley.newRequestQueue(this);」與「RequestQueue隊列= Volley.newRequestQueue(this,new HurlStack(null,getSocketFactory()));」在排球的要求。