首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Java SSL 連線錯誤:handshake alert: unrecognized_name 解決方案

     編輯:程式設計綜合問答

錯誤堆疊

javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name
 at sun.security.ssl.ClientHandshaker.handshakeAlert(...)

根本原因

JDK 7+ 預設開啟 **SNI (Server Name Indication)** 延伸。Client Hello 會攜帶目標主機名。若伺服器的 SSL 憑證不包含該主機名(或虛擬主機配置錯誤),伺服器會回傳 unrecognized_name 致命警告,導致握手失敗。

解決方案(按推薦順序)

1. 修正伺服器端配置(根治)

  • 確保憑證的 Subject Alternative Name (SAN) 包含所有服務域名。
  • Nginx/Apache/Tomcat 正確配置 server_name / Host 對應的憑證。
  • 這是**最正確、最安全**的做法。

2. 客戶端關閉 SNI(繞過,僅供測試/舊系統)

// 必須在建立連線前設置,全局生效
System.setProperty("jsse.enableSNIExtension", "false");

⚠️ **副作用**:無法正確訪問共用 IP 的多域名 HTTPS 站點(虛擬主機失效)。

3. 代碼層面指定 HostnameVerifier(精細控制)

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier((hostname, session) -> true); // 僅測試用,生產嚴禁!

4. 使用自定義 SSLSocketFactory 忽略 SNI

SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[]{new X509TrustManager(){...}}, null);
HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());
// 在自定義 SSLSocketFactory.createSocket() 中不傳遞 host 參數

你的代碼問題

System.setProperty("jsse.enableSNIExtension", "false"); // 位置錯!必須在 URL.openConnection() 之前
URL url = new URL(strURL);
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();

✅ 正確位置:

System.setProperty("jsse.enableSNIExtension", "false"); // 最早,main 開頭或靜態區塊
URL url = new URL(strURL);
// ...

排查清單

  1. 用 openssl s_client -connect host:443 -servername host 驗證伺服器憑證 SAN。
  2. 確認 JDK 版本(JDK 7u25+ 預設開啟 SNI)。
  3. 若無法控制伺服器,臨時關閉 SNI 或用 HTTP Client 庫(OkHttp/Apache HttpClient)自定義 SSL 參數。

總結

unrecognized_name 99% 是**伺服器憑證缺少 SAN**或**虛擬主機配置錯**。優先修伺服器;實在不行,在**建立連線前**全局關閉 SNI,但要承擔虛擬主機失效風險。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved