1. 介绍

在数据库管理领域,确保应用与数据库间的安全通信至关重要。本文将介绍如何通过JDBC和Spring Boot建立PostgreSQL的SSL连接。我们将涵盖服务器配置、证书处理和多种连接方式,助你快速实现安全数据库通信。

2. PostgreSQL配置

首先需要配置PostgreSQL服务器支持SSL连接。确保已准备好根CA证书、服务器证书和私钥文件。修改服务器配置文件postgresql.conf,添加证书路径:

...
ssl = on
ssl_ca_file = '/opt/homebrew/var/postgresql@14/rootCA.crt'
ssl_cert_file = '/opt/homebrew/var/postgresql@14/localhost.crt'
#ssl_crl_file = ''
#ssl_crl_dir = ''
ssl_key_file = '/opt/homebrew/var/postgresql@14/localhost.key'
...

接着修改客户端配置文件pg_hba.conf,在IPv4部分添加:

...
# IPv4 local connections:
hostssl    all             all             0.0.0.0/0            cert
...

⚠️ 确保证书文件路径正确且权限设置合理,否则会导致连接失败。

3. Maven配置

pom.xml中添加PostgreSQL JDBC驱动依赖:

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.7.3</version>
</dependency>

我们使用最新版驱动以支持pkcs-12客户端证书格式。

4. 通过JDBC直接连接

建立SSL连接需要客户端证书(需使用与服务器证书相同的根CA签发)。重要:JDBC无法直接使用原始私钥,需先转换为pkcs-8格式

openssl pkcs8 -topk8 -inform PEM -outform DER -in certs/pg_client.key -out certs/pg_client.pk8 -nocrypt

创建PgJdbc类实现连接测试:

public class PgJdbc {
    public void checkConnectionSsl(String url, String username, String password, Map<String, String> extraProps) {
        Properties props = new Properties();
        props.putAll(extraProps);
        props.put("username", username);
        props.put("password", password);
        props.put("sslmode", "verify-ca");
        props.put("ssl", "true");

        try (Connection connection = DriverManager.getConnection(url, props)) {
            if (!connection.isClosed()) {
                connection.close();
            }
            System.out.println("Connection was successful");
        } catch (SQLException e) {
            System.out.println("Connection failed");
        }
    }

    // ...
}

main方法中测试连接:

public class PgJdbc {
    // ...

    public static void main(String[] args) {
        PgJdbc pg = new PgJdbc();
        String url = "jdbc:postgresql://localhost:5432/testdb";
        String username = "postgres";
        String password = "password";
        String BASE_PATH = Paths.get("certs")
          .toAbsolutePath()
          .toString();

        Map<String, String> connectionProperties = Map.of(
          "sslcert", BASE_PATH.concat("/pg_client.crt"),
          "sslkey", BASE_PATH.concat("/pg_client.pk8"),
          "sslrootcert", BASE_PATH.concat("/root.crt"));

        System.out.println("Connection without keystore and truststore");
        pg.checkConnectionSsl(url, username, password, connectionProperties);
    }
}

执行测试:

$ mvn clean compile -q exec:java -Dexec.mainClass="com.baeldung.pgoverssl.PgJdbc"
Connection was successful

✅ 连接成功建立!这种方式简单直接,适合快速验证。

5. 通过JDBC使用密钥库连接

也可使用Java密钥库(keystore)和信任库(truststore)建立连接。步骤如下:

  1. 将证书和私钥转换为pkcs-12格式:

    $ openssl pkcs12 -export -in certs/pg_client.crt -inkey certs/pg_client.key -out certs/pg_client.p12 -name postgres
    
  2. 创建密钥库:

    $ keytool -importkeystore -destkeystore certs/pg_client.jks -srckeystore certs/pg_client.p12 -srcstoretype pkcs12
    Importing keystore certs/pg_client.p12 to certs/pg_client.jks...
    Enter destination keystore password: 
    ...
    Import command completed:  1 entries successfully imported, 0 entries failed or cancelled
    
  3. 创建信任库:

    $ keytool -import -alias server -file certs/root.crt -keystore certs/truststore.jks -storepass password
    ...
    Certificate was added to keystore
    

修改main方法使用密钥库:

public class PgJdbc {
    // ...

    public static void main(String[] args) {
        // ...

        System.setProperty("javax.net.ssl.keyStore", BASE_PATH.concat("/pg_client.jks"));
        System.setProperty("javax.net.ssl.keyStorePassword", "password");
        System.setProperty("javax.net.ssl.trustStore", BASE_PATH.concat("/truststore.jks"));
        System.setProperty("javax.net.ssl.trustStorePassword", "password");

        System.out.println("\nConnection using keystore and truststore");
        pg.checkConnectionSsl(url, username, password, Map.of("sslfactory", "org.postgresql.ssl.DefaultJavaSSLFactory"));
    }
}

执行测试:

Connection using keystore and truststore
Connection was successful

✅ 同样成功连接!这种方式更适合生产环境,便于统一管理证书。

6. 通过Spring Boot连接

在Spring Boot应用中配置SSL连接同样简单。添加依赖:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.3</version>
</parent>

// ...

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

创建启动类:

@SpringBootApplication
public class PgSpringboot {
    public static void main(String[] args) {
        SpringApplication.run(PgSpringboot.class, args);
    }
}

配置application.yaml

spring:
  application:
    name: postgresqlssltest
  datasource:
    url: jdbc:postgresql://localhost:5432/testdb?ssl=true&sslmode=verify-ca&sslrootcert=certs/root.crt&sslcert=certs/pg_client.crt&sslkey=certs/pg_client.pk8
    username: postgres
    password: "password"
    driver-class-name: org.postgresql.Driver
  jpa:
    hibernate:
      ddl-auto: update
    database-platform: org.hibernate.dialect.PostgreSQLDialect

启动应用测试连接:

$ mvn clean compile -q exec:java -Dexec.mainClass="com.baeldung.pgoverssl.PgSpringboot" -Dspring.config.location=classpath:./pgoverssl/application.yaml
...
2024-07-04T21:41:17.552+01:00  INFO 458 --- [postgresqlssltest] [ringboot.main()] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2024-07-04T21:41:18.290+01:00  INFO 458 --- [postgresqlssltest] [ringboot.main()] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@4e331d3d
2024-07-04T21:41:18.291+01:00  INFO 458 --- [postgresqlssltest] [ringboot.main()] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
...

✅ Spring Boot成功建立SSL连接!配置集中在YAML文件中,维护更方便。

7. 总结

本文详细介绍了通过SSL连接PostgreSQL的多种方式:

  • ✅ 直接使用证书和私钥(适合快速验证)
  • ✅ 使用Java密钥库(适合生产环境)
  • ✅ Spring Boot集成(简化配置)

关键点总结:

  1. 服务器需正确配置SSL证书
  2. 客户端证书需与服务器使用相同根CA
  3. 私钥格式转换是常见踩坑点
  4. Spring Boot通过URL参数简化配置

完整示例代码可在GitHub获取。根据实际场景选择合适方案,确保数据库通信安全可靠。


原始标题:Connect with PostgreSQL Database over SSL | Baeldung