Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7ac955b

Browse files
committed
Allow SCRAM authentication, when pg_hba.conf says 'md5'.
If a user has a SCRAM verifier in pg_authid.rolpassword, there's no reasonwe cannot attempt to perform SCRAM authentication instead of MD5. The worstthat can happen is that the client doesn't support SCRAM, and theauthentication will fail. But previously, it would fail for sure, becausewe would not even try. SCRAM is strictly more secure than MD5, so there'sno harm in trying it. This allows for a more graceful transition from MD5passwords to SCRAM, as user passwords can be changed to SCRAM verifiersincrementally, without changing pg_hba.conf.Refactor the code in auth.c to support that better. Notably, we now have tolook up the user's pg_authid entry before sending the password challenge,also when performing MD5 authentication. Also simplify the concept of a"doomed" authentication. Previously, if a user had a password, but it hadexpired, we still performed SCRAM authentication (but always returned errorat the end) using the salt and iteration count from the expired password.Now we construct a fake salt, like we do when the user doesn't have apassword or doesn't exist at all. That simplifies get_role_password(), andwe can don't need to distinguish the "user has expired password", and"user does not exist" cases in auth.c.On second thoughts, also rename uaSASL to uaSCRAM. It refers to themechanism specified in pg_hba.conf, and while we use SASL for SCRAMauthentication at the protocol level, the mechanism should be called SCRAM,not SASL. As a comparison, we have uaLDAP, even though it looks like theplain 'password' authentication at the protocol level.Discussion:https://www.postgresql.org/message-id/6425.1489506016@sss.pgh.pa.usReviewed-by: Michael Paquier
1 parent7887453 commit7ac955b

File tree

9 files changed

+214
-165
lines changed

9 files changed

+214
-165
lines changed

‎doc/src/sgml/client-auth.sgml

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -412,23 +412,22 @@ hostnossl <replaceable>database</replaceable> <replaceable>user</replaceable>
412412
</varlistentry>
413413

414414
<varlistentry>
415-
<term><literal>md5</></term>
415+
<term><literal>scram</></term>
416416
<listitem>
417417
<para>
418-
Require the client to supply a double-MD5-hashed password for
419-
authentication.
420-
See <xref linkend="auth-password"> for details.
418+
Perform SCRAM-SHA-256 authentication to verify the user's
419+
password. See <xref linkend="auth-password"> for details.
421420
</para>
422421
</listitem>
423422
</varlistentry>
424423

425424
<varlistentry>
426-
<term><literal>scram</></term>
425+
<term><literal>md5</></term>
427426
<listitem>
428427
<para>
429-
Perform SCRAM-SHA-256 authentication to verify the user's
430-
password.
431-
See <xref linkend="auth-password">for details.
428+
Perform SCRAM-SHA-256or MD5authentication to verify the
429+
user'spassword. See <xref linkend="auth-password">
430+
for details.
432431
</para>
433432
</listitem>
434433
</varlistentry>
@@ -689,13 +688,12 @@ host postgres all 192.168.12.10/32 scram
689688
# Allow any user from hosts in the example.com domain to connect to
690689
# any database if the user's password is correctly supplied.
691690
#
692-
# Most users use SCRAM authentication, but some users use older clients
693-
# that don't support SCRAM authentication, and need to be able to log
694-
# in using MD5 authentication. Such users are put in the @md5users
695-
# group, everyone else must use SCRAM.
691+
# Require SCRAM authentication for most users, but make an exception
692+
# for user 'mike', who uses an older client that doesn't support SCRAM
693+
# authentication.
696694
#
697695
# TYPE DATABASE USER ADDRESS METHOD
698-
host all@md5users .example.com md5
696+
host allmike .example.com md5
699697
host all all .example.com scram
700698

701699
# In the absence of preceding "host" lines, these two lines will
@@ -949,12 +947,13 @@ omicron bryanh guest1
949947
</para>
950948

951949
<para>
952-
In <literal>md5</>, the client sends a hash of a random challenge,
953-
generated by the server, and the password. It prevents password sniffing,
954-
but is less secure than <literal>scram</>, and provides no protection
955-
if an attacker manages to steal the password hash from the server.
956-
<literal>md5</> cannot be used with the <xref
957-
linkend="guc-db-user-namespace"> feature.
950+
<literal>md5</> allows falling back to a less secure challenge-response
951+
mechanism for those users with an MD5 hashed password.
952+
The fallback mechanism also prevents password sniffing, but provides no
953+
protection if an attacker manages to steal the password hash from the
954+
server, and it cannot be used with the <xref
955+
linkend="guc-db-user-namespace"> feature. For all other users,
956+
<literal>md5</> works the same as <literal>scram</>.
958957
</para>
959958

960959
<para>

‎src/backend/libpq/auth-scram.c

Lines changed: 58 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -130,79 +130,91 @@ static char *scram_MockSalt(const char *username);
130130
* after the beginning of the exchange with verifier data.
131131
*
132132
* 'username' is the provided by the client. 'shadow_pass' is the role's
133-
* password verifier, from pg_authid.rolpassword. If 'doomed' istrue, the
134-
* authenticationmustfail, as if an incorrect password was given.
135-
*'shadow_pass' may be NULL, when 'doomed' is set.
133+
* password verifier, from pg_authid.rolpassword. If 'shadow_pass' isNULL, we
134+
*still perform anauthenticationexchange, but it willfail, as if an
135+
*incorrect password was given.
136136
*/
137137
void*
138-
pg_be_scram_init(constchar*username,constchar*shadow_pass,booldoomed)
138+
pg_be_scram_init(constchar*username,constchar*shadow_pass)
139139
{
140140
scram_state*state;
141-
intpassword_type;
141+
boolgot_verifier;
142142

143143
state= (scram_state*)palloc0(sizeof(scram_state));
144144
state->state=SCRAM_AUTH_INIT;
145145
state->username=username;
146146

147147
/*
148-
* Perform sanity checks on the provided password after catalog lookup.
149-
* The authentication is bound to fail if the lookup itself failed or if
150-
* the password stored is MD5-encrypted. Authentication is possible for
151-
* users with a valid plain password though.
148+
* Parse the stored password verifier.
152149
*/
150+
if (shadow_pass)
151+
{
152+
intpassword_type=get_password_type(shadow_pass);
153153

154-
if (shadow_pass==NULL||doomed)
155-
password_type=-1;
156-
else
157-
password_type=get_password_type(shadow_pass);
154+
if (password_type==PASSWORD_TYPE_SCRAM)
155+
{
156+
if (parse_scram_verifier(shadow_pass,&state->salt,&state->iterations,
157+
state->StoredKey,state->ServerKey))
158+
got_verifier= true;
159+
else
160+
{
161+
/*
162+
* The password looked like a SCRAM verifier, but could not be
163+
* parsed.
164+
*/
165+
elog(LOG,"invalid SCRAM verifier for user \"%s\"",username);
166+
got_verifier= false;
167+
}
168+
}
169+
elseif (password_type==PASSWORD_TYPE_PLAINTEXT)
170+
{
171+
/*
172+
* The stored password is in plain format. Generate a fresh SCRAM
173+
* verifier from it, and proceed with that.
174+
*/
175+
char*verifier;
158176

159-
if (password_type==PASSWORD_TYPE_SCRAM)
160-
{
161-
if (!parse_scram_verifier(shadow_pass,&state->salt,&state->iterations,
162-
state->StoredKey,state->ServerKey))
177+
verifier=scram_build_verifier(username,shadow_pass,0);
178+
179+
(void)parse_scram_verifier(verifier,&state->salt,&state->iterations,
180+
state->StoredKey,state->ServerKey);
181+
pfree(verifier);
182+
183+
got_verifier= true;
184+
}
185+
else
163186
{
164187
/*
165-
* Thepassword looked like aSCRAM verifier,but couldnot be
166-
*parsed.
188+
* Theuser doesn't haveSCRAM verifier,nor couldwe generate
189+
*one. (You cannot do SCRAM authentication with an MD5 hash.)
167190
*/
168-
elog(LOG,"invalid SCRAM verifier for user \"%s\"",username);
169-
doomed= true;
191+
state->logdetail=psprintf(_("User \"%s\" does not have a valid SCRAM verifier."),
192+
state->username);
193+
got_verifier= false;
170194
}
171195
}
172-
elseif (password_type==PASSWORD_TYPE_PLAINTEXT)
196+
else
173197
{
174-
char*verifier;
175-
176198
/*
177-
* Thepassword provided is in plain format, in which case a fresh
178-
*SCRAM verifier can be generated and used for the rest of the
179-
*processing.
199+
* Thecaller requested us to perform a dummy authentication. This is
200+
*considered normal, since the caller requested it, so don't set log
201+
*detail.
180202
*/
181-
verifier=scram_build_verifier(username,shadow_pass,0);
182-
183-
(void)parse_scram_verifier(verifier,&state->salt,&state->iterations,
184-
state->StoredKey,state->ServerKey);
185-
pfree(verifier);
203+
got_verifier= false;
186204
}
187-
else
188-
doomed= true;
189205

190-
if (doomed)
206+
/*
207+
* If the user did not have a valid SCRAM verifier, we still go through
208+
* the motions with a mock one, and fail as if the client supplied an
209+
* incorrect password. This is to avoid revealing information to an
210+
* attacker.
211+
*/
212+
if (!got_verifier)
191213
{
192-
/*
193-
* We don't have a valid SCRAM verifier, nor could we generate one, or
194-
* the caller requested us to perform a dummy authentication.
195-
*
196-
* The authentication is bound to fail, but to avoid revealing
197-
* information to the attacker, go through the motions with a fake
198-
* SCRAM verifier, and fail as if the password was incorrect.
199-
*/
200-
state->logdetail=psprintf(_("User \"%s\" does not have a valid SCRAM verifier."),
201-
state->username);
202214
mock_scram_verifier(username,&state->salt,&state->iterations,
203215
state->StoredKey,state->ServerKey);
216+
state->doomed= true;
204217
}
205-
state->doomed=doomed;
206218

207219
returnstate;
208220
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp