2012-01-30 44 views
5

Tôi đang gặp sự cố khi tương tác với trang web HTTPS qua Java. Chương trình của tôi sử dụng một URL có chứng chỉ không đáng tin cậy mỗi khi chương trình chạy. Chương trình này phải chạy trên nhiều hệ thống. Hiện nay, tôi có như sau:Chấp nhận chứng chỉ trong Java

public class A{ 
    HostnameVerifier hv = new HostnameVerifier(){ 
     public boolean verify(String urlHostName, SSLSession session){ 
      return true; 
     }  
    }; 

    HttpsURLConnection.setDefaultHostnameVerifier(hv); 

    javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1]; 
    javax.net.ssl.TrustManager tm = new miTM(); 
    trustAllCerts[0] = tm; 
    javax.net.ssl.SSLContext sc = null; 
    try { 
     sc = javax.net.ssl.SSLContext.getInstance("SSL"); 
    } catch (NoSuchAlgorithmException e) { 
     e.printStackTrace(); 
    } 
    try { 
     sc.init(null, trustAllCerts, null); 
    } catch (KeyManagementException e) { 
     e.printStackTrace(); 
    } 
    javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 
} 
class miTM implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager{ 

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

    public boolean isServerTrusted(java.security.cert.X509Certificate[] certs){ 
     return true; 
     } 

    public boolean isClientTrusted(java.security.cert.X509Certificate[] certs){ 
     return true; 
    } 

    public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException{ 
     return; 
    } 

    public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException{ 
     return; 
     } 
} 

Với mã này, tôi có thể thực hiện như sau tốt:

URL url = new URL(urlString); 
URLConnection cnx = url.openConnection(); 
cnx.connect(); 

InputStream ins = cnx.getInputStream(); 
BufferedReader in = new BufferedReader(new InputStreamReader(ins)); 
String curline; 
while((curline = in.readLine()) != null) { 
    System.out.println(curline); 
} 

Tuy nhiên, tôi không thể làm như sau:

httpClient = new HttpClient(); 
PostMethod postMethod = null; 
int intResult = 0; 
postMethod = new PostMethod(authURL); 
Enumeration emParams = authParams.propertyNames(); 
while (emParams.hasMoreElements()) { 
    String paramName = (String) emParams.nextElement(); 
    String paramValue = authParams.getProperty(paramName); 
    postMethod.addParameter(paramName, paramValue); 
} 

intResult = httpClient.executeMethod(postMethod); 
postMethod.releaseConnection(); 
ins.close(); 

Khi executeMethod (postMethod) được thực hiện, tôi nhận được một SSLHandshakeException, CertPathBuilderException, và như vậy.

Tôi có thể làm gì để khắc phục vấn đề này? Tôi đang nghĩ đến việc chấp nhận chứng chỉ hoặc chỉ bỏ qua tất cả xác nhận chứng chỉ (khi chương trình chạy trong nội bộ trong một mạng riêng).

Cảm ơn

+0

Bạn có sử dụng Apache HttpClient 3.x (hoặc 4)? – Bruno

Trả lời

5

Dường như bạn đang sử dụng Apache HttpClient 3. Nếu đây thực sự là phiên bản 3, bạn cần xây dựng riêng SecureProtocolSocketFactory như được giải thích trong Apache HttpClient 3 SSL guide của bạn. Có một số example here.

Đối với Apache HttpClient 4, bạn sẽ có thể chuyển một số SSLContext tới hàm tạo cho (HttpClient) SSLSocketFactory, như được mô tả trong the answers to this question (bao gồm ghi chú liên quan đến xác minh tên máy chủ).

Tuy nhiên, nói chung, không làm theo cách tiếp cận này. Bạn đang vô hiệu hóa một cách hiệu quả phần xác thực của kết nối SSL/TLS hoàn toàn bằng cách làm như vậy, do đó làm cho nó dễ bị tấn công MITM.

Thay vào đó, bạn nên nhập chứng chỉ máy chủ trong kho lưu trữ tin cậy của khách hàng, như được mô tả trong this answer.

Tôi đang nghĩ đến việc chấp nhận chứng chỉ hoặc chỉ bỏ qua tất cả xác nhận chứng chỉ (khi chương trình chạy trong nội bộ trong mạng riêng tư ).

Điều bạn đang nói là bạn sẵn sàng sử dụng SSL/TLS để mã hóa chỉ trong mạng riêng của mình bởi vì bạn không tin tưởng người dùng của mình không đủ để xem lưu lượng truy cập xung quanh máy của họ , nhưng bạn cũng giả định rằng những người dùng này sẽ không thể thực hiện tấn công MITM. Điều này không hoàn toàn hợp lý. Nếu bạn tin tưởng họ đủ, bạn cũng có thể gửi dữ liệu rõ ràng. Nếu không, thì bạn nên triển khai SSL/TLS đúng cách, bao gồm các bước xác thực (chứng chỉ và xác minh tên máy chủ).

+0

Cảm ơn! Tôi đã sử dụng Apache HttpClient 3.x, nhưng quyết định đi với 4. Tôi theo đề nghị của bạn và nó đã làm việc. Cảm ơn một lần nữa. – ms1013

1

HttpClient 4.3:

 HttpClientBuilder cb = HttpClientBuilder.create(); 
    SSLContextBuilder sslcb = new SSLContextBuilder(); 
    sslcb.loadTrustMaterial(KeyStore.getInstance(KeyStore.getDefaultType()), new TrustSelfSignedStrategy()); 
    cb.setSslcontext(sslcb.build()); 
    CloseableHttpClient httpclient = cb.build(); 
+0

bạn có thể giải thích điều này một chút không? – benka

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