2012-03-22 34 views
19

Tôi có một chương trình Java kết nối với máy chủ web bằng SSL/TLS và gửi các yêu cầu HTTP khác nhau qua kết nối đó. Máy chủ là localhost và đang sử dụng chứng chỉ tự ký, nhưng mã của tôi đang sử dụng TrustManagers tùy chỉnh và bỏ qua chứng chỉ không hợp lệ. Nó đã hoạt động hoàn hảo cho đến bây giờ.Nhận SSLHandshakeException: handshake_failure mặc dù khách hàng của tôi bỏ qua tất cả các chứng chỉ

Sự khác biệt duy nhất trên máy chủ là nó được sử dụng để chạy jboss 6 và hiện đang chạy jboss 7. Tôi không chắc đây có phải là vấn đề về cấu hình hay không, có vấn đề với mã của tôi hay không các lỗi tương tự nếu tôi cố kết nối bằng các chương trình dựa trên Java khác như WebScarab hoặc ZAP.

Trong mọi trường hợp, có bất kỳ điều gì tôi có thể thực hiện với mã của mình để khắc phục sự cố này không? Dưới đây là lỗi đầy đủ:

Received fatal alert: handshake_failure 
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure 
     at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source) 
     at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(Unknown Source) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source) 
     at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source) 
     at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source) 
     at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source) 
     at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(Unknown Source) 

Dưới đây là các thông điệp debug trước sự thất bại:

main, WRITE: TLSv1 Handshake, length = 75 
main, WRITE: SSLv2 client hello message, length = 101 
main, READ: TLSv1 Alert, length = 2 
main, RECV TLSv1 ALERT: fatal, handshake_failure 

Trả lời

24

Vì vậy, tôi đã tìm thấy sự cố. Có thể có một lỗi trong Java, nhưng máy khách dường như bắt đầu một TLSv1 Handshake, nhưng sau đó gửi một thông điệp chào hỏi của máy khách SSLv2, tại thời điểm đó máy chủ từ chối kết nối.

Điều này xảy ra ngay cả khi bạn tạo SSLContext của bạn với một thể hiện của TLS:

SSLContext sslContext = SSLContext.getInstance("TLS"); 

Giải pháp là để thiết lập một hệ thống tài sản trước khi bất kỳ cố gắng kết nối được thực hiện:

System.setProperty("https.protocols", "TLSv1"); 

Có lẽ các giải pháp khác cho nó, nhưng điều này làm việc cho tôi.

+1

Bạn có thể quan tâm đến điều này: http://stackoverflow.com/a/4686924/372643 – Bruno

+0

@Bruno Yeah, tôi thấy rằng trước đó trong khi tìm kiếm trên Google. Đây có phải là lỗi trong Java không? Tôi không thể nhìn thấy nó như thế nào có thể/nên được mặc định hành vi khi tôi đã chỉ định SSLContext như TLS. – Rsaesha

+1

Nó không phải là một lỗi, đó là do thiết kế (SSLv2 là cho comp phía sau.). Xem [JSSE Ref/SSLContext] (http://docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#SSLContext): "* Ví dụ: getInstance (" SSLv3 ") có thể trả về một cá thể thực hiện "SSLv3" và "TLSv1" * [...] Bạn có thể kiểm soát giao thức nào thực sự được kích hoạt cho kết nối SSL bằng cách sử dụng phương thức setEnabledProtocols (String [] protocols) ". Trong trường hợp của bạn, 'https.protocols' sẽ xử lý' setEnabledProtocols' cho 'HttpsURLConnection'. – Bruno

0

Bạn đang nhìn thấy lỗi này có lẽ hầu hết vì keystore rằng JBoss của bạn 6 có quyền truy cập vào là không thể truy cập cho phiên bản JBoss 7 của bạn.

Tôi khuyên bạn nên làm như sau.

server certificate tự ký của bạn phải được nhập khẩu vào một truststore

keytool -import -alias gridserver -file server.crt -storepass $YOUR_PASSWORD_HERE -keystore server.keystore 

Thêm các thuộc tính sau để run.conf bạn

-Djavax.net.ssl.keyStoreType=pkcs12 
-Djavax.net.ssl.trustStoreType=jks 
-Djavax.net.ssl.keyStore=clientcertificate.p12 
-Djavax.net.ssl.trustStore=server.keystore 
-Djavax.net.debug=ssl # very verbose debug. Turn this off after everything looks good. 
-Djavax.net.ssl.keyStorePassword=$YOUR_PASSWORD_HERE 
-Djavax.net.ssl.trustStorePassword=$YOUR_PASSWORD_HERE 
+0

Các máy chủ chạy tốt thông qua một trình duyệt web như Chrome hoặc Firefox, vì vậy keystore trên máy chủ không phải là vấn đề. Chứng nhận không phải là một vấn đề, vì tôi chỉ đơn giản là bỏ qua tất cả các chứng chỉ. – Rsaesha

4

Thông báo thông tin bạn cung cấp là rất ít cũng như của bạn ngăn xếp dấu vết.
Tôi sẽ đoán ở đây.
Điều tôi nghi ngờ là trong máy chủ mới giao thức là TLSv1 trong khi khách hàng của bạn cố gắng kết nối với SSLv3 (hoặc ít hơn) và kết quả là việc bắt tay không thành công.

Thay đổi khách hàng của bạn để sử dụng phiên bản TLS hoặc
làm cho máy chủ web của bạn hỗ trợ SSLv3. Tôi biết làm thế nào để làm điều này trong Tomcat nhưng không phải trong JBoss.

Nếu cách này không hoạt động, hãy cập nhật bài đăng với nhiều thông tin hơn (và dấu vết ngăn xếp đầy đủ).
Bạn nên bật thông tin gỡ lỗi ssl -Djavax.net.debug=ssl

+0

Dấu vết ngăn xếp đầy đủ chỉ hiển thị phương thức kết nối của lớp của tôi và bất kỳ phương thức nào đều gọi đó. Đó là phương pháp tương tự đã được làm việc với các phiên bản trước của máy chủ. Dù sao, đây là gỡ lỗi: http://pastebin.com/RJqcQwaP Điều gì có vẻ hơi lạ với tôi là mặc dù tôi nói với chương trình của mình sử dụng TLS, có vẻ như muốn gửi tin nhắn chào khách hàng SSLv2 . – Rsaesha

+0

@Rsaesha: Đặt một số mã khách hàng vào bài đăng – Cratylus

0

Dấu vết ngăn xếp là từ mã máy khách và khách hàng của bạn 'Đã nhận được cảnh báo nghiêm trọng'. Nói cách khác, lỗi SSL xảy ra trong Jboss, không phải là khách hàng của bạn.

Máy chủ TrustManager tùy chỉnh phía khách hàng của bạn do đó không có gì để làm với nó. Dự đoán hoang dã của tôi là Jboss 7 mới của bạn được định cấu hình để yêu cầu chứng chỉ ứng dụng khách và khách hàng của bạn không có mặt.

Để gỡ lỗi kết nối SSL của bạn, sử dụng openssl và thử điều này:

openssl s_client -connect jboss.server.com:443

hoặc là nó là một máy chủ SSLv3

openssl s_client -connect jboss.server.com:443 -ssl3

này nên in rất nhiều thông tin thú vị.

+0

Đây là đầu ra của lệnh đầu tiên: http://pastebin.com/NvRqdu3f – Rsaesha

+0

Đoán hoang dã của tôi chỉ là, hoang dã. Máy chủ của bạn ổn. user384706 giúp bạn đi đúng hướng. Đây có thể là phiên bản giao thức không khớp. Tôi thấy máy chủ của bạn là TLSv1/SSLv3 và dường như bạn đang gửi SSLv2. –

0

Tôi nghĩ rằng điều này có liên quan đến một số Java 7 bug. Thật khó để chắc chắn nếu không có thêm chi tiết.

4

Điều này đã từng được giải quyết chưa?

Tôi đã có cùng một vấn đề chính xác, về cơ bản tôi đã nhận được một ngoại lệ bắt tay ngay sau clientHello. Vì vậy, Các chuỗi sự kiện là

  1. tôi sẽ xuất trình giấy của tôi đến máy chủ
  2. server imediately sẽ phản ứng với một thất bại bắt tay. (Tôi thậm chí sẽ không nhận được một máy chủ Xin chào lại).

Cuối cùng tôi thấy máy chủ yêu cầu thuật toán mã hóa/giải mã mạnh hơn so với những gì tôi đã cung cấp trong giai đoạn bắt tay ban đầu (Tức là Máy chủ và Máy chủ không thể đồng ý về thuật toán mã hóa lẫn nhau để sử dụng cho giao tiếp ssl).

Tôi cần cài đặt Java JCE không giới hạn (Chính sách mở rộng mã hóa Java). Có quy tắc xuất khẩu về việc sử dụng này, vì vậy nếu bạn gửi mã của bạn ở nước ngoài có thể có những tác động .. làm thế nào đây là những gì giải quyết vấn đề của tôi.

liên kết này giải thích làm thế nào để cài đặt các chính sách cập nhật http://suhothayan.blogspot.com/2012/05/how-to-install-java-cryptography.html

Đây cũng là một liên kết tuyệt vời mà đã giúp tôi hiểu chính xác những gì đang xảy ra https://support.f5.com/kb/en-us/solutions/public/15000/200/sol15292.html#id

này có thể hoặc không thể là vấn đề, nhưng khi bắt tay không thành công ngay sau client Xin chào, có vẻ như máy khách và máy chủ không thể đồng ý về điều gì đó (trong nhiều trường hợp các thuật toán mã hóa mà họ sẽ cần phải giao tiếp).

0

Đối với tôi Giải pháp là: System.setProperty("https.protocols", "TLSv1.1,TLSv1.2");

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