Re: SCRAM with channel binding downgrade attack
Michael Paquier <michael@paquier.xyz>
Attachments
- 0001-Rework-scram_channel_binding-to-protect-from-downgra.patch (text/x-diff) patch 0001
On Sat, Jun 02, 2018 at 01:08:56PM -0400, Heikki Linnakangas wrote:
> On 28/05/18 15:08, Michael Paquier wrote:
>> On Mon, May 28, 2018 at 12:26:37PM +0300, Heikki Linnakangas wrote:
>> > Sounds good.
>>
>> Okay. Done this way as attached. If the backend forces anything else
>> than SCRAM then the client gets an immediate error if channel binding is
>> required, without waiting for the password prompt.
>
> Thanks! The comments and error messages need some copy-editing:
Thanks Heikki for the input. I have reworked all the points you raised
in the attached.
>> /*
>> * Select the mechanism to use. Pick SCRAM-SHA-256-PLUS over anything
>> * else if a channel binding mode is not 'disable'. Pick SCRAM-SHA-256
>> * if nothing else has already been picked. If we add more mechanisms, a
>> * more refined priority mechanism might become necessary.
>> */
>
> "else if a channel binding mode is not 'disable'" sounds a bit awkward. A
> double negative. (Also, "a" -> "the")
Okay. I have completely rewritten this block. Hopefully that's clearer.
>> + /*
>> + * If client is willing to enforce the use the channel binding but
>> + * it has not been previously selected, because it was either not
>> + * published by the server or could not be selected, then complain
>> + * back. If SSL is not used for this connection, still complain
>> + * similarly, as the client may want channel binding but forgot
>> + * to set it up to do so which could be the case with sslmode=prefer
>> + * for example. This protects from any kind of downgrade attacks
>> + * from rogue servers attempting to bypass channel binding.
>> + */
>
> Instead of "is willing to enforce the use the channel binding", perhaps
> simply "requires channel binding".
Check.
>> + printfPQExpBuffer(&conn->errorMessage,
>> + libpq_gettext("channel binding required for SASL authentication but no valid mechanism could be selected\n"));
>
> Channel binding is a property of SCRAM authentication specifically, it's not
> applicable to other SASL mechanisms. So I'd suggest something like:
>
> "server does not support channel binding, and channel_binding_mode=require
> was used"
Changed as such, except that this is using scram_channel_binding_mode in
the error message.
>> + /*
>> + * Complain if channel binding mechanism is chosen but no channel
>> + * binding type is defined.
>> + */
>> + if (strcmp(selected_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0 &&
>> + conn->scram_channel_binding_type == NULL)
>> + {
>> + printfPQExpBuffer(&conn->errorMessage,
>> + libpq_gettext("SASL authentication mechanism using channel binding supported but no channel binding type defined\n"));
>> + goto error;
>> + }
>
> It's not immediately clear to me from the error message or the comment, when
> this error is thrown. Can this even happen?
No, let's not make this happen then. I have added NULL handling in
connectOptions2 related to the initialization of the options so both
scram_channel_binding_mode and scram_channel_binding_type will never be
NULL like sslmode.
>> + /*
>> + * Before processing any message, perform security-related sanity
>> + * checks. If the client is willing to perform channel binding with
>> + * SCRAM authentication, only a subset of messages can be used so
>> + * as there is no transmission of any password data or such.
>> + */
>
> I'd suggest something like:
>
> "If SCRAM with channel binding is required, refuse all other authentication
> methods. Requiring channel binding implies that the client doesn't trust the
> server, until the SCRAM authentication is completed, so it's important that
> we don't divulge the plaintext password, or perform some weaker
> authentication, even if the server asks for it. In all other authentication
> methods, it's currently assumed that the client trusts the server, either
> implicitly or because the SSL certificate was already verified during the
> SSL handshake."
Check. Thanks for the suggestion.
>> + printfPQExpBuffer(&conn->errorMessage,
>> + libpq_gettext("channel binding required for authentication but invalid protocol used\n"));
>
> If I understand correctly, you get this error, e.g. if you have "password"
> or "sspi" in pg_hba.conf, and the client uses
> "channel_binding_mode=require". "Invalid protocol" doesn't sound right for
> that. Perhaps "channel binding required, but the server requested %s
> authentication".
Right, even "md5" enters in this category if the user has a MD5
verifier, but not if it has a SCRAM verifier. I have done that with
get_auth_request_str(), which maps authentication requests to the
probable hba entry. It feels like cheating to map "trust" to
AUTH_REQ_OK as all methods use it as final message though, even if it is
not triggered by this patch. So I have used no mapping name for it.
> Is it possible to have an error hint here? Perhaps add
> "HINT: change the authentication method to scram-sha-256 in the server's
> pg_hba.conf file".
Hm. A HINT would require something similar to PQresultErrorField for
error hints, which is a fight I not much willing to do just for this
patch. Spawning a new error message with a newline would also be
considered as a new error message. So I discard this one.
I have also added a test with a "password" server which stresses this
code path actually, and I just indented the patch. What do you think?
--
Michael
Commits
-
doc: update PG 11 release notes
- 6eb612fea9d0 12.0 cited
-
Fix misspelled pg_trgm contrib name in PostgreSQL 11 release notes
- 3abc5a67edfd 12.0 landed
-
Doc: clarify release note text about v11's new window function features.
- 510421c45fb4 11.0 landed
- 11a3aeeb5e17 12.0 landed
-
Improve wording of release notes item
- bee6a683a5c3 11.0 landed
-
Fix typos in release notes
- fb6accd27b99 11.0 landed
-
Doc: preliminary list of PG11 major features.
- 4aad161c9a6d 11.0 landed
-
Make numeric power() handle NaNs according to the modern POSIX spec.
- d1fc750b5199 11.0 landed
-
Various improvements of skipping index scan during vacuum technics
- 8e12f4a250d2 11.0 cited
-
Revert back-branch changes in power()'s behavior for NaN inputs.
- f74d83b3034f 10.4 cited
-
Avoid wrong results for power() with NaN input on more platforms.
- 6bdf1303b34b 11.0 cited
-
Avoid wrong results for power() with NaN input on some platforms.
- 61b200e2f582 11.0 cited
-
Skip full index scan during cleanup of B-tree indexes when possible
- 857f9c36cda5 11.0 cited
-
Rewrite the code that applies scan/join targets to paths.
- 11cf92f6e2e1 11.0 cited
-
Postpone generate_gather_paths for topmost scan/join rel.
- 3f90ec8597c3 11.0 cited
-
Add casts from jsonb
- c0cbe00fee6d 11.0 cited
-
Make plpgsql use its DTYPE_REC code paths for composite-type variables.
- 4b93f57999a2 11.0 cited
-
Don't allow VACUUM VERBOSE ANALYZE VERBOSE.
- 921059bd66c7 11.0 cited
-
Pass InitPlan values to workers via Gather (Merge).
- e89a71fb449a 11.0 cited
-
Account for the effect of lossy pages when costing bitmap scans.
- 5edc63bda68a 11.0 cited
-
Allow no-op GiST support functions to be omitted.
- d3a4f89d8a3e 11.0 cited
-
Rearm statement_timeout after each executed query.
- f8e5f156b30e 11.0 cited
-
Push limit through subqueries to underlying sort, where possible.
- 1f6d515a67ec 11.0 cited