Java 7引入了默认情况下启用的SNI支持。我发现某些配置错误的服务器会在SSL握手中发送“无法识别的名称”警告,大多数客户端会忽略此警告… Java除外。如@Bob Kerns所述,Oracle工程师拒绝“修复”此错误/功能。
解决方法是,他们建议设置
jsse.enableSNIExtension属性。要使你的程序无需重新编译即可运行,请按以下方式运行你的应用程序:
java -Djsse.enableSNIExtension=false yourClass
也可以在Java代码中设置该属性,但是必须在任何SSL操作之前设置该属性。加载SSL库后,你可以更改属性,但不会对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消息中添加主机名)。



