11

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.

asked Sep 18, 2015 at 6:53
3
  • 5
    Tom 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. Commented Sep 18, 2015 at 14:04
  • Is upgrading to 9.3 (preferably 9.4) an option? Commented 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. Commented Oct 1, 2015 at 10:07

5 Answers 5

6

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).

answered Dec 21, 2020 at 14:09
14

@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$
answered Oct 4, 2015 at 20:48
3
  • 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. Commented 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 Commented 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. Commented Jun 4, 2020 at 17:02
5
+50

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.

answered Oct 1, 2015 at 17:27
3
  • 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: 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. Commented 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. Commented Oct 7, 2015 at 18:12
  • Yes, but you was the first with this approach. Unfortunately, I can not spit the bounty Commented Oct 8, 2015 at 10:14
2

You can specify the protocols (TLSv1.2) instead of fine grained list of ciphers in the conf file.

References:

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
answered Jan 31, 2017 at 10:16
1

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!

answered Sep 21, 2018 at 14:20

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.