java - extended server_name (SNI Extension) 不是用jdk1.8.0发送而是用jdk1.7.0发送

标签 java web-services ssl cxf sni

我已经使用 ApacheCXF (v3.0.4) 实现了一个 JAX-WS 客户端,并且一切正常,但是当我想对 java 8 (jdk1.8.0_25) 使用安全连接 (SSL/TLS) 时,问题就来了。

我在日志中看到以下异常 (-Djavax.net.debug=all):

main, handling exception: java.net.SocketException: Connection reset
main, SEND TLSv1.2 ALERT:  fatal, description =    unexpected_message
main, WRITE: TLSv1.2 Alert, length = 2
main, Exception sending alert: java.net.SocketException: Connection reset by peer: socket write error

经过深入分析后,我发现问题是由于 Java 8 未发送 server_name (SNI) 但 Java 7 已发送且 Web 服务调用成功。

Java 8 日志 (-Djavax.net.debug=all): 缺少“Extension server_name”

[...]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSA
***
[...]

Java 7 日志 (-Djavax.net.debug=all)(有效):“Extension server_name”已设置

[...]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSA
Extension server_name, server_name: [host_name: testeo.hostname.es]
***
[...]

据观察,在 Java 7 中设置了扩展服务器名称,服务器名称:[主机名称:testeo.hostname.es],然后网络服务调用成功。

为什么 Java 8 不像 Java 7 那样设置 server_name?是 Java 配置问题吗?

最佳答案

如前所述,原因与使用 setHostnameVerifier() 破坏 SNI(扩展服务器名称)的 JDK 错误有关。 https://bugs.openjdk.java.net/browse/JDK-8144566

我们的解决方法: 测试后,我们发现将连接的 SSLSocketFactory 设置为几乎任何默认值似乎都可以解决问题。

这不起作用: HttpsURLConnection.setSSLSocketFactory((SSLSocketFactory) SSLSocketFactory.getDefault());

这确实有效: HttpsURLConnection.setSSLSocketFactory(new SSLSocketFactoryFacade());

因此,要为 JAX-WS 客户端修复它,您可以这样做: bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", new SSLSocketFactoryFacade());

我们的 SSLSocketFactory facade:(注意它实际上什么都不做)

public class SSLSocketFactoryFacade extends SSLSocketFactory {

    SSLSocketFactory sslsf;

    public SSLSocketFactoryFacade() {
        sslsf = (SSLSocketFactory) SSLSocketFactory.getDefault();;
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return sslsf.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return sslsf.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException {
        return sslsf.createSocket(socket, s, i, b);
    }

    @Override
    public Socket createSocket(String s, int i) throws IOException, UnknownHostException {
        return sslsf.createSocket(s, i);
    }

    @Override
    public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException, UnknownHostException {
        return sslsf.createSocket(s, i, inetAddress, i1);
    }

    @Override
    public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
        return createSocket(inetAddress, i);
    }

    @Override
    public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException {
        return createSocket(inetAddress, i, inetAddress1, i1);
    }
}

关于java - extended server_name (SNI Extension) 不是用jdk1.8.0发送而是用jdk1.7.0发送,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30817934/

相关文章:

java - openbsd:从 .tar 或 .deb 安装程序

java - 选择了 noSelectionOption 的 Primefaces SelectOneRadio

java - 运行 web 服务 eclipse - apache tomcat 8

c# - SSL 上的 WCF 服务无法使用权​​限 'test-service.hostname.com' 为 SSL/TLS 建立安全通道

Java 正则表达式不匹配(俄语)

java - 将对象转换为字符串后存储在 hashMap 中

android - 在android中实现REST web服务的代码问题

database - 如何知道 WCF DataContract 代表持久实体还是 transient 实体?

java - JVM 忽略证书名称不匹配

java - SSL/双向 SSL 通信问题