Hi all, As touched on in past threads, our SCRAM implementation is slightly nonstandard and doesn't always protect the entirety of the authentication handshake:
- the username in the startup packet is not covered by the SCRAM crypto and can be tampered with if channel binding is not in effect, or by an attacker holding only the server's key - low iteration counts accepted by the client make it easier than it probably should be for a MITM to brute-force passwords (note that PG16's scram_iterations GUC, being server-side, does not mitigate this) - by default, a SCRAM exchange can be exited by the server prior to sending its verifier, skipping the client's server authentication step (this is mitigated by requiring channel binding, and PG16 adds require_auth=scram-sha-256 to help as well) These aren't currently considered security vulnerabilities, but it'd be good for the documentation to call them out, considering mutual authentication is one of the design goals of the SCRAM RFC. (I'd also like to shore up these problems, eventually, to make SCRAM-based mutual authn viable with Postgres. But that work has stalled a bit on my end.) Here's a patch to explicitly warn people away from SCRAM as a form of server authentication, and nudge them towards a combination with verified TLS or gssenc. I've tried to keep the text version-agnostic, to make a potential backport easier. Is this a good place for the warning to go? Should I call out that GSS can't use channel binding, or promote the use of TLS versus GSS for SCRAM, or just keep it simple? Thanks, --Jacob
From 5b346313f1cecd3c4c79b6e104094e50bb1cfa75 Mon Sep 17 00:00:00 2001 From: Jacob Champion <jchamp...@timescale.com> Date: Mon, 22 May 2023 16:46:23 -0700 Subject: [PATCH] docs: encourage strong server verification with SCRAM The server verification in libpq's SCRAM implementation can be subverted in various ways. While mitigations for some of the issues exist, it's probably wise for most users to combine it with strong server authentication, to avoid entering a SCRAM exchange with an untrusted server. Recommend that in the docs. --- doc/src/sgml/runtime.sgml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml index dbe23db54f..cf93d9443c 100644 --- a/doc/src/sgml/runtime.sgml +++ b/doc/src/sgml/runtime.sgml @@ -2021,6 +2021,21 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433 authentication with them. The TCP client must connect using <literal>gssencmode=require</literal>. </para> + + <warning> + <para> + While the SCRAM authentication method (<xref linkend="auth-password"/>) + theoretically provides a form of server authentication without the use of + certificates, the current SCRAM implementation does not protect the entire + authentication exchange. A spoofed server (or an active attacker on the + network) may tamper with the startup packet or attempt to bypass the + client's server verification step. Additionally, an attacker on the wire + may use an intercepted SCRAM exchange to begin a brute-force attack + against the password offline. It's recommended to employ strong server + authentication, using one of the above anti-spoofing measures, to prevent + these attacks. + </para> + </warning> </sect1> <sect1 id="encryption-options"> -- 2.25.1