使用 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=#
自定义 SSLSocketFactory
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 客户端密钥和根证书的位置可以通过 sslcert
、sslkey
和 sslrootcert
设置分别覆盖。这些默认分别为 /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
来获取额外的调试信息。
在没有证书验证的情况下使用 SSL
在某些情况下,可能无法配置您的 Java 环境以使服务器证书可用,例如在小程序中。对于大规模部署,最好获取由公认的证书颁发机构签署的证书,但这并不总是可行。JDBC 驱动程序提供了一个选项,可以在不进行任何验证的情况下建立 SSL 连接,但在启用此选项之前,请了解所涉及的风险。
非验证连接是通过驱动程序提供的自定义 SSLSocketFactory
类建立的。设置连接 URL 参数 sslfactory=org.postgresql.ssl.NonValidatingFactory
将关闭所有 SSL 验证。