使用 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 客户端密钥和根证书可以分别使用sslcert
、sslkey
和sslrootcert
设置进行覆盖。这些参数的默认值分别为/defaultdir/postgresql.crt
、/defaultdir/postgresql.pk8
和/defaultdir/root.crt
, 其中的 defaultdir 在类 Unix 系统上为${user.home}/.postgresql/
,在 Windows 上为%appdata%/postgresql/
。
从版本 42.2.9 开始,还支持 PKCS-12。在此存档格式中,客户端密钥和客户端证书位于一个文件,文件需要使用参数sslkey
进行设置。要识别 PKCS-12 格式,文件扩展名 必须是 “.p12”(自 42.2.9 起支持)或 “.pfx”(自 42.2.16 起支持)。(在这种情况下,sslcert
参数会被忽略。)
可以使用连接参数sslmode
实现对 SSL 连接的更精细控制。此参数与 libpq 的sslmode
参数相同,当前支持以下选择。
sslmode | 窃听保护 | MITM 保护 | |
---|---|---|---|
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。您可以应用任何您想要的名称。
如果您无权访问系统证书信任库,则可以创建自己的信任库。
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 环境以使服务器证书可用,例如在 applet 小程序中。对于大规模部署,最好获得由公认的证书颁发机构签名的证书,但这并不总是一种选择。JDBC 驱动程序提供了一个无需执行任何验证即可建立 SSL 连接的选项,但在启用此选项之前,请了解所涉及的风险。
非验证连接是通过随驱动程序提供的自定义SSLSocketFactory
类建立的。设置连接 URL 参数sslfactory=org.postgresql.ssl.NonValidatingFactory
将关闭所有 SSL 验证。