我今天从 Java 1.6 升级到 Java 1.7。 从那时起,当我尝试通过 SSL 与我的网络服务器建立连接时出现错误:
javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name
at sun.security.ssl.ClientHandshaker.handshakeAlert(ClientHandshaker.java:1288)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1904)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1027)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1262)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1289)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1273)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:523)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1296)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
at java.net.URL.openStream(URL.java:1035)
代码如下:
SAXBuilder builder = new SAXBuilder();
Document document = null;
try {
url = new URL(https://some url);
document = (Document) builder.build(url.openStream());
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(DownloadLoadiciousComputer.class.getName()).log(Level.SEVERE, null, ex);
}
它只是一个测试项目,这就是为什么我允许并在代码中使用不受信任的证书:
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
Logger.getLogger(DownloadManager.class.getName()).log(Level.SEVERE, null, e);
}
我成功尝试连接到 https://google.com . 我的错在哪里?
谢谢。
最佳答案
Java 7 引入了默认启用的 SNI 支持。我发现某些配置错误的服务器在 SSL 握手中发送了“无法识别的名称”警告,大多数客户端都忽略了这个警告……Java 除外。如@Bob Kerns提到,Oracle 工程师拒绝“修复”这个错误/功能。
作为解决方法,他们建议设置 jsse.enableSNIExtension
属性。要让您的程序无需重新编译即可运行,请将您的应用程序运行为:
java -Djsse.enableSNIExtension=false yourClass
也可以在 Java 代码中设置该属性,但必须在任何 SSL 操作之前设置。加载 SSL 库后,您可以更改属性,但它是 won't have any effect on the SNI status .要在运行时禁用 SNI(具有上述限制),请使用:
System.setProperty("jsse.enableSNIExtension", "false");
设置此标志的缺点是 SNI 在应用程序的任何地方都被禁用。为了利用 SNI 并仍然支持配置错误的服务器:
- 使用您要连接的主机名创建一个
SSLSocket
。我们将其命名为sslsock
。 - 尝试运行
sslsock.startHandshake()
。这将阻塞直到完成或在错误时引发异常。每当startHandshake()
发生错误时,获取异常消息。如果它等于handshake alert: unrecognized_name
,那么你发现了一个配置错误的服务器。 - 当您收到
unrecognized_name
警告(在 Java 中为致命)时,重试打开SSLSocket
,但这次没有主机名。这有效地禁用了 SNI(毕竟,SNI 扩展是关于向 ClientHello 消息添加主机名)。
对于 Webscarab SSL 代理,this commit实现后备设置。
关于java - SSL 握手警报 : unrecognized_name error since upgrade to Java 1. 7.0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7615645/