【发布时间】:2011-06-07 11:26:59
【问题描述】:
如何使 MySQL JDBC 在 SSL 上工作(使用 X509 证书验证)?
我有 MySQL 手册中所述的自行创建的证书,在 Using SSL for Secure Connections 中,具体来说:
# Create CA certificate
shell> openssl genrsa 2048 > ca-key.pem
shell> openssl req -new -x509 -nodes -days 1000 \
-key ca-key.pem > ca-cert.pem
# Create server certificate
shell> openssl req -newkey rsa:2048 -days 1000 \
-nodes -keyout server-key.pem > server-req.pem
shell> openssl x509 -req -in server-req.pem -days 1000 \
-CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > server-cert.pem
# Create client certificate
shell> openssl req -newkey rsa:2048 -days 1000 \
-nodes -keyout client-key.pem > client-req.pem
shell> openssl x509 -req -in client-req.pem -days 1000 \
-CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > client-cert.pem
发出GRANT ALL ON *.* TO vic@localhost IDENTIFIED BY '12345' REQUIRE X509; 后,我可以通过命令行连接到 MySQL:
mysql -u vic -p --ssl-ca=ca-cert.pem --ssl-cert=client-cert.pem --ssl-key=client-key.pem mysql
...
mysql> SHOW STATUS LIKE 'Ssl_cipher';
+---------------+--------------------+
| Variable_name | Value |
+---------------+--------------------+
| Ssl_cipher | DHE-RSA-AES256-SHA |
+---------------+--------------------+
但是,当我尝试运行 Java 测试时,我得到验证失败:Access denied for user 'vic'@'localhost' (using password: YES)。代码如下:
public class Launcher {
public static void main(String[] args) throws DbException, SQLException, ClassNotFoundException {
StringBuffer sb = new StringBuffer("jdbc:mysql://localhost/bt?useSSL=true&");
sb.append("user=vic&password=12345&");
sb.append("clientCertificateKeyStorePassword=123456&");
sb.append("clientCertificateKeyStoreType=JKS&");
sb.append("clientCertificateKeyStoreUrl=file:///home/vic/tmp/client-keystore&");
sb.append("trustCertificateKeyStorePassword=123456&");
sb.append("trustCertificateKeyStoreType=JKS&");
sb.append("trustCertificateKeyStoreUrl=file:///home/vic/tmp/ca-keystore");
Class.forName("com.mysql.jdbc.Driver");
Connection c = DriverManager.getConnection(sb.toString());
Statement st = c.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM test_table");
while (rs.next()) {
System.out.println(rs.getInt("id"));
}
rs.close(); st.close(); c.close();
}
}
以下是我准备 Java 密钥库文件的方法:
keytool -import -alias mysqlServerCACert -file ca-cert.pem -keystore ca-keystore
keytool -import -file client-cert.pem -keystore client-keystore -alias client-key
更新如果我使用“root”用户而不是“vic”,我可以通过 JDBC 通过 SSL 进行连接。然后下面的代码
Statement st = c.createStatement();
ResultSet rs = st.executeQuery("SHOW STATUS LIKE 'Ssl_cipher';");
while (rs.next()) {
System.out.println(rs.getString(1));
System.out.println(rs.getString(2));
}
打印
Ssl_cipher
DHE-RSA-AES128-SHA
但是我不能在生产中使用 root,我想知道为什么 JDBC 使用 AES128,而命令行 mysql 客户端使用 AES256。
UPDATE2 在我将user 表中root@localhost 的ssl_type 更改为X509 后,请求客户端的完整身份验证,我得到的root 行为与vic 相同——可以'不通过 JDBC 登录。
UPDATE3 如果我在GRANT 语句中使用REQUIRE SSL 而不是REQUIRE X509,则代码有效。是否可以让 X509 工作?
【问题讨论】: