2013-07-31 8 views
8

Tôi đang đọc từ SSL Socket nhưng máy chủ không khớp với chứng chỉ (ví dụ: host = "localhost"). Tôi sẽ mong đợi ngoại lệ nhưng mã sau đây vui vẻ nói chuyện với máy chủ từ xa mà không có bất kỳ vấn đề.SSLSocket bỏ qua miền không khớp

try (
    final Socket socket = SSLSocketFactory.getDefault().createSocket(host, port); 
    final OutputStream os = socket.getOutputStream(); 
    final InputStream is = socket.getInputStream()) { 

    os.write(("HEAD/HTTP/1.1\r\nHost: " + host + "\r\nConnection: close\r\n\r\n").getBytes()); 
    os.flush(); 

    final byte[] bytes = new byte[1024]; 
    int n; 
    while ((n = is.read(bytes)) != -1) { 
     System.out.print(new String(bytes, 0, n)); 
    } 
    System.out.println(); 
} catch (final IOException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
} 

Vì vậy, tôi đã cố gắng tiếp cận khác:

try { 
    final HttpURLConnection conn = (HttpURLConnection) new URL("https://" + host + ":" + port + "/").openConnection(); 

    try (InputStream is = conn.getInputStream()) { 
     IOUtils.copy(is, System.out); 
    } catch (final IOException e1) { 
     try (InputStream es = conn.getErrorStream()) { 
      if (es != null) { 
       IOUtils.copy(es, System.out); 
      } 
     } 
    } 
} catch (final IOException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
} 

Đáng tiếc là tôi vẫn nhận được không phải ngoại lệ SSL, chỉ WARN trong các bản ghi: 2013-07-31 16:02:27,182 WARN nio - javax.net.ssl.SSLException: Received fatal alert: certificate_unknown

Làm thế nào để có được ngoại lệ SSL nếu giấy chứng nhận không phù hợp?

Trả lời

16

Đặc tả giao thức SSL/TLS là mô đun và được tách rời khỏi các thông số được sử dụng để xác thực máy chủ từ xa. Các thông số kỹ thuật khác được chia thành hai loại: xác minh rằng bản thân chứng chỉ có thể tin cậy (RFC 3280/5280) và xác minh danh tính trong chứng chỉ (RFC 6125 hoặc RFC 2818 cho HTTPS).

JSSE tích hợp giao thức SSL và xác minh chứng chỉ trong API SSLSocket (hoặc SSLEngine), nhưng không xử lý xác minh số nhận dạng (whch cũng quan trọng không kém).

Điều này chủ yếu là do thực tế là SSLSocket/SSLEngine có thể áp dụng cho bất kỳ giao thức ứng dụng nào (ví dụ: HTTP, IMAP, SMTP, LDAP, ...), nhưng quy tắc xác minh số nhận dạng có các thông số khác nhau các biến thể nhỏ), cho đến khi RFC 6125 (vẫn còn khá gần đây).

HttpsURLConnection xử lý cả hai, vì nó cũng sử dụng một HostnameVerifier, tuân theo đặc tả HTTPS (RFC 2818, Phần 3.1). Việc này được thực hiện riêng biệt với API SSLSocket/SSLEngine. Đối với các giao thức khác, bạn có thể cần phải thực hiện những gì đặc tả giao thức nói.

Điều này được nói, kể từ Java 7, có một cơ chế để xác minh danh tính của chứng chỉ trực tiếp như một phần của API SSLSocket/SSLEngine.

SSLParameters sslParams = new SSLParameters(); 
sslParams.setEndpointIdentificationAlgorithm("HTTPS"); 
sslSocket.setSSLParameters(sslParams); 

Sử dụng điều này sẽ làm cho nó ném ngoại lệ nếu tên máy chủ không khớp.

Không có sự khác biệt lớn giữa HTTPS và các thông số kỹ thuật thống nhất hơn trong RFC 6125 (bên cạnh thực tế là sau này xem xét địa chỉ IP nằm ngoài phạm vi). Ngay cả khi bạn không sử dụng HTTPS, thông thường sẽ có ý nghĩa khi sử dụng các đặc tả nhận dạng của nó cho các giao thức khác. (Có lẽ thuật toán nhận dạng điểm cuối "RFC 6125" có thể có trong các phiên bản sau của Java.)

+0

Cảm ơn bạn đã cung cấp chi tiết. –

2

So khớp tên máy chủ không phải là một phần của SSL, nó là một phần của HTTPS. Xem ví dụ javax.net.ssl.HostnameVerifier.

Nhật ký bạn trích dẫn cho biết rằng một SSLException được ném bởi HttpsURLConnection.

+0

Sau khi truy tìm nhật ký đó, tôi đã phát hiện ra rằng nó đã được ghi lại trong 'org.eclipse.jetty.io.nio.SelectChannelEndPoint' (testcase và máy chủ này trên cùng một JVM). Ngoài ra tôi đã phát hiện ra rằng 'IOException' ném từ đọc từ connection.getInputStream() thực sự là' javax.net.ssl.SSLHandshakeException' và đây là chính xác những gì tôi cần :-) –