A força do MySQL JDBC ignora o certificado do cliente no AWS RDS

5

Eu tenho um aplicativo da Web Java em execução na AWS e conexão com um banco de dados MySQL em execução no AWS RDS.

Meu aplicativo usa certificados de cliente SSL assinados por nossa própria CA para se conectar a vários serviços da Web, por isso, defini as propriedades do sistema -Djavax.net.ssl.keyStore e -Djavax.net.ssl.trustStore .

Eu adicionei os certificados https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.pem ao meu trustStore , e eu posso conectar-me ao MySQL bem usando SSL através do cliente de linha de comando.

Minha string de conexão do MySQL é semelhante a:

jdbc:mysql://my-server-id.eu-west-1.rds.amazonaws.com/my-database?verifyServerCertificate=true&useSSL=true&requireSSL=true

Estou usando mysql:mysql-connector-java:jar:5.1.38 para executar a conexão JBDC.

Descobri que meu aplicativo Java pode conectar OK ao MySQL quando eu configuro o trustStore , mas ele falha quando defino o keyStore e o trustStore :

! javax.net.ssl.SSLException: Unsupported record version Unknown-0.0
! at sun.security.ssl.InputRecord.checkRecordVersion(InputRecord.java:552) ~[na:1.8.0_91]
! at sun.security.ssl.InputRecord.readV3Record(InputRecord.java:565) ~[na:1.8.0_91]
! at sun.security.ssl.InputRecord.read(InputRecord.java:532) ~[na:1.8.0_91]
! at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973) ~[na:1.8.0_91]
! at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375) ~[na:1.8.0_91]
! at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403) ~[na:1.8.0_91]
! at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387) ~[na:1.8.0_91]
! at com.mysql.jdbc.ExportControlled.transformSocketToSSLSocket(ExportControlled.java:149) ~[user-portal-web-0.0.1.jar:0.0.1]
! ... 40 common frames omitted

Parece que o Java está apresentando meu certificado de cliente com assinatura privada da CA para o MySQL, que está rejeitando-o. Capturei a interação usando tcpdump e o DN do meu certificado de cliente está sendo enviado para o MySQL.

Como posso usar meu certificado de cliente para conexões HTTPS, mas não usá-lo para a conexão MySQL?

Eu tentei criar um keystore vazio e definir minha string de conexão para usá-lo:

jdbc:mysql://my-server-id.eu-west-1.rds.amazonaws.com/my-database?verifyServerCertificate=true&useSSL=true&requireSSL=true&clientCertificateKeyStoreUrl=file:nokeys.jks&clientCertificateKeyStorePassword=changeit

Isso me dá o seguinte erro:

java.lang.IllegalStateException: TrustManagerFactoryImpl is not initialized
    at sun.security.ssl.TrustManagerFactoryImpl.engineGetTrustManagers(TrustManagerFactoryImpl.java:100)
    at javax.net.ssl.TrustManagerFactory.getTrustManagers(TrustManagerFactory.java:285)
    at com.mysql.jdbc.ExportControlled.getSSLSocketFactoryDefaultOrConfigured(ExportControlled.java:323)
    at com.mysql.jdbc.ExportControlled.transformSocketToSSLSocket(ExportControlled.java:85)
    
por Rich 04.07.2016 / 12:28

1 resposta

4

Você pode forçar o MySQL a não usar nenhum certificado de cliente configurando um keystore vazio na URL de conexão.

O problema que tive acima foi uma variante do link - se você definir "clientCertificateKeyStoreUrl" em a URL de conexão, mas não também "trustCertificateKeyStoreUrl" (e os outros 4 parâmetros abaixo), então o MySQL irá travar com "TrustManagerFactoryImpl não foi inicializado" ao invés de um erro mais útil.

Você pode criar um armazenamento de chaves vazio com um comando como:

keytool -genkey -alias foo -keystore empty.jks # (set password "changeit")
keytool -delete -alias foo -keystore empty.jks

Em seguida, conecte-se ao MySQL com um URL como:

jdbc:mysql://my-server-id.rds.amazonaws.com/my-database?verifyServerCertificate=true&useSSL=true&requireSSL=true&clientCertificateKeyStoreUrl=file:empty.jks&clientCertificateKeyStorePassword=changeit&clientCertificateKeyStoreType=JKS&trustCertificateKeyStoreUrl=file:/etc/pki/cosmos/current/client.jks&trustCertificateKeyStoreType=JKS&trustCertificateKeyStorePassword=changeit

Todos os 6 argumentos keystore são necessários, mesmo se você quiser os padrões, caso contrário, você verá o erro "TrustManagerFactoryImpl não foi inicializado"

    
por 06.07.2016 / 09:07