尝试通过 JDBC 与 Postgres 建立 SSL 连接时出现 PSQLException“无法打开 SSL 根证书文件”

Posted

技术标签:

【中文标题】尝试通过 JDBC 与 Postgres 建立 SSL 连接时出现 PSQLException“无法打开 SSL 根证书文件”【英文标题】:PSQLException "Could not open SSL root certificate file" when attempting SSL connection with Postgres via JDBC 【发布时间】:2020-11-21 01:48:47 【问题描述】:

在 Java 15 中,使用来自 jdbc.postgresql.org 的 PostgreSQL JDBC 驱动程序(版本 42.2.18,JDBC4.2)和 DataSource

PGSimpleDataSource ds = new PGSimpleDataSource();
ds.setServerNames( new String[]  "my-server-address"  );
ds.setPortNumbers( new int[]  25060  );
ds.setSsl( true );
ds.setDatabaseName( "mydb" );
ds.setUser( "scott" );
ds.setPassword( "tiger" );
this.dataSource = ds;

…代码Connection conn = this.dataSource.getConnection(); 抛出此异常:

org.postgresql.util.PSQLException:无法打开 SSL 根证书文件 /Users/basilbourque/.postgresql/root.crt。

我知道我的 Postgres 12 服务器是为 SSL 连接设置的,因为我的 IntelliJ Ultimate 有一个数据库访问功能 (DataGrip) 可以通过 SSL (TLS) 保护成功连接。

那么我在 JDBC 中的 DataSource 配置有什么问题?

【问题讨论】:

【参考方案1】:

感谢 this Github issue 页面的 pgjdbc 驱动程序,我找到了 davecramer 的这篇文章:

从 42.2.5 开始,ssl=true 意味着根据发行说明进行完整验证。如果您希望获得旧行为,请使用 sslmode=require

果然,将ds.setSsl( true ); 替换为ds.setSslMode( "require" ); 允许我的JDBC 驱动程序通过DataSource 建立连接。

        PGSimpleDataSource ds = new PGSimpleDataSource();
        ds.setServerNames( new String[]  "my-server-address"  );
        ds.setPortNumbers( new int[]  25060  );
        ds.setSslMode( "require" );  // Replaces: ds.setSsl( true );
        ds.setDatabaseName( "mydb" );
        ds.setUser( "scott" );
        ds.setPassword( "tiger" );
        this.dataSource = ds;

我不知道这些 SSL/TLS 相关选项实际上在做什么,但这对我连接到我的 DigitalOcean 管理的 Postgres 数据库服务器很有用。

下面的代码sn-p现在运行成功了:

        try
                (
                        Connection conn = this.dataSource.getConnection() ;
                        Statement stmt = conn.createStatement() ;
                )
        
            String sql =
                    """
                    SELECT uuid_generate_v1()
                    ;
                    """;
            try (
                    ResultSet rs = stmt.executeQuery( sql ) ;
            )
            
                while ( rs.next() )
                
                    UUID uuid = rs.getObject( 1 , UUID.class );
                    System.out.println( "uuid = " + uuid );
                
            
        
        catch ( SQLException e )
        
            e.printStackTrace();
        

【讨论】:

通过这些选项,PostgreSQL 使用加密通信,但不会尝试验证服务器的真实性。因此,您可能会成为中间人攻击的牺牲品。如果这不是问题,那么您的设置很好。

以上是关于尝试通过 JDBC 与 Postgres 建立 SSL 连接时出现 PSQLException“无法打开 SSL 根证书文件”的主要内容,如果未能解决你的问题,请参考以下文章

休眠缓慢以获取 Postgres 连接

Postgres / JDBC 与 pgjdbc-ng:将 EAN 类型写入数据库

Postgres 的 "\connect" 命令的 JDBC 对应项是啥?

kafka JDBC源连接器无法获取postgres表

Java JDBC Postgres copyIn无法识别行尾并填充双引号

Docker Compose 无法从数据库 (jdbc:postgresql://db:5432/postgres) 为用户“postgres”获取连接:连接尝试失败