我正在尝试从Java Springboot应用程序连接到MySQL RDS DB。我已经对DB进行了必要的更改。
ALTER USER 'my_app'@'%' require SSL;
GRANT USAGE ON *.* TO 'my_app'@'%' REQUIRE SSL;
但是,连接不会发生。它在客户端身份验证部分失败。服务器(MySQL DB)无法验证客户端(Java应用程序)。
问题:
如何禁用客户端身份验证?根据文档,除非您"需要X509",否则该文档应被禁用。所以,我对此感到困惑。文档我引用的是:https://dev.mysql.com/doc/refman/8.0/en/alter-user.html。
使用密钥库和信托店如何进行此项工作?
更多信息:
我还将AWS根和区域证书导入了我的信任商店。此时(没有密钥库作为JVM传递),连接发生了。
但是,在我的应用程序中,我也需要使用一个密钥库。
-Djavax.net.ssl.keyStore=path/keyStore.jks
-Djavax.net.ssl.keyStorePassword=<keyStore_password>
当我这样做时,连接不会发生并且抛出以下错误:
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: unknown_ca
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
添加SSL握手调试,我看到以下日志:
*** CertificateRequest
Cert Types: RSA, DSS, ECDSA
Cert Authorities:
<Empty>
localhost-startStop-1, READ: TLSv1.1 Handshake, length = 4
*** ServerHelloDone
matching alias: mysqlrds
matching alias: client-nonprod
*** Certificate chain
chain [0] = [
看起来它在服务器(MySQL DB)试图验证客户端(Java应用程序)的部分失败。在以下步骤中,客户端(Java应用程序)需要向服务器(MySQL DB)提供证书。
在上面的步骤(CERTIFTATEREQUEST)中,服务器正在发送一个空的"证书权限"。这通常意味着服务器(MySQL DB)具有空的或不初始化的信任存储。之后的步骤(证书链),客户端(Java App)发送到服务器(MySQL DB)证书。在这种情况下," keystore_cert.jks"。但是服务器,不知道它,并且在握手上引发和错误。
示例代码:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
//1. Dowload my sql connector to a folder "jars". http://central.maven.org/maven2/mysql/mysql-connector-java/8.0.13/mysql-connector-java-8.0.13.jar
// This file and the jars folder are on the same folder (or level). Not inside one another.
//2. edit this file to have your settings. Name of the DB,URL,username,password,trustStore,keyStore,DB name, table name.
//3. compile the file: javac -cp ".:./jars/mysql-connector-java-8.0.13.jar" SampleCode.java
//4. run the program: java -cp ".:./jars/mysql-connector-java-8.0.13.jar" SampleCode
public class SampleCode {
public static void main(String[] args) {
Connection con;
try {
// TODO: replace with your settings.
System.setProperty("javax.net.ssl.trustStore", "path/resource/certs/trustStore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "trustStore_pass");
System.setProperty("javax.net.ssl.keyStore", "path/resource/certs/keyStore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "keyStore_pass");
System.setProperty("javax.net.debug", "ssl:handshake");
Class.forName("com.mysql.cj.jdbc.Driver");
// TODO: replace with your settings.
con = DriverManager.getConnection(
"jdbc:mysql://my_db_name.random_string.us-east-1.rds.amazonaws.com:3/my_db?useLegacyDatetimeCode=false&verifyServerCertificate=true&useSSL=true&requireSSL=true",
"my_app", "my_pass");
System.out.println(" connection successful n");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM my_table "); // TODO: replace with yours.
while (rs.next()) {
System.out.println("id : " + rs.getString("id"));
}
rs.close();
stmt.close();
con.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
参考材料:
- https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-using-ssl.html
- https://bugs.mysql.com/bug.php?id=91969
我在使用冬眠的应用程序中遇到了相同的错误。显然,RDS仅在SSL握手期间对客户端认证。而不是禁用客户端身份验证,因为您需要为应用程序使用单独的密钥存储,而是可以通过连接属性覆盖用于JDBC连接的密钥存储。
- 遵循"更新您的应用程序信任商店"部分中提到的步骤。在https://docs.aws.amazon.com/amazonrds/latest/userguide/ssl-certificate-rotation-mysql.html获取将用于RDS连接的客户端密钥库。
- 在您的示例代码中添加以下代码:
Properties properties = new Properties();
properties.put("user", "my_app");
properties.put("password", "my_pass"); properties.put("clientCertificateKeyStoreUrl","file:path_to_rds_truststore_file");
properties.put("clientCertificateKeyStorePassword","password");
String url = "jdbc:mysql://localhost/mydatabase";
Connection con = DriverManager.getConnection(url, properties);
通过执行以上操作,您可以覆盖将用于在使用单独的系统宽密钥库时建立与RDS连接的密钥库。请注意,您需要每次要与RDS实例连接时设置属性。
如您的参考:
中所述请注意,当一起使用时,连接属性覆盖了其他两种方法设置的值。另外,仅在该连接中使用的任何具有连接属性的值,而使用系统范围值设置的值则用于所有连接(除非连接属性覆盖)。
>