Thread: [BUGS] BUG #14686: OpenSSL 1.1.0+ breaks PostgreSQL's sslcompressionassumption, defaults to SSL_OP_NO_COMPRESSION
[BUGS] BUG #14686: OpenSSL 1.1.0+ breaks PostgreSQL's sslcompressionassumption, defaults to SSL_OP_NO_COMPRESSION
From
greenreaper@hotmail.com
Date:
The following bug has been logged on the website: Bug reference: 14686 Logged by: Laurence Parry Email address: greenreaper@hotmail.com PostgreSQL version: 9.6.3 Operating system: Debian 9 'stretch', Linux 4.9.25, libc 2.24 Description: PostgreSQL is documented to compress data over SSL connections by default where possible: https://www.postgresql.org/docs/9.6/static/libpq-connect.html#LIBPQ-CONNECT-SSLCOMPRESSION PostgreSQL assumes that OpenSSL 0.9.8+ will compress with zlib if it can. However, OpenSSL 1.1.0+ - already in Manjaro, and the upcoming Debian 9 'Stretch', Fedora 26, and Tails 3.0 - sets SSL_OP_NO_COMPRESSION by default to discourage the CRIME attack: https://www.openssl.org/news/changelog.html#x7 *) CRIME protection: disable compression by default, even if OpenSSL is compiled with zlib enabled. Applications canstill enable compression by calling SSL_CTX_clear_options(ctx, SSL_OP_NO_COMPRESSION), or by using the SSL_CONFlibrary to configure compression. PostgreSQL does not anticipate this, and so fails to compress the connection even if zlib support is compiled into OpenSSL. This is not immediately obvious, unless you are watching networking graphs. Restoring compression in PostgreSQL requires patching out the new default in the depths of OpenSSL and recompiling (rather than just reconfiguring and recompiling). == Possible PostgreSQL code fix == If the connection string includes sslcompression=0, initialize_SSL() in pqlib disables SSL compression by setting SSL_OP_NO_COMPRESSION: https://doxygen.postgresql.org/fe-secure-openssl_8c_source.html#l01278 I believe there also needs to be an 'else' case to *clear* SSL_OP_NO_COMPRESSION with: SSL_clear_options(conn->ssl, SSL_OP_NO_COMPRESSION); in the case that sslcompression is unset or not '0', rather than rely on the default. PostgreSQL _could_ clear it if sslcompression is '1', rather than unset or not '0', but that would mean more people not using SSL compression. From 9.2 onwards, the documentation has 1 as the default; so many will not have set it, assuming that it will [continue to] work. Distributions will not use PostgreSQL 10 until it is released, while OpenSSL 1.1.0 is already in use with PostgreSQL 9.6 (and might be used with older versions): https://distrowatch.com/search.php?pkg=openssl&relation=similar&pkgver=1.1&distrorange=InAny#pkgsearch [In addition, PostgreSQL currently won't work as described if a distribution or end-user has made a similar change to the default in OpenSSL 1.0.x, although that seems less likely.] I therefore suggest leaving compression on by default, and back-patching a fix to 9.2 and above, where sslcompression was introduced, to clear this flag if it may have been set. The same code is in fe-secure.c rather than fe-secure-openssl.c in PostgreSQL 9.4 and below. This would be in line with the back-porting of other support for 1.1.0 in: https://www.postgresql.org/message-id/flat/20160627151604.GD1051%40msg.df7cb.de#20160627151604.GD1051@msg.df7cb.de According to a Python SSL comment: /* SSL_CTX_clear_options() and SSL_clear_options() were first added in* OpenSSL 0.9.8m but do not appear in some 0.9.9-devversions such the* 0.9.9 from "May 2008" that NetBSD 5.0 uses. */ Since SSL_OP_NO_COMPRESSION was added in 1.0.0, it should be fine to use SSL_clear_options() within the existing #ifdef. It may also help to mention in the documentation that this compression requires a version of openssl/libssl compiled with zlib[-dynamic], and potentially environment variables to enable it, such as OPENSSL_DEFAULT_ZLIB in Ubuntu 12.04 (but not 14.04+): https://bazaar.launchpad.net/~ubuntu-branches/ubuntu/vivid/openssl/vivid/revision/95 This was suggested previously in: https://www.postgresql.org/message-id/flat/CAKwe89Cj7KQ3BZDoUXLF5KBZ8X6icKXHi2Y1mDzTut3PNrH2VA%40mail.gmail.com == Workaround: recompiling openssl == You can check whether openssl has been compiled with zlib support by checking for -DZLIB / -DZLIB_SHARED in: $ openssl version -f but either way, it will not be on by default with openssl 1.1.0+ For those wishing to fix compression on Debian stretch (or jessie, or Ubuntu 14.04+): # apt-get install build-essential # apt-get build-dep openssl From an unprivileged account: $ apt-get source openssl $ cd openssl-1.1.0f $ nano debian/rules [ replace 'no-zlib' with 'zlib' or 'zlib-dynamic' in CONFARGS ] For OpenSSL 1.1.0+ (stretch et. al), also apply the following patch to ssl/ssl_lib.c: ###START### --- ssl/ssl_lib.c.orig 2017-06-02 22:34:20.524405847 +0200 +++ ssl/ssl_lib.c 2017-06-02 22:34:36.764406166 +0200 @@ -2471,13 +2471,6 @@ * deployed might change this. */ ret->options |= SSL_OP_LEGACY_SERVER_CONNECT; - /* - * Disable compression by default to prevent CRIME. Applications can - * re-enable compression by configuring - * SSL_CTX_clear_options(ctx, SSL_OP_NO_COMPRESSION); - * or by using the SSL_CONF library. - */ - ret->options |= SSL_OP_NO_COMPRESSION; ret->tlsext_status_type = -1; ###END### $ nice dpkg-buildpackage -b -j4 -nc (note: build tests will fail if root) Then, from a privileged account [adjust for version/arch] # dpkg -I ../libssl1.1_1.1.0f-1_amd64.deb # dpkg -I ../openssl_1.1.0f-1_amd64.deb Check that ZLIB is no longer a disabled algorithm: # openssl list -disabled It should also be listed as -DZLIB and -DZLIB_SHARED in: # openssl version -f # service postgresql restart == Future thoughts == If compression is unavailable it may become a competitive issue (MySQL/MariaDB offer zlib/deflate-based compression toggled via slave_compressed_protocol), or a reason to avoid streaming physical replication - possibly logical as well, I don't have experience there. Uncompressed replication roughly triples the required bandwidth/transfer, which can translate into significant costs or performance issues. In my case, compression means I can remain within a 10TB/month budget on a server used for cascading replication. The feeling in 2012 was that transport compression isn't within PostgreSQL's wheelhouse (which is why it remains important to enable it where possible in OpenSSL): https://www.postgresql.org/message-id/flat/4FD9E70B.9040607%40timbira.com#4FD9E70B.9040607@timbira.com This is a fair argument; however, TLS 1.3 removes compression: https://tools.ietf.org/html/draft-ietf-tls-tls13-20 - "Other cryptographic improvements including the removal ofcompression and custom DHE groups..." ...and this will be included in OpensSSL 1.1.1+, likely this year: https://www.openssl.org/blog/blog/2017/05/04/tlsv1.3/ So it may become necessary to use *something* in PostgreSQL 11+, be it zlib, PGLZ ( http://paquier.xyz/postgresql-2/postgres-9-5-feature-highlight-pglz-compression-libpqcommon/ ), or another algorithm. Or specify TLS 1.2. But that would need further code changes, too - and you have to use an outdated security protocol for compression" does not sound compelling. Best regards, -- Laurence "GreenReaper" Parry - Inkbunny administrator greenreaper.co.uk - wikifur.com - flayrah.com - inkbunny.net "Eternity lies ahead of us, and behind. Have you drunk your fill?" -- Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-bugs
Re: [BUGS] BUG #14686: OpenSSL 1.1.0+ breaks PostgreSQL's sslcompression assumption, defaults to SSL_OP_NO_COMPRESSION
From
Tom Lane
Date:
greenreaper@hotmail.com writes: > PostgreSQL is documented to compress data over SSL connections by default > where possible: > https://www.postgresql.org/docs/9.6/static/libpq-connect.html#LIBPQ-CONNECT-SSLCOMPRESSION > PostgreSQL assumes that OpenSSL 0.9.8+ will compress with zlib if it can. > However, OpenSSL 1.1.0+ - already in Manjaro, and the upcoming Debian 9 > 'Stretch', Fedora 26, and Tails 3.0 - sets SSL_OP_NO_COMPRESSION by default > to discourage the CRIME attack: So the actual issue here, which you've not addressed in this otherwise extensive screed, is whether it's a wise thing for us to override that decision. Should we not just change sslcompression into a no-op? Is there some reason why PG data is immune to the CRIME attack? We might in the future consider compressing the data for ourselves inside the SSL stream, but (a) that would be a protocol break, with a pile of unpleasant compatibility consequences, and (b) if compression by OpenSSL itself makes the stream more decryptable, wouldn't app-provided compression inside the stream also do that? In short I'm wondering whether app-driven transport data compression is an idea whose time has passed. regards, tom lane -- Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-bugs
Re: [BUGS] BUG #14686: OpenSSL 1.1.0+ breaks PostgreSQL'ssslcompression assumption, defaults to SSL_OP_NO_COMPRESSION
From
Laurence Parry
Date:
> So the actual issue here, which you've not addressed in
> this otherwise extensive screed, is whether it's a wise
> thing for us to override that decision.
>
> Is there some reason why PG data is immune to the CRIME attack?
I didn't address the security implications because I am not a security expert.
It would be a good idea for a security professional to evaluate the protocol.
If you want, I can make a few guesses, to be taken with a large pinch of salt:1) Many PostgreSQL connections operate over networks which are believed to be secure. This came up last year in postgres-hackers, and there were others who felt that CRIME was not a significant concern in most of their deployments:
In this case, administrators may be using SSL *only* for the compression benefits, because there is no separate compression feature. There is still an argument for defence-in-depth, but it is not as compelling in such situations.
[Bear in mind that unexpected loss of compression - say, after upgrading a standby - can impact the stability of a replication setup with specified bandwidth limits. Suddenly, the load triples - perhaps 5Mbps -> 15Mbps, on a 10Mbps leased line. Replication lags, WAL backs up - and before you know it, you're out of disk space on the *primary*, without even touching it. This may only be noticed once the server gets busy - say, after the maintenance window in which you upgraded the standby - and is compounded by the fact that the only way you know what's happened is by capturing the SSL handshakes, or deduce it from the change in bandwidth usage.]
2) HTTPS is particularly vulnerable to CRIME because unrelated information (much of which the attacker knows and/or controls) is regularly compressed and transferred with a static authentication cookie which they want to discover.
PostgreSQL does not handle authentication in quite the same way. It is done only at connection startup; credentials are transferred separately from other data, and the authentication persists for the connection lifetime, which is often extensive:
Now, ZLIB-based SSL compression is stateful, so if an attacker can get a client to open many connections, they might be vulnerable if they can also get information into the first 32KB transmitted and draw an inference from there. But it's likely to be harder to determine a match, especially if they don't know the queries being made.
3) Applications which are separated from the database over a network are also likely to be using a connection pooler, which holds open a set of of active connections and does not consistently repeat authentication when new requests are made.
4) In my own use-case, network connections are only used for replication, which doesn't have the multiple-connections issue - if a slot is in use, the master will refuse additional connections (I know this well from using a somewhat unreliable WAN). Maybe there is some MITM attack which could be used to repeatedly drop and re-establish the connection, but this is likely to be noticeable in the logs/performance. If using certificates for identification, that kind of attack should be infeasible.
5) A WAL stream or other connection might contain other data which they could try to match. But even if specific plaintext can be inserted, *and* they can get a secret included too, an active connection is likely transferring other content as well. It lacks the same consistency as as a stream of POSTs which the attacker controls, containing a constant secret at a constant location. (synchronous_commit='off' may make this harder, though I don't know how immediate streaming replication is.)
> Should we not just change sslcompression into a no-op?
Well, it effectively *is* a no-op on OpenSSL 1.1.0+. That's what I want to fix! Losing the ability to compress the transport should, in itself, be considered a regression. I don't think every PostgreSQL user on a modern OS should have to patch their copy of OpenSSL because PostgreSQL isn't doing what it claims to. :-)
Making sslcompression a no-op would also stop administrators from disabling SSL compression just for PostgreSQL on platforms where it *is* on by default - i.e. OpenSSL 0.9.8x/1.0.x where the distro hasn't patched-out ZLIB - which is currently the point of the parameter.
I guess maybe you meant it should always set no-compression? There's an argument that PostgreSQL's defaults should be the safest possible. From that perspective, it may be reasonable to change the default to not be compressed, at least for 10. But even if this is done, PostgresSQL should clear the no-compression flag if sslcompression=1, as that is a clear expression of intent by the administrator.
PostgreSQL is used in a variety of situations. In some of those, SSL compression may be seen as inadvisable. In others, it is beneficial. This is about making sure administrators can continue to choose it as an option based on their situation.
PostgreSQL already trusts administrators to make decisions about security trade-offs, otherwise it might forbid connections without SSL entirely - or at least have 'require' rather than 'prefer' as a default. It _would_ be a good idea to communicate concerns in the documentation, so administrators can make more-educated decisions.
> In short I'm wondering whether app-driven transport data
> compression is an idea whose time has passed.
If anything it seems far *more* suitable for the app to do it vs. delegating to the transport, because it has knowledge of the sensitivity of the data.
For example, it might use a stateless ZLIB replacement ( http://www.libslz.org/ ) during the authentication phase, and revert to regular ZLIB operation during WAL streaming. Or just use SLZ all the time, accepting that compression will be worse (but still with a ~55% saving), and faster to boot.
But that would be a separate feature. This bug is about preserving an existing documented feature, which is seen as useful in many use-cases:
...at least until there is a good replacement for it.--
Laurence "GreenReaper" Parry