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 致命警告,導致握手失敗。
server_name / Host 對應的憑證。// 必須在建立連線前設置,全局生效
System.setProperty("jsse.enableSNIExtension", "false");
⚠️ **副作用**:無法正確訪問共用 IP 的多域名 HTTPS 站點(虛擬主機失效)。
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier((hostname, session) -> true); // 僅測試用,生產嚴禁!
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);
// ...
openssl s_client -connect host:443 -servername host 驗證伺服器憑證 SAN。unrecognized_name 99% 是**伺服器憑證缺少 SAN**或**虛擬主機配置錯**。優先修伺服器;實在不行,在**建立連線前**全局關閉 SNI,但要承擔虛擬主機失效風險。