I need to configure TLS 1.1 protocol for SSL connection in PostgreSQL.
I was not able to see protocol setting in the PostgreSQL configuration
It is required to disable SSL protocols and TLSv1 and enable only TLSv1.1 (or TLSv1.2)
Added
PCI DSS v3.1 requires that fallback to SSL and TLSv1 will be disabled.
Is it is possible to configure PostgreSQL to negotiate using TLSv1.1 only?
If you know that it is impossible please share this information
Added 2
Unfortunately, the configuration of ssl_ciphers
is not enough since you can use same ciphers for different protocols. It is required to configure SSL_METHOD
as described here:
https://www.openssl.org/docs/manmaster/ssl/ssl.html.
My conclusion that the configuration of SSL_METHOD
(or SSL_PROTOCOL
) is missed from the PostgreSQL configuration and it can not be complaint to PCI DSS 3.1.
Please correct me if I am wrong.
-
5Tom says: "libpq versions before 9.4 will only accept TLSv1 exactly. In 9.4 it should negotiate the highest TLS version supported by both server and client." So you might be out of luck on 9.1.Josh Kupershmidt– Josh Kupershmidt2015年09月18日 14:04:42 +00:00Commented Sep 18, 2015 at 14:04
-
Is upgrading to 9.3 (preferably 9.4) an option?András Váczi– András Váczi2015年10月01日 08:19:34 +00:00Commented Oct 1, 2015 at 8:19
-
@dezso I have changed my question to version 9.4. Any case, I did not find in the configuration option to configure TLS 1.1 protocol for SSL connection.Michael– Michael2015年10月01日 10:07:18 +00:00Commented Oct 1, 2015 at 10:07
5 Answers 5
Meanwhile, starting from Postgres 12, it's possible to force the minimal SSL/TLS encryption level at the server side by tweaking the ssl_min_protocol_version` parameter.
According to this documentation page valid values are currently: TLSv1, TLSv1.1, TLSv1.2, TLSv1.3.
As of Postgres 13, the default value is TLSv1.2 (before that it was TLSv1).
@BrianEfting was correct, you can specify the appropriate cipher suites to only allow TLSv1.2 which should fit your PCI-DSS 3.1 specification needs.
Using a cipher list like this in the ssl_ciphers
option in your postgresql.conf
:
ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-DSS-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:DHE-RSA-AES128-SHA256:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK
along with setting ssl_prefer_server_ciphers=true
, should be sufficient to allow only TLSv1.2 connections.
You can verify this using SSLyze which knows about the PostgreSQL protocol.
To test, I used the following command:
./sslyze.py --sslv2 --sslv3 --tlsv1 --tlsv1_1 --tlsv1_2 localhost:5432 --starttls=postgres --hide_rejected_ciphers
Which gave the output below under PostgreSQL 9.4 on Debian Wheezy showing that all cipher suites except for the TLSv1.2 ciphers specified were rejected, which should satisfy the requirements of PCI-DSS 3.1 by using TLSv1.1 or greater.
postgres@pgsqlsec4:~/sslyze$ ./sslyze.py --sslv2 --sslv3 --tlsv1 --tlsv1_1 --tlsv1_2 localhost:5432 --starttls=postgres --hide_rejected_ciphers
AVAILABLE PLUGINS
-----------------
PluginCompression
PluginHeartbleed
PluginChromeSha1Deprecation
PluginSessionRenegotiation
PluginOpenSSLCipherSuites
PluginSessionResumption
PluginHSTS
PluginCertInfo
CHECKING HOST(S) AVAILABILITY
-----------------------------
localhost:5432 => ::1:5432
SCAN RESULTS FOR LOCALHOST:5432 - ::1:5432
------------------------------------------
* SSLV2 Cipher Suites:
Server rejected all cipher suites.
* TLSV1_2 Cipher Suites:
Preferred:
ECDHE-RSA-AES128-GCM-SHA256 ECDH-256 bits 128 bits
Accepted:
ECDHE-RSA-AES256-SHA384 ECDH-256 bits 256 bits
ECDHE-RSA-AES256-GCM-SHA384 ECDH-256 bits 256 bits
DHE-RSA-AES256-SHA256 DH-1024 bits 256 bits
DHE-RSA-AES256-GCM-SHA384 DH-1024 bits 256 bits
ECDHE-RSA-AES128-SHA256 ECDH-256 bits 128 bits
ECDHE-RSA-AES128-GCM-SHA256 ECDH-256 bits 128 bits
DHE-RSA-AES128-SHA256 DH-1024 bits 128 bits
DHE-RSA-AES128-GCM-SHA256 DH-1024 bits 128 bits
* TLSV1_1 Cipher Suites:
Server rejected all cipher suites.
* TLSV1 Cipher Suites:
Server rejected all cipher suites.
* SSLV3 Cipher Suites:
Server rejected all cipher suites.
SCAN COMPLETED IN 0.73 S
------------------------
postgres@pgsqlsec4:~/sslyze$
-
It is the workaround. Once again: it is required to configure protocol and it is missed from PostgreSQL configuration. I can not accept the answer. Any case, I do not have a problem to give a bounty for the hard work.Michael– Michael2015年10月06日 11:13:52 +00:00Commented Oct 6, 2015 at 11:13
-
@Michael This is functionally identical to disabling TLS v1.0. There is a new config directive in version 12 of Postgres but it's not been released yet:
ssl_min_protocol_version=TLSv1.1
deed02392– deed023922019年09月05日 16:11:08 +00:00Commented Sep 5, 2019 at 16:11 -
It's not functionally identical is the problem: It also disables TLS 1.1 because there are no new cipher suites there. It's also far less auditable, though arguably that's not a functional aspect. You could make it slightly more auditable by tacking on a !TLSv1. but still compare that to an nginx config for example, where an auditor only has to read a single one or two word line.DylanYoung– DylanYoung2020年06月04日 17:02:47 +00:00Commented Jun 4, 2020 at 17:02
From the following link:
18.3. Connections and Authentication (PostgreSQL 9.4 Manual)
It would appear that you can use the ssl_ciphers
option to specify your list of accepted ciphers. And it mentions that it follows whatever your version of OpenSSL supports.
And in this link:
OpenSSL Ciphers (OpenSSL.org)
Mentions that there is no specific ciphersuite for TLSv1.1 but you can specify TLSv1.2.
-
Unfortunately, the configuration of
ssl_ciphers
is not enough since you can use same ciphers for different protocols. It is required to configureSSL_METHOD
as described here: openssl.org/docs/manmaster/ssl/ssl.html. My conclusion that the configuration ofSSL_METHOD
(orSSL_PROTOCOL
) is missed from the PostgreSQL configuration and it can not be complaint to PCI DSS 3.1. Please correct me if I am wrong.Michael– Michael2015年10月04日 08:23:36 +00:00Commented Oct 4, 2015 at 8:23 -
Well thank you Michael. I think @Kassandry worked harder than I did, though, and deserves some serious props here. Even going so far as to test and see that the insecure methods are indeed rejected.Brian Efting– Brian Efting2015年10月07日 18:12:12 +00:00Commented Oct 7, 2015 at 18:12
-
Yes, but you was the first with this approach. Unfortunately, I can not spit the bountyMichael– Michael2015年10月08日 10:14:41 +00:00Commented Oct 8, 2015 at 10:14
You can specify the protocols (TLSv1.2) instead of fine grained list of ciphers in the conf file.
References:
- https://www.postgresql.org/docs/9.4/static/runtime-config-connection.html#GUC-SSL-CIPHERS
- https://www.postgresql.org/message-id/[email protected]
Modify postgresql.conf
ssl_ciphers = 'TLSv1.2:!aNULL'
ssl_prefer_server_ciphers=true
Restart the service
/etc/init.d/postgresql94 restart
Re-run the test again
sslyze --sslv2 --sslv3 --tlsv1 --tlsv1_1 --tlsv1_2 localhost:5432 --starttls=postgres --hide_rejected_ciphers
This should do it if you're using the defaults to start:
ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL:!SSLv3'
It also covers TLS1.1, TLS1.0, and SSLv2 on newer versions of openssl. (See the postgresql docs for info on the +3DES hack; it does appear to have been fixed in newer versions of openssl).
If not or if you want to be more explicit, just append, ':!SSLv2:!SSLv3:!TLSv1'
TLSv1.1
is also deprecated, so I recommend also appending ':!TLSv1.1'
This gives a final "safe" cipher string based on the default as follows:
HIGH:MEDIUM:+3DES:!aNULL:!SSLv2:!SSLv3:!TLSv1:!TLSv1.1
You can test with your version of openssl using the following:
openssl ciphers -v MY_CIPHER_STRING | column -t
This is lists all the ciphers that will be included WITH their protocol.
Sample output with the "safe" ciphers list above (opensslv1.0.1):
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384
DHE-DSS-AES256-GCM-SHA384 TLSv1.2 Kx=DH Au=DSS Enc=AESGCM(256) Mac=AEAD
DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(256) Mac=AEAD
DHE-RSA-AES256-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(256) Mac=SHA256
DHE-DSS-AES256-SHA256 TLSv1.2 Kx=DH Au=DSS Enc=AES(256) Mac=SHA256
ECDH-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AESGCM(256) Mac=AEAD
ECDH-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AESGCM(256) Mac=AEAD
ECDH-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AES(256) Mac=SHA384
ECDH-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AES(256) Mac=SHA384
AES256-GCM-SHA384 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(256) Mac=AEAD
AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256
ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256
DHE-DSS-AES128-GCM-SHA256 TLSv1.2 Kx=DH Au=DSS Enc=AESGCM(128) Mac=AEAD
DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(128) Mac=AEAD
DHE-RSA-AES128-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(128) Mac=SHA256
DHE-DSS-AES128-SHA256 TLSv1.2 Kx=DH Au=DSS Enc=AES(128) Mac=SHA256
ECDH-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AESGCM(128) Mac=AEAD
ECDH-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AESGCM(128) Mac=AEAD
ECDH-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AES(128) Mac=SHA256
ECDH-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AES(128) Mac=SHA256
AES128-GCM-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(128) Mac=AEAD
AES128-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA256
BEWARE
The cipher suite SSLv3 (likewise TLSv1, etc...) expands to all ciphers supported by SSLv3. This means that these same ciphers will be excluded in higher protocols as well (if they exist there).
To demonstrate:
openssl ciphers 'TLSv1:!SSLv3'
Output:
Error in cipher list
139740792764064:error:1410D0B9:SSL routines:SSL_CTX_set_cipher_list:no cipher match:ssl_lib.c:1312:
i.e. since every cipher available in SSLv3 is also available in TLSv1, we get no ciphers returned.
As noted by the OP, this means there is no way to disable SSLv3 through the cipher list without also excluding the same cipher for higher protocols
In practice, this should only lead to better security, but it may cause problems for those with backwards compatibility requirements (must support TLSv1.0 and cannot support SSLv3, for example)
Since TLSv1.1 doesn't contain any new ciphers, it will also be disabled if you use !SSLv3
.
Be careful!