更新时间:2024-05-07 GMT+08:00

连接数据库(以SSL方式)

用户通过JDBC连接GaussDB服务器时,可以通过开启SSL加密客户端和服务器之间的通讯,为敏感数据在Internet上的传输提供了一种安全保障手段。

本节主要介绍应用程序通过JDBC如何采用SSL的方式对客户端进行配置(服务端配置请联系管理员)。

在使用本节所描述的方法前,默认用户已经获取了服务端和客户端所需要的证书和私钥文件,关于证书等文件的获取请参见Openssl相关文档和命令 。

客户端配置

不同于基于gsql的程序,JDBC默认支持服务证书确认,如果用户使用一个由认证中心(CA,全球CA或区域CA)签发的证书,则java应用程序不需要做什么,因为java拥有大部分认证中心签发的证书的拷贝。如果用户使用的是自签的证书,则需要配置客户端程序,使其可用,此过程依赖于openssl工具以及java自带的keytool工具,配置步骤如下:

如果使用内置证书,以下步骤有效。

  1. 在客户端机器上,上传证书文件。

    1. 以普通用户登录客户端机器。
    2. 创建“/tmp/cacert”目录。
      mkdir /tmp/cacert
    3. 将根证书文件以及客户端证书和私钥文件放入所创建的目录下。

  2. 将根证书导入到trustStore中。

    openssl x509 -in cacert.pem -out cacert.crt.der -outform der

    生成中间文件cacert.crt.der。

    keytool -keystore mytruststore -alias cacert -import -file cacert.crt.der

    请用户根据提示信息输入口令,此口令为truststorepassword,例如xxxxxxxxx,从而生成mytruststore。

    • cacert.pem为根证书。
    • cacert.crt.der为中间文件。
    • mytruststore为生成的密钥库名称,此名称以及别名,用户可以根据需要进行修改。

  3. 将客户端证书和私钥导入到keyStore中。

    openssl pkcs12 -export -out client.pkcs12 -in client.crt -inkey client.key   

    请用户根据提示信息输入clientkey,例如xxxxxxxxx,从而生成client.pkcs12。

    keytool -importkeystore -deststorepass xxxxxxxxxxx -destkeystore client.jks -srckeystore client.pkcs12 -srcstorepass xxxxxxxxx -srcstoretype PKCS12 -alias 1 -destkeypass xxxxxxxxx

    此处deststorepass与destkeypass需保持一致,srcstorepass需与上条命令中的export password保持一致。生成client.jks。

示例1 使用NonValidatingFactory通道

示例1和示例2选择其一即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 认证用的用户名和密码直接写到代码中有很大的安全风险,建议在配置文件或者环境变量中存放(密码应密文存放,使用时解密),确保安全;
// 本示例以用户名和密码保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量(环境变量名称请根据自身情况进行设置)EXAMPLE_USERNAME_ENV和EXAMPLE_PASSWORD_ENV。
public class SSL{
    public static void main(String[] args) {
        Properties urlProps = new Properties();
        String urls = "jdbc:postgresql://$ip:$port/postgres";
        String userName = System.getenv("EXAMPLE_USERNAME_ENV");
        String password = System.getenv("EXAMPLE_PASSWORD_ENV");

        urlProps.setProperty("sslfactory","org.postgresql.ssl.NonValidatingFactory");
        urlProps.setProperty("user", userName);
        urlProps.setProperty("password", password);
        urlProps.setProperty("ssl", "true");
        

        try {
            Class.forName("org.postgresql.Driver").newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            Connection conn;
            conn = DriverManager.getConnection(urls,urlProps);
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

示例2 使用证书

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// 认证用的用户名和密码直接写到代码中有很大的安全风险,建议在配置文件或者环境变量中存放(密码应密文存放,使用时解密),确保安全;
// 本示例以用户名和密码保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量(环境变量名称请根据自身情况进行设置)EXAMPLE_USERNAME_ENV和EXAMPLE_PASSWORD_ENV。
public class SSL{
    public static void main(String[] args) {
        Properties urlProps = new Properties();
        String urls = "jdbc:postgresql://$ip:$port/postgres";
        String userName = System.getenv("EXAMPLE_USERNAME_ENV");
        String password = System.getenv("EXAMPLE_PASSWORD_ENV");

        urlProps.setProperty("sslcert", "client.crt");
        urlProps.setProperty("sslkey", "client.key.pk8");
        urlProps.setProperty("sslrootcert", "cacert.pem");
        urlProps.setProperty("user", userName);
        urlProps.setProperty("ssl", "true");
        /* sslmode可配置为:require、verify-ca、verify-full,以下三个示例选择其一*/
        /* ==================  示例2.1  设置sslmode为require,使用证书 */
        urlProps.setProperty("sslmode", "require");
        /* ==================  示例2.2  设置sslmode为verify-ca,使用证书 */
        urlProps.setProperty("sslmode", "verify-ca");
        /* ==================  示例2.3  设置sslmode为verify-full,使用证书(Linux下验证) */
        urls = "jdbc:postgresql://world:8000/postgres";
        urlProps.setProperty("sslmode", "verify-full");

        try {
            Class.forName("org.postgresql.Driver").newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            Connection conn;
            conn = DriverManager.getConnection(urls,urlProps);
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
/**
 * 注:将客户端密钥转化为DER格式:
 * openssl pkcs8 -topk8 -outform DER -in client.key -out client.key.pk8 -nocrypt
 * openssl pkcs8 -topk8 -inform PEM -in client.key -outform DER -out client.key.der -v1 PBE-MD5-DES
 * openssl pkcs8 -topk8 -inform PEM -in client.key -outform DER -out client.key.der -v1 PBE-SHA1-3DES
 * 以上算法由于安全级别较低,不推荐使用。
 * 如果客户需要采用更高级别的私钥加密算法,启用bouncycastle或者其他第三方私钥解密密码包后可以使用的私钥加密算法如下:
 * openssl pkcs8 -in client.key -topk8  -outform DER -out client.key.der -v2 AES128
 * openssl pkcs8 -in client.key -topk8  -outform DER -out client.key.der -v2 aes-256-cbc -iter 1000000
 * openssl pkcs8 -in client.key -topk8 -out client.key.der  -outform Der -v2 aes-256-cbc -v2prf hmacWithSHA512
 * 启用bouncycastle:使用jdbc的项目引入依赖:bcpkix-jdk15on.jar包,版本建议:1.65以上。
 */

JDBC使用SSL方式建立连接时,会在客户端获取强随机数,建立连接过程中可能出现图中的报错信息。

原因在于客户端环境随机数产生的速度太慢,无法满足产品要求,熵源不足,导致服务启动失败。当前已知在一些Linux环境中存在这个问题。

建议处理方案:启动客户端环境中的haveged服务,增加系统熵池熵值以提高读取随机数的速度。启动命令为:

systemctl start haveged