2011-06-23 57 views
7

Tôi hơi bối rối khi cố gắng sử dụng HttpClient để gọi một trang web https sử dụng chứng chỉ tự ký. Tôi có các mã như dưới đây, đó là cho phép tôi thực hiện cuộc gọi nhưng sau đó tôi nhận được lỗi như javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found Tôi đã tải về chứng chỉ từ trình duyệt web của tôi và hiểu tôi có thể nhập nó vào kho khóa nhưng tôi thà chỉ cần đặt nó vào mã và sử dụng nó theo cách đó, có cách nào để làm điều này không?Lỗi Java HttpClient không tìm thấy chứng chỉ SSL, sử dụng chứng chỉ dưới dạng Chuỗi trong mã?

HttpClient client = new HttpClient(); 

    EasySSLProtocolSocketFactory easySSLProtocolSocketFactory = new EasySSLProtocolSocketFactory(); 
    Protocol https = new Protocol("https", easySSLProtocolSocketFactory, 
      443); 
    Protocol.registerProtocol("https", https); 

    BufferedReader br = null; 

    String responseString = ""; 

    GetMethod method = new GetMethod(path); 

    int returnCode = client.executeMethod(method); 
+0

Tại sao bạn lại đặt mã vào mã? Điều gì xảy ra khi chứng chỉ máy chủ hết hạn và họ nhận được chứng chỉ mới? Đừng làm thế. – EJP

Trả lời

4

Giả sử chứng chỉ của bạn ở định dạng PEM. Bạn có thể nhúng mã vào mã và sử dụng BouncyCastle 's PEMReader để biến nó thành một phiên bản X509Certificate. Khi việc này được thực hiện, hãy tạo một cá thể KeyStore trong bộ nhớ và đặt chứng chỉ X.509 này vào bộ nhớ. Sau đó, tạo nhanh SSLContext bằng cách sử dụng KeyStore làm cửa hàng ủy thác và làm cho ứng dụng HTTP của bạn sử dụng nó.

này sẽ trông như thế này (không cố gắng, nhớ đóng độc giả và bắt ngoại lệ ...):

PEMReader pemReader = new PEMReader(new StringReader("----- BEGIN ......"); 
X509Certificate cert = (X509Certificate) pemReader.readObject(); 

KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); 
ks.load(null, null); 
ks.setCertificateEntry("some name", cert); 

TrustManagerFactory tmf = TrustManagerFactory.getInstance(
    TrustManagerFactory.getDefaultAlgorithm()); 
tmf.init(ks); 

SSLContext sc = SSLContext.getInstance("TLS"); 
sc.init(null, tmf.getTrustManagers(), null); 

Sau đó, sử SSLContext này cho kết nối của bạn. Bạn có thể làm điều này với Apache HttpClient SSLSocketFactory nếu bạn đang sử dụng phiên bản 4.x (hoặc this nếu bạn đang sử dụng phiên bản 3.x). Tôi muốn đề nghị sử dụng Apache HttpClient 4.x ngày nay.

+0

cảm ơn, đây là thông tin tuyệt vời, tôi không quen thuộc với SSLSocketFactory và tôi đang đấu tranh để tìm một ví dụ, tôi đoán nó sẽ thay thế 'EasySSLProtocolSocketFactory' trong mã của tôi? Bất kỳ lời khuyên về việc sử dụng này được đánh giá rất cao – Rick

+0

thực sự tôi nghĩ rằng tôi đã nhập sai nhà máy SSL (từ Java.net.ssl ​​.. Tôi thấy tôi cần một Apache bây giờ – Rick

+0

bạn có thể làm rõ gói SSLContext bạn đang sử dụng, xin lỗi tôi chỉ là một bit nhầm lẫn vì có nhiều hơn 1 – Rick

0

Đây là cách để làm cho Apache HttpClient 4,3 chấp nhận chứng chỉ tự ký:

HttpClientBuilder cb = HttpClientBuilder.create(); 
SSLContextBuilder sslcb = new SSLContextBuilder(); 
sslcb.loadTrustMaterial(KeyStore.getInstance(KeyStore.getDefaultType()), 
         new TrustSelfSignedStrategy()); 
cb.setSslcontext(sslcb.build()); 
HttpClient client = cb.build() 

Bây giờ để thực hiện POST hoặc GET yêu cầu sử dụng tiêu chuẩn thực hiện phương pháp:

HttpResponse response = client.execute(...); 

Nhắc nhở: Bạn dễ bị tổn thương khi bạn tin tưởng chứng chỉ tự ký.

+0

Nhận ngoại lệ này khi tôi sử dụng mã: "Ngoại lệ trong chủ đề" chính "javax.net.ssl.SSLException: java.lang.RuntimeException: Lỗi không mong muốn: java.security.InvalidAlgorithmParameterException: tham số trustAnchors phải không trống" – Mike

+0

Chấp nhận tất cả các chứng chỉ tự ký [không an toàn] (http://stackoverflow.com/q/23923810/781723); nó khá nhiều đánh bại mục đích sử dụng SSL ngay từ đầu. –

2

Xây dựng về câu trả lời của Alexander Chzhen và cho HttpClient 4.3 đầu tiên tôi tạo ra một bối cảnh đó tin tưởng tất cả:

SSLContextBuilder sslctxb = new SSLContextBuilder(); 

sslctxb.loadTrustMaterial(KeyStore.getInstance(KeyStore.getDefaultType()), 
          new TrustSelfSignedStrategy() { 
    @Override 
    public boolean isTrusted(X509Certificate[] chain, 
          String   authType) 
    throws CertificateException { 
    return true; 
    } 
}); 

SSLContext sslctx = sslctxb.build(); 

Sau đó, những người xây dựng khách hàng:

HttpClientBuilder hcb = HttpClients.custom(); 

và tôi chỉ đặt bối cảnh. Tôi không sử dụng setSSLSocketFactory bởi vì nó sẽ gây trở ngại cho setHostnameVerifier dưới đây:

hcb.setSslcontext(sslctx); 

Cuối cùng tôi đặt một người xác minh hostname xác minh tất cả:

hcb.setHostnameVerifier(new X509HostnameVerifier() { 
    @Override 
    public void verify(String host, SSLSocket ssl) 
    throws IOException { 
    } 

    @Override 
    public void verify(String host, X509Certificate cert) 
    throws SSLException { 
    } 

    @Override 
    public void verify(String host, String[] cns, String[] subjectAlts) 
    throws SSLException { 
    } 

    @Override 
    public boolean verify(String hostname, SSLSession session) { 
    return true; 
    } 
}); 

Cuối cùng xây dựng cho khách hàng:

HttpClient c = hcb.build(); 
+0

+1 bởi vì điều này làm việc trong khi giải pháp của Alexander không phải là – Mike

+1

@ Giống như vậy, vấn đề với hai giải pháp này là bạn chấp nhận * bất kỳ * chứng chỉ tự ký (ít nhiều giống như tắt xác minh chứng chỉ). – Bruno

1

Nếu bạn chỉ muốn chấp nhận chứng chỉ đơn này nhưng không phải tất cả chứng chỉ tự ký, thì bạn nên tải xuống chứng chỉ và lưu trữ tệp pem một cách nào đó đây.

Bây giờ bạn có thể sử dụng mã này để tải tệp pem, tạo một cửa hàng ủy thác mới với chứng chỉ này và sử dụng truststore cho HttpClient của bạn.

//use java. ... .X509Certificate, not javax. ... .X509Certificate 
import java.security.cert.X509Certificate; 
import java.security.cert.CertificateException; 
import java.security.cert.CertificateFactory; 

@Test 
public void testSslCertificate() 
     throws IOException, KeyStoreException, NoSuchAlgorithmException, 
       CertificateException, KeyManagementException { 

    X509Certificate cert; 
    try (FileInputStream pemFileStream = new FileInputStream(newFile("your.pem"))) { 
     CertificateFactory certFactory = CertificateFactory.getInstance("X509"); 
     cert = (X509Certificate) certFactory.generateCertificate(pemFileStream); 
    } 

    //create truststore 
    KeyStore trustStore = KeyStore.getInstance("JKS"); 
    trustStore.load(null); //create an empty trustore 

    //add certificate to truststore - you can use a simpler alias 
    String alias = cert.getSubjectX500Principal().getName() + "[" 
      + cert.getSubjectX500Principal().getName().hashCode() + "]"; 
    trustStore.setCertificateEntry(alias, cert); 

    //configure http client 
    TrustManagerFactory trustManagerFactory = 
     TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
    trustManagerFactory.init(trustStore); 

    SSLContext sslContext = SSLContext.getInstance("TLS"); 
    sslContext.init(null, trustManagerFactory.getTrustManagers(), null); 

    HttpClientBuilder httpClientBuilder = HttpClientBuilder. 
              create().setSslcontext(sslContext); 

    try (CloseableHttpClient httpClient = httpClientBuilder.build()) { 
     HttpGet httpGetRequest = new HttpGet("https://yourServer"); 
     try (CloseableHttpResponse httpResponse = 
          httpClient.execute(httpGetRequest)) { 
      Assert.assertEquals(200, 
           httpResponse.getStatusLine().getStatusCode()); 
     } 
    } 
} 
0

Trong nhiều trường hợp, việc ghim chứng chỉ có thể thích hợp hơn để mã hóa một chứng chỉ cụ thể.

Có, bạn có thể mã hóa một chứng chỉ vào mã của bạn và thao tác đó sẽ hoạt động và bảo mật. Đó là một cách tiếp cận hoàn toàn hợp lý. Tuy nhiên, nó có một số nhược điểm. Một điều đáng tiếc là cuối cùng chứng chỉ đó sẽ hết hạn và sau đó ứng dụng của bạn sẽ ngừng hoạt động. Ngoài ra, nếu bạn muốn thay đổi khóa riêng của mình, bạn sẽ không thể.

Do đó, trong nhiều trường hợp, việc sử dụng ghim chứng chỉ linh hoạt hơn và có thể thích hợp hơn. Xem here để biết các tham chiếu về cách triển khai ghim chứng chỉ.

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