使用 SSL

主要文档 中介绍了为 SSL 配置 PostgreSQL® 服务器,因此这里不再赘述。在尝试从 Java 访问启用了 SSL 的服务器之前,请确保您可以通过 **psql** 访问它。如果您已建立 SSL 连接,您应该看到如下输出。

$ ./bin/psql -h localhost -U postgres
psql (14.5)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.

postgres=#

PostgreSQL® 为开发人员提供了一种自定义 SSL 连接建立方式。这可以通过允许开发人员创建自己的 SSLContext 实例来提供自定义证书源或其他扩展。连接 URL 参数 sslfactory 允许用户指定用于创建 SSLSocketFactory 的自定义类。sslfactory 指定的类名必须扩展 javax.net.ssl.SSLSocketFactory 并且对驱动程序的类加载器可用。

此类必须具有一个零参数构造函数或一个优先接受Properties参数的单参数构造函数。提供了一个简单的org.postgresql.ssl.DefaultJavaSSLFactory,它使用默认的 Java SSLFactory。

有关如何实际实现此类的信息超出了本文档的范围。寻求帮助的地方包括JSSE 参考指南和 JDBC 驱动程序提供的NonValidatingFactory的源代码。

有许多连接参数可用于配置客户端以使用 SSL。请参阅SSL 连接参数

最简单的是ssl=true,将此传递给驱动程序将导致驱动程序验证 SSL 证书并验证主机名(与verify-full相同)。

注意

这与默认使用非验证 SSL 连接的 libpq 不同。

在此模式下,在建立 SSL 连接时,JDBC 驱动程序将验证服务器的身份,从而防止“中间人”攻击。它通过检查服务器证书是否由受信任的机构签署,以及您连接到的主机是否与证书中的主机名相同来实现这一点。

如果您**需要**加密,并且希望连接在无法加密的情况下失败,请设置sslmode=require,这将确保服务器配置为接受此主机/IP 地址的 SSL 连接,并且服务器识别客户端证书。换句话说,如果服务器不接受 SSL 连接或客户端证书不被识别,则连接将失败。

注意

在此模式下,我们将接受所有服务器证书。

如果 sslmode=verify-ca,则通过检查证书链到客户端存储的根证书来验证服务器。

如果 sslmode=verify-full,则会验证服务器主机名,以确保它与服务器证书中存储的名称匹配。

如果无法验证服务器证书,则 SSL 连接将失败。在大多数安全敏感环境中,建议使用 verify-full

默认的 SSL 套接字工厂是 LibPQFactory。如果证书验证失败,您可以尝试使用 sslcert=,LibPQFactory 将不会发送客户端证书。如果服务器未配置为使用证书进行身份验证,则应该连接。

客户端证书、PKCS-8 客户端密钥和根证书的位置可以通过 sslcertsslkeysslrootcert 设置分别覆盖。这些默认分别为 /defaultdir/postgresql.crt、/defaultdir/postgresql.pk8/defaultdir/root.crt,其中 defaultdir 在 *nix 系统中为 ${user.home}/.postgresql/,在 Windows 上为 %appdata%/postgresql/

从 42.2.9 版本开始,也支持 PKCS-12。在此存档格式中,客户端密钥和客户端证书位于一个文件中,需要使用 sslkey 参数设置。为了识别 PKCS-12 格式,文件扩展名必须为“.p12”(从 42.2.9 版本开始支持)或“.pfx”(从 42.2.16 版本开始支持)。(在这种情况下,sslcert 参数将被忽略。)

注意

使用 PKCS-12 客户端证书时,使用 openssl pkcs12 -export -name user ... 时,名称或别名 *必须* 为 user。在 certdir Makefile 中有关于如何导出证书的完整示例。

可以使用 sslmode 连接参数实现对 SSL 连接的更精细控制。此参数与 libpq sslmode 参数相同,目前实现以下内容

sslmode 窃听保护 中间人攻击保护
disable 我不关心安全性,也不想为加密支付开销
allow 也许 我不关心安全性,但如果服务器坚持要求,我会为加密支付开销
prefer 也许 我不关心加密,但如果服务器支持,我会为加密支付开销
require 我希望我的数据被加密,并且我接受开销。我相信网络会确保我始终连接到我想要的服务器。
verify-ca 取决于 CA 策略 我希望我的数据被加密,并且我接受开销。我想确保我连接到一个我信任的服务器。
verify-full 我希望我的数据被加密,并且我接受开销。我想确保我连接到一个我信任的服务器,并且它是指定的服务器。

注意

如果您使用的是 Java 的默认机制(不是 LibPQFactory)来创建 SSL 连接,则需要使服务器证书对 Java 可用,第一步是将其转换为 Java 理解的格式。

openssl x509 -in server.crt -out server.crt.der -outform der

从这里开始,最简单的方法是将此证书导入到 Java 的系统信任库中。

keytool -keystore $JAVA_HOME/lib/security/cacerts -alias postgresql -import -file server.crt.der

cacerts 密钥库的默认密码是 changeit。将别名设置为 postgresql 不是必需的。您可以使用任何您想要的名称。

如果您无法访问系统 cacerts 信任库,则可以创建自己的信任库。

keytool -keystore mystore -alias postgresql -import -file server.crt.der

启动 Java 应用程序时,您必须指定此密钥库和密码才能使用。

java -Djavax.net.ssl.trustStore=mystore -Djavax.net.ssl.trustStorePassword=mypassword com.mycompany.MyApp

如果出现问题,可以通过在命令行中添加 -Djavax.net.debug=ssl 来获取额外的调试信息。

在某些情况下,可能无法配置您的 Java 环境以使服务器证书可用,例如在小程序中。对于大规模部署,最好获取由公认的证书颁发机构签署的证书,但这并不总是可行。JDBC 驱动程序提供了一个选项,可以在不进行任何验证的情况下建立 SSL 连接,但在启用此选项之前,请了解所涉及的风险。

非验证连接是通过驱动程序提供的自定义 SSLSocketFactory 类建立的。设置连接 URL 参数 sslfactory=org.postgresql.ssl.NonValidatingFactory 将关闭所有 SSL 验证。