Java访问MySQL实现传输加密

背景

     最近研究了一下MySQL的JDBC传输加密,网上找了很多资料,写得不是很清楚,有疑问的地方也很多,特意研究了一下记录下来。
     MySQL服务端默认已开启SSL,可以通过查询have_ssl参数获取,对于JDBC客户端,若版本驱动版本为8.x可以直接通过添加JDBC参数useSSL=true,实现传输加密(驱动版本为5.x还是需要校验证书,配置证书地址,8.x已经是主流的驱动版本,可以不考虑5.x版本),但这种方式默认是不校验证书,使用的证书为MySQL安装时生成的自签名证书,客户端也可以通过开启证书校验,指定证书地址实现更高安全的数据传输,所以有两种方案:


方案一:在保证服务端开启SSL的情况下,添加JDBC参数useSSL=true,不校验证书(verifyServerCertificate默认就为false)实现加密传输。


方案二:在保证服务端开启SSL的情况下,添加JDBC参数useSSL=true,校验证书,并配置证书的文件位置。


1. 配置说明

1.1服务端配置

MySQL默认开启SSL,可通过下面的语句进行查询:

-- 查询服务端是否开启SSL,MySQL默认是启用的,YES启用,DISABLED禁用
SHOW VARIABLES LIKE '%have_ssl%';


若希望显示的启用服务端SSL,可修改mysql配置文件my.cnf,添加配置
 

#ssl=0为禁用,ssl=1为启用
[mysqld]
ssl=1


1.2客户端配置


方案一:启用SSL,不校验证书


该方案实现较简单,直接配置客户端开启SSL,不做证书校验。

public static void main(String[] args) {

    try {
        Class.forName("com.mysql.cj.jdbc.Driver");
        /**
         * 方案一:使用服务端的自签名证书,客户端不做校验,默认verifyServerCertificate=false
         */
        String url = "jdbc:mysql://169.254.57.111:3306/mysql?useSSL=true";
        String username="root";
        String password="root";
        Connection connection = DriverManager.getConnection(url,username,password);
        Statement statement = connection.createStatement();
        //查询当前会话是否使用了加密,若加密会返回加密算法,反之返回空
        String sql = "SHOW SESSION STATUS LIKE 'Ssl_cipher'";
        ResultSet resultSet = statement.executeQuery(sql);
        while(resultSet.next()){
            System.out.println("Variable_name="+resultSet.getString("Variable_name"));
            System.out.println("Value="+resultSet.getString("Value"));
        }
        resultSet.close();
        statement.close();
        connection.close();
    }catch (Exception e) {
        e.printStackTrace();
    }
}


方案二:启用SSL,校验证书


该方案实现较复杂,首先需要在MySQL服务器上生成证书,然后客户端开启SSL,开启证书校验,并配置证书地址。

证书生成
- 生成证书
#登录mysql服务器,进入/etc/mysql目录(也可以专为证书创建一个目录)
#生成证书密钥
openssl genrsa 2048 > ca-key.pem
#生成证书
openssl req -new -x509 -nodes -days 3600 -key ca-key.pem -out ca-cert.pem -subj "/C=CH/ST=CQ/L=CQ/O=test/OU=Go/CN=ca/emailAddress=test.com"

openssl req -newkey rsa:2048 -days 3600 -nodes -keyout server-key.pem -out server-req.pem -subj "/C=CH/ST=CQ/L=CQ/O=test/OU=Go/CN=Server/emailAddress=test.com"
#生成服务端密钥
openssl rsa -in server-key.pem -out server-key.pem
#生成服务端证书
openssl x509 -req -in server-req.pem -days 3600 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem

#验证证书是否正确
openssl verify -CAfile ca-cert.pem server-cert.pem

#查看证书的内容(例如,检查证书有效的日期范围,10年)
openssl x509 -text -in ca-cert.pem
openssl x509 -text -in server-cert.pem
#授权,必须是要做的,否则查看MySQL的日志会看到无法读取证书的错误。
chmod 755 /etc/mysql/*.pem   
chown mysql:mysql /etc/mysql/*.pem
#修改MySQL配置文件/etc/mysql/my.cnf,添加证书和密钥位置配置项
[mysqld]
ssl-ca=/etc/mysql/ca-cert.pem
ssl-cert=/etc/mysql/server-cert.pem
ssl-key=/etc/mysql/server-key.pem

 客户端配置

     将上一步中的MySQL服务器下载ca-cert.pom文件,我这里是下载到D盘下,执行命令将ca-cert.pem文件写入keystore文件,jdbc会直接访问这个文件。

keytool -importcert -alias MySQLCACert -file ca-cert.pem -keystore truststore.jks -storepass 123456


JDBC验证加密访问

public static void main(String[] args) {

    try {
        Class.forName("com.mysql.cj.jdbc.Driver");
   
        /**
         * 方案二:自己生成自签名证书,服务端做证书校验
         */
        String url = "jdbc:mysql://169.254.57.111:3306/mysql?useSSL=true&requireSSL=true&verifyServerCertificate=true"
                + "&trustCertificateKeyStoreUrl=file:D:/truststore.jks"
                + "&trustCertificateKeyStorePassword=123456";

        String username="root";
        String password="root";
        Connection connection = DriverManager.getConnection(url,username,password);
        Statement statement = connection.createStatement();
        //查询当前会话是否使用了加密,若加密会返回加密算法,反之返回空
        String sql = "SHOW SESSION STATUS LIKE 'Ssl_cipher'";

        ResultSet resultSet = statement.executeQuery(sql);
        while(resultSet.next()){
            System.out.println("Variable_name="+resultSet.getString("Variable_name"));
            System.out.println("Value="+resultSet.getString("Value"));
        }
        resultSet.close();
        statement.close();
        connection.close();
    }catch (Exception e) {
        e.printStackTrace();
    }
}


2. 验证结果


修改前,数据未加密


修改后,数据已加密

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值