2013-06-11 29 views
43

tôi đang cố gắng để thực hiện một yêu cầu https sử dụng mã này:Đưa ra yêu cầu HTTPS sử dụng Android Volley

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

nhưng tôi nhận được lỗi này:

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

Hai điểm cần lưu ý:

  1. Chứng chỉ HTTPS hợp lệ. Dễ dàng mở mà không có bất kỳ cảnh báo nào trên trình duyệt.
  2. Mã trên hoạt động tốt với các liên kết HTTP.

Tôi thực sự cần phải biết nếu có bất kỳ thiết bị chuyển mạch/tùy chọn nào trong khung công tác Android Volley bằng cách sử dụng thành công nào tôi sẽ đạt được URL HTTPS?

+1

Tôi đoán là bạn sẽ cần định cấu hình theo cách tương tự nếu bạn sử dụng trực tiếp 'HttpUrlConnection'. Xem http://commonsware.com/blog/2013/03/04/ssl-android-basics.html và http://nelenkov.blogspot.ie/2011/12/using-custom-certificate-trust-store-on .html – CommonsWare

+4

Tôi đã tìm thấy một lớp được gọi là 'HurlStack' mở rộng' HttpStack' là một tham số tùy chọn cho 'Volley.newRequestQueue'. Phương thức khởi tạo của 'HurlStack' chấp nhận một tham số kiểu' SSLSocketFactory' và nó được viết bằng javadoc của nó: "Nhà máy SSL để sử dụng cho các kết nối HTTPS" nhưng chưa thử nó. –

Trả lời

14

Có lẽ liên kết này sẽ rất hữu ích cho bạn: Using Android Volley With Self-Signed SSL Certificate

+1

Vui lòng kiểm tra xem hàng nhập có đúng không. Có lẽ bạn đã trộn các lớp HttpClient tích hợp với các lớp từ bản demo. – Ognyan

+0

Rất tiếc, tôi không mong đợi câu trả lời nhanh chóng, bạn đã chính xác rằng đó là vấn đề. Cảm ơn bạn đã tạo một thư viện khổng lồ như vậy. – SteveGSD

+0

liên kết có thể bị hỏng ... bạn có thể kiểm tra không? @Ogre_BGR – rafid059

1

Tôi không thể mở các liên kết được cung cấp bởi @ Ogre_BGR, nhưng khi duyệt net tôi thấy việc thực hiện thực tế thực hiện trong sau smanikandan14 Github .Look khi ông SSl-connection explanation để hiểu thêm về nó.

47

Có lẽ các mã dưới đây sẽ rất hữu ích cho bạn:

1.Create một lớp HttpsTrustManager mà thực hiện 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.Add HttpsTrustManager.allowAllSSL() trước khi bạn thực hiện một yêu cầu 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

Điều này là tất cả ngoại trừ việc bạn không thực sự xác thực chứng chỉ máy chủ. Chỉ cần chắc chắn không triển khai điều này trong sản xuất, trừ khi bạn muốn phơi bày người dùng của mình với tất cả các loại tấn công SSL. – asgs

+3

Đây không phải dành cho sản xuất. –

+0

điều này trông giống như một giải pháp đơn giản cho tự ký cert trên localhost –

8

bạn có thể add this class và thực hiện nó từ onCreate phương pháp

new NukeSSLCerts().nuke(); 

nó sẽ làm cho bóng chuyền tin cậy tất cả chứng chỉ SSL.

+1

điều này quá nguy hiểm ... – Rocel

+0

cách khác là certbot, cung cấp chứng chỉ đã ký miễn phí, nhưng chỉ trong 90 ngày, chúng tôi phải gia hạn sau 90 ngày –

+1

Hoàn hảo cho phát triển –

1

Cho đến nay câu trả lời duy nhất nói về việc thêm chứng chỉ không đáng tin cậy làm giải pháp, nhưng vì trình duyệt của bạn không phàn nàn thường có nghĩa là Volley không thể tìm thấy chứng chỉ trung gian hoàn thành chuỗi tin cậy đầy đủ.

Điều đó xảy ra với tôi bằng chứng chỉ LetsEncrypt. Hầu hết các trình duyệt đã có các chứng chỉ trung gian để mọi thứ trên trình duyệt đều ổn, nhưng Volley dường như thiếu một thứ gì đó.

Giải pháp
Thêm chứng chỉ trung gian vào cấu hình máy chủ web của bạn. Đối với Apache bạn có thể làm theo tài liệu tham khảo này:
https://access.redhat.com/solutions/43575

cho LetsEncrypt nó đặc biệt là tập tin này: /etc/letsencrypt/live/your.website.com/chain.pem Vì vậy, bên cạnh CertificateFile và keyfile của bạn, bạn đã phải làm việc bây giờ bạn có dòng thứ ba này:

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

Chỉ cần thêm dòng đó, khởi động lại apache và Volley không phàn nàn nữa và bạn đã không giới thiệu bất kỳ lỗ hổng bảo mật nào!

0

Điều này có thể xảy ra vì nhiều lý do, bao gồm:

  • Các CA cấp chứng chỉ máy chủ là chưa biết
  • Chứng chỉ máy chủ đã không có chữ ký của CA, nhưng tự được ký
  • Các cấu hình máy chủ là mất tích một CA trung gian

Official doc from android

Giải pháp: bạn có thể cung cấp một tập tin giấy chứng nhận trong thời hạn theo yêu cầu

1

Nếu bạn đang sử dụng bóng và muốn HTTPS yêu cầu hoặc dịch vụ chứng nhận SSL sau đó bạn có thể chọn cách dễ nhất này: ->

Bước -> 1. giữ tập tin .cer vào res/raw/folder.

Bước -> 2. Sử dụng phương pháp này và thay thế tên tệp .cer bằng tệp .cer của bạn và thay thế tên máy chủ của bạn.

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; 
} 

Bước -> 3. Thay thế dòng này "RequestQueue queue = Volley.newRequestQueue (this);" với "RequestQueue queue = Volley.newRequestQueue (điều này, HurlStack mới (null, getSocketFactory()));" theo yêu cầu của bóng chuyền.

Các vấn đề liên quan