2013-08-15 25 views
50

Tôi nhận được lỗi kết nối xuất hiện ngẫu nhiên khi kết nối với máy chủ HAProxy bằng SSL. Tôi đã xác nhận rằng những lỗi này xảy ra trên các phiên bản JDK 1.7.0_21 và 1.7.0_25 nhưng không phải với 1.7.0_04 hoặc với 1.6.0_38.

Trường hợp ngoại lệ là

Exception in thread "main" javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated 
    at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:397) 
    at SSLTest2.main(SSLTest2.java:52) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:601) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) 

Những thất bại này chỉ xảy ra khi sử dụng bối cảnh SSL TLS và không phải với bối cảnh mặc định. Các mã sau đây được chạy trong một vòng lặp một ngàn lần và thất bại xảy ra trước khi vòng lặp hoàn thành (khoảng 2% của các kết nối thất bại):

SSLContext sslcontext = SSLContext.getInstance("TLS"); 
sslcontext.init(null, null, null); 
SSLSocketFactory factory = sslcontext.getSocketFactory(); 
SSLSocket socket = (SSLSocket)factory.createSocket("myserver", 443); 

//socket.startHandshake(); 
SSLSession session = socket.getSession(); 
session.getPeerCertificates(); 
socket.close(); 

Tuy nhiên, nếu tôi tạo ra bối cảnh SSL cách này tôi không có kết nối thất bại trên bất kỳ phiên bản Java tôi đã đề cập:

SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault(); 

cách đầu tiên sử dụng SSLContextImpl$TLS10Context và sau đó sử dụng SSLContextImpl$DefaultSSLContext. Nhìn vào mã, tôi không thấy bất kỳ sự khác biệt nào có thể gây ra ngoại lệ.

Tại sao tôi nhận được lỗi và lợi ích/bất lợi của việc sử dụng cuộc gọi getDefault() là gì?

Lưu ý: Các trường hợp ngoại lệ được nhìn thấy lần đầu tiên bằng cách sử dụng Apache HttpClient (phiên bản 4). Mã này là tập hợp con nhỏ nhất tái tạo vấn đề được thấy với HttpClient.

Đây là lỗi tôi thấy khi thêm -Djavax.net.debug=ssl:

main, READ: TLSv1 Alert, length = 2 
main, RECV TLSv1 ALERT: fatal, bad_record_mac 
%% Invalidated: [Session-101, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA] 
main, called closeSocket() 
main, handling exception: javax.net.ssl.SSLException: Received fatal alert: bad_record_mac 
main, IOException in getSession(): javax.net.ssl.SSLException: Received fatal alert: bad_record_mac 

Một mẩu thông tin là các lỗi không xảy ra nếu tôi tắt Diffie-Hellman trên máy chủ proxy.

+3

Vui lòng chạy lại với -Djavax.net.debug = ssl, bắt tay và đăng đầu ra từ lần chạy không thành công. – EJP

+0

Chạy lại bằng tùy chọn gỡ lỗi. Đã cập nhật câu hỏi với thông tin này. Có ai có ý tưởng nào? – user2687486

+0

Tại sao bạn thích bốn dòng mã hơn? – EJP

Trả lời

1

Xét xử của các triệu chứng, tôi đoán này có liên quan đến trình duyệt sử dụng TLS false start, đó là một thủ thuật client-side Google giới thiệu với reduce the back-and-forth in TLS:

Bắt đầu False được kiểm soát chủ yếu bởi các trình duyệt và hoạt động bằng cách giảm hai lần truyền dữ liệu được mô tả trong thông số kỹ thuật SSL chính thức thành một vé khứ hồi. Nó đã làm điều này bằng cách hướng dẫn máy khách gửi các thông báo ApplicationData đã hoàn thành và đầu tiên trong một công văn đơn chứ không phải đặt chúng trong hai gói riêng biệt và chỉ gửi thứ hai sau khi nhận được xác nhận từ máy chủ.

Google đề xuất False Start làm tiêu chuẩn chính thức để làm cho SSL trở nên dễ chịu hơn đối với các trang web hiện tại thấy nó quá đắt để cung cấp. Bằng cách viết tắt cái bắt tay đàm phán khóa mã hóa và các biến khác cần thiết để bảo vệ dữ liệu đi qua giữa người dùng cuối và trang web, False Start được dự định giảm hình phạt hiệu suất mà nhiều người nói đến từ việc sử dụng giao thức.

Từ relevant issue raised in Mozilla Firefox: (tôi nhấn mạnh)

Cho đến nay, một danh sách đầy đủ các sản phẩm mà được biết là có vấn đề về khả năng tương thích hiện tại hoặc trước đó với Bắt đầu False bao gồm (AFAICT): F5, A10, Microsoft TMG, Cisco ASA, ServerIron ADX, ESET, NetNanny, một số cấu hình triển khai máy chủ SSL của Java.

+0

Kết nối, trong trường hợp của OP và cũng trong trường hợp của tôi, là giữa một khách hàng được viết bằng JAVA và một máy chủ (proxy hoặc http). Không có trình duyệt nào ở đây ... –

+0

@ LorenzoDematté Aah, tất nhiên, bạn nói đúng. Không thể tin rằng tôi đã bỏ lỡ điều đó. – JvR

-3

javax.net.ssl.SSLPeerUnverifiedException nảy sinh chỉ vì an ninh http bạn phải cấu hình kết nối của bạn như https khác theo mã này ..

  SSLContext ctx = SSLContext.getInstance("TLS"); 
    ctx.init(null, new TrustManager[]{tm}, null); 
    SSLSocketFactory ssf = new SSLSocketFactory(ctx); 
    ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 
    ClientConnectionManager ccm = client.getConnectionManager(); 
    SchemeRegistry sr = ccm.getSchemeRegistry(); 
    sr.register(new Scheme("https", ssf, 443)); 
    return new DefaultHttpClient(ccm, client.getParams()); 

sử dụng này. tôi hy vọng nó sẽ giúp bạn

+3

Bạn vừa giới thiệu lỗ hổng bảo mật với 'ALLOW_ALL_HOSTNAME_VERIFIER', điều đó không giúp ích gì. – Bruno

+0

Nó không 'phát sinh chỉ vì an ninh HTTP' ở tất cả. Nó không liên quan gì đến HTTPS. Nó xảy ra ở lớp TLS. – EJP