首页 文章

带有APR连接器的Tomcat正在使用SSL断开Java客户端

提问于
浏览
1

我正在尝试使用SSL与Tomcat和APR连接器 . 我可以对服务器进行更改,但不能对现有的Java客户端进行更改 .

出于某种原因,只要Java客户端使用SSL连接到Tomcat服务器,就无法连接 - 服务器会重置连接 . 但是,完全相同的Java代码可以连接到Apache使用SSL托管的不同端口上的同一服务器 . 此外,非Java代码(如curl)可以连接到Tomcat SSL连接 .

我通过强制Java客户端使用TLSv1协议(-Dhttps.protocols = TLSv1)来实现这一点 . 但是,这不是一个实用的解决方案,因为我目前无法为Java客户端发布更新 .

由于这适用于服务器上的Apache,在我看来,我应该能够在服务器上进行某种配置更改,以便与Tomcat一起使用,而无需更改Java客户端 .

总结:Java连接到Tomcat SSL = FAIL

卷曲连接到Tomcat SSL =好

Java连接到Apache SSL =好

卷曲连接到Apache SSL =好

下面是一些示例Java代码,用于说明问题 . 我在Mac OS X上运行Java 6 .

public class SSLConnectTest {
    public static void main(String[] args) throws Exception {
        System.setProperty( "javax.net.debug", "all" );

        testConnection( "https://secure2.360works.com" ); //Apache running SSL. This works.
        testConnection( "https://secure2.360works.com:8443/" ); //Tomcat running SSL and APR. This fails.
    }

    private static void testConnection( String urlString ) throws IOException {
        new URL( urlString ).openStream().close();
    }
}

以下是SSL握手中发生的情况:

trigger seeding of SecureRandom
done seeding SecureRandom
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
%% No cached client session
*** ClientHello, TLSv1
RandomCookie:  GMT: 1377233856 bytes = { 69, 128, 29, 114, 252, 186, 13, 192, 212, 243, 179, 208, 124, 196, 220, 137, 23, 124, 30, 226, 98, 148, 243, 6, 188, 230, 109, 119 }
Session ID:  {}
Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
***
main, WRITE: TLSv1 Handshake, length = 81
main, WRITE: SSLv2 client hello message, length = 110
main, handling exception: java.net.SocketException: Connection reset
main, SEND TLSv1 ALERT:  fatal, description = unexpected_message
main, WRITE: TLSv1 Alert, length = 2
main, Exception sending alert: java.net.SocketException: Broken pipe
main, called closeSocket()
Disconnected from the target VM, address: '127.0.0.1:62146', transport: 'socket'
Exception in thread "main" java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:168)
    at com.sun.net.ssl.internal.ssl.InputRecord.readFully(InputRecord.java:422)
    at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:460)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:863)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1188)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1215)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1199)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1172)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
    at java.net.URL.openStream(URL.java:1010)
    at com.prosc.license.client.network.SSLConnectTest.testConnection(SSLConnectTest.java:22)
    at com.prosc.license.client.network.SSLConnectTest.main(SSLConnectTest.java:18)

这是server.xml中的连接器配置 . 我希望这里的一些改变能解决问题:

<Connector port="8443" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
sslProtocol="SSLv2+TLSv1+SSLv3"
SSLHonorCipherOrder="true"
protocol="org.apache.coyote.http11.Http11AprProtocol"
clientAuth="false" SSLCertificateFile="/etc/apache2/ssl.crt/secure2.360works.com.crt"
SSLCertificateKeyFile="/etc/apache2/ssl.crt/secure2.360works.com.key"
SSLCertificateChainFile="/etc/apache2/ssl.crt/secure2.360works.com.chcrt" />

1 回答

  • 3

    main,WRITE:TLSv1握手,长度= 81
    main,WRITE:SSLv2客户端问候消息,长度= 110

    我认为这是来自Java 6环境(除非客户端明确启用了 SSLv2Hello 协议) . 您是否尝试在Java 7 JRE(doesn't enable SSLv2Hello by default)上运行时查看客户端是否能够连接 .

    我猜这个问题的发生是因为APR连接器可能不喜欢接收SSLv2客户端Hello(来自Java,实际上不是SSLv2客户端Hello,而是包含在v2中的v3,请参阅EJP's answer) .

    一些可能解决此问题的建议:

    • 尝试使APR接受SSLv2连接,至少SSLv3或以上包含在v2 Hello中 . (使用SSLv2 isn 't a good idea, but the SSLv2Hello with SSLv3/TLS shouldn'是个问题 . )

    • 在Apache Tomcat中切换APR以获得纯Java连接器(BIO或NIO,请参阅comparative table) . 您可能需要将证书和密钥转换为密钥库,但这不应该太困难,特别是在 PKCS12 密钥库中 .

相关问题