SSLv3協議、TLSv1.2協議配置不對導致javax.ws.rs.ProcessingException: java.net.SocketException: Connection reset


SSl:Secure Sockets Layer 安全套接層

TLS:Transport Layer Security傳輸層安全

是為網絡通信提供安全及數據完整性的一種安全協議。TLS與SSL在傳輸層對網絡連接進行加密。(見百度)

場景描述:將公司請求第三方公司的接口協議由http改成https后,出現了請求套接字異常的情況,第三方公司也收不到具體的請求,具體異常如下,

javax.ws.rs.ProcessingException: java.net.SocketException: Connection reset
at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:287)
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:252)
at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:684)
at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:681)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:681)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:411)
at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:311)
at com.baoxian.payment.UnionPayPayment.request(UnionPayPayment.java:323)
...

Caused by: java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:209)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
at sun.security.ssl.InputRecord.read(InputRecord.java:503)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1513)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:338)
at org.glassfish.jersey.client.internal.HttpUrlConnector._apply(HttpUrlConnector.java:394)
at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:285)
... 66 more

實現http協議的代碼為:

 1 import java.security.SecureRandom;
 2 import java.security.cert.X509Certificate;
 3 
 4 import javax.net.ssl.HostnameVerifier;
 5 import javax.net.ssl.SSLContext;
 6 import javax.net.ssl.SSLSession;
 7 import javax.net.ssl.TrustManager;
 8 import javax.net.ssl.X509TrustManager;
 9 import javax.ws.rs.client.Client;
10 import javax.ws.rs.client.ClientBuilder;
11 
12 import org.apache.commons.logging.Log;
13 import org.apache.commons.logging.LogFactory;
14 
15 public class ClientUtil {
16     private static Log log = LogFactory.getLog(ClientUtil.class);
17     private static SSLContext sslContext = null;
18     private static HostnameVerifier hv = null;
19     public static Client sslClient = null;
20     public static Client client = null;
21     static{
22         client = ClientBuilder.newClient();
23         try {
24             sslContext = SSLContext.getInstance("SSLv3");
25             sslContext.init(null, new TrustManager[] { new X509TrustManager() {
26                 public X509Certificate[] getAcceptedIssuers() {
27                     return new X509Certificate[0];
28                 }
29 
30                 public void checkClientTrusted(X509Certificate[] certs, String authType) {
31                 }
32 
33                 public void checkServerTrusted(X509Certificate[] certs, String authType) {
34                 }
35             } }, new SecureRandom());
36         } catch (Exception e) {
37             log.error("SSL失敗", e);
38         }
39         hv = new HostnameVerifier() {
40             public boolean verify( String arg0, SSLSession arg1 ) { return true; }
41         };
42         sslClient = ClientBuilder.newBuilder().hostnameVerifier(hv).sslContext(sslContext).build();
43     }
44 }

調用ClientUtil類的代碼

1         url = url + "?data=" + URLEncoder.encode(jsonObject.toJSONString(), "UTF-8");
2         log.info("銀聯請求: type: " + transType + ", URL:" + url);
3         4 
5         Response response = ClientUtil.client.
.target(url) 7 .request() 8 .get();

這里的代碼寫死了只能用SSLv3安全協議,一運行的時候就報連接錯誤。可是,同樣的請求放到google瀏覽器上請求就可以通過。

把請求復制到google瀏覽器請求欄,按F12,點擊enter鍵,查看Security菜單欄輸出的網頁內容,發現這個請求接受TLS1.2安全協議


為了不影響其它類使用SSL協議,對這個類進行重寫。重寫后類,新增了獲取制定安全協議的方法,支持指定安全協議的請求。
 1 import java.security.SecureRandom;
 2 import java.security.cert.X509Certificate;
 3 
 4 import javax.net.ssl.HostnameVerifier;
 5 import javax.net.ssl.SSLContext;
 6 import javax.net.ssl.SSLSession;
 7 import javax.net.ssl.TrustManager;
 8 import javax.net.ssl.X509TrustManager;
 9 import javax.ws.rs.client.Client;
10 import javax.ws.rs.client.ClientBuilder;
11 
12 import org.apache.commons.logging.Log;
13 import org.apache.commons.logging.LogFactory;
14 
15 public class ClientUtil {
16     private static Log log = LogFactory.getLog(ClientUtil.class);
17     private static SSLContext sslContext = null;
18     private static HostnameVerifier hv = null;
19     public static Client sslClient = null;
20     public static Client client = null;
21     private static TrustManager simpleTrust=null;
22     static{
23         client = ClientBuilder.newClient();
24         try {
25             sslContext = SSLContext.getInstance("SSLv3");
26             simpleTrust=new X509TrustManager() {
27                 public X509Certificate[] getAcceptedIssuers() {
28                     return new X509Certificate[0];
29                 }
30 
31                 public void checkClientTrusted(X509Certificate[] certs, String authType) {
32                 }
33 
34                 public void checkServerTrusted(X509Certificate[] certs, String authType) {
35                 }
36             };
37             sslContext.init(null, new TrustManager[] { simpleTrust}, new SecureRandom());
38         } catch (Exception e) {
39             log.error("SSL失敗", e);
40         }
41         hv = new HostnameVerifier() {
42             public boolean verify( String arg0, SSLSession arg1 ) { return true; }
43         };
44         sslClient = ClientBuilder.newBuilder().hostnameVerifier(hv).sslContext(sslContext).build();
45     }
46 
47     public static Client getSslClient(String protocol)
48     {
49         try {
50             SSLContext sslContextTmp= SSLContext.getInstance(protocol);
51             sslContextTmp.init(null, new TrustManager[] { simpleTrust}, new SecureRandom());
52             return ClientBuilder.newBuilder().hostnameVerifier(hv).sslContext(sslContextTmp).build();
53         }
54         catch (Exception ex)
55         {
56             return ClientBuilder.newBuilder().hostnameVerifier(hv).sslContext(sslContext).build();
57         }
58     }
59 }

 

改正后的調用方法

1         url = url + "?data=" + URLEncoder.encode(jsonObject.toJSONString(), "UTF-8");
2 
3         Response response = ClientUtil.getSslClient("TLSv1.2")
4                 .target(url)
5                 .request()
6                 .get();

 

說明:不同第三方公司支持https協議的時候可以用不同安全協議,對於不同的情況要予以考慮。

 

 

 

 
        

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM