java - 使用 Java 与 MySQL 服务器的 SSL 连接

标签 java mysql ssl jdbc truststore

我正在尝试通过 SSL 使用 Java 连接到 MySQL 服务器。我收到以下异常:

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Cannot connect to MySQL server on www.mysite.com:3306.

Make sure that there is a MySQL server running on the machine/port you are trying to connect to and that the machine this software is running on is able to connect to this host/port (i.e. not firewalled). Also make sure that the server has not been started with the --skip-networking flag.

at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:407)
at com.mysql.jdbc.Util.getInstance(Util.java:382)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1013)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:987)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:982)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:927)
at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:827)
at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:47)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:407)
at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:378)
at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:305)
at java.sql.DriverManager.getConnection(Unknown Source)
at java.sql.DriverManager.getConnection(Unknown Source)
at java.lang.Thread.run(Unknown Source)

Caused by: java.lang.UnsupportedOperationException: The method shutdownInput() is not supported in SSLSocket
at sun.security.ssl.BaseSSLSocketImpl.shutdownInput(Unknown Source)
at com.mysql.jdbc.MysqlIO.forceClose(MysqlIO.java:506)
at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2404)
at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2163)
at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:794)
... 25 more

这是我的代码:

properties = new Properties();
properties.put("user", "myuser");
properties.put("password", "mypassword");
properties.put("useSSL", "true");
System.setProperty("javax.net.ssl.keyStore", "keystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "keystorepass");
System.setProperty("javax.net.ssl.trustStore", "truststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "truststorepass");
connection = DriverManager.getConnection("jdbc:mysql://www.mysite.com:3306/mydatabase", properties);

详情

创建 keystore 和信任库

我生成的 keystore 和信任库如下:

openssl pkcs12 -export -inkey client-key.pem -in client-cert.pem > keystore.p12
keytool -importkeystore -srckeystore keystore.p12 -srcstoretype pkcs12 -destkeystore keystore.jks -deststoretype JKS

openssl x509 -outform der -in ca.pem -out ca.der
keytool -import -file ca.der -alias myCA -keystore truststore.jks

原始证书

这是我的证书列表:

  • ca.pem
  • 客户端 key .pem
  • 客户端证书.pem
  • 服务器 key .pem
  • 服务器证书.pem

不使用 SSL 连接

下面的代码工作正常,只是为了演示我可以用 Java 连接到 MySQL 服务器:

properties = new Properties();
properties.put("user", "myuser");
properties.put("password", "mypassword");
connection = DriverManager.getConnection("jdbc:mysql://www.mysite.com:3306/mydatabase", properties);

在命令行上使用 MySQL 时可以通过 SSL 连接

我使用以下命令启动 MySQL 服务器:

mysqld --ssl-ca=ca.pem --ssl-cert=server-cert.pem --ssl-key=server-key.pem

然后我使用 MySQL 命令连接到它:

mysql --host=www.mysite.com --user=myuser --password=mypassword --database=mydatabase --ssl-ca=ca.pem --ssl-cert=client-cert.pem --ssl-key=client-key.pem

这是有效的,在查询 SHOW STATUS LIKE 'Ssl_cipher' 之后,我得到了正确的结果:

+---------------+--------------------+
| Variable_name | Value              |
+---------------+--------------------+
| Ssl_cipher    | DHE-RSA-AES256-SHA |
+---------------+--------------------+

最佳答案

如果您遇到此问题,至少要确保您的 CA 证书已导入到 JRE 的 keystore 中!

keytool -import -noprompt -trustcacerts -alias -file ca.pem -keystore

(您可能需要将“ca.pem”文件的名称更改为您自己的 CA 证书文件名)

请记住让 保持独特。 此外,更改 以使其与 JVM 的路径相匹配。请注意,这很可能是最高版本的 JRE,但也可能是 SDK 的 JRE 或已安装的不同 JRE(例如“C:\Program Files\Java\jre1.8.0_25\lib\security\cacerts” )

您需要为 JVM 信任库输入密码:此密码始终为“changeit”。

我不能保证这会解决问题,但这是我在解决这个问题时迈出的重要一步,我最终成功了。

关于java - 使用 Java 与 MySQL 服务器的 SSL 连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33189395/

相关文章:

mysql - "Can' t 连接到本地 MySQL 服务器”在 docker-compose 中

web-services - 解释 : The underlying connection was closed: The connection was closed unexpectedly

python - FTPSHook Airflow(数据通道需要 522 SSL/TLS)

ssl - https 连接中未使用 Cloudflare 证书

java - windows下修改java环境变量的方法

java - ArrayList 排序时出现 NullPointer

java - c3p0 - maxIdleTime 配置

php - Pear DB_DataObject 和输入清理

php - 在 PHP 中使用循环将项目插入 SQL 表中

java - 如何处理服务器未启用 SSL/TLS 但客户端在 Java 中启用了 SSL/TLS 的负面测试用例