10000 Make SCRAM iteration count configurable · postgrespro/postgres@b577743 · GitHub
[go: up one dir, main page]

Skip to content

Commit b577743

Browse files
Make SCRAM iteration count configurable
Replace the hardcoded value with a GUC such that the iteration count can be raised in order to increase protection against brute-force attacks. The hardcoded value for SCRAM iteration count was defined to be 4096, which is taken from RFC 7677, so set the default for the GUC to 4096 to match. In RFC 7677 the recommendation is at least 15000 iterations but 4096 is listed as a SHOULD requirement given that it's estimated to yield a 0.5s processing time on a mobile handset of the time of RFC writing (late 2015). Raising the iteration count of SCRAM will make stored passwords more resilient to brute-force attacks at a higher computational cost during connection establishment. Lowering the count will reduce computational overhead during connections at the tradeoff of reducing strength against brute-force attacks. There are however platforms where even a modest iteration count yields a too high computational overhead, with weaker password encryption schemes chosen as a result. In these situations, SCRAM with a very low iteration count still gives benefits over weaker schemes like md5, so we allow the iteration count to be set to one at the low end. The new GUC is intentionally generically named such that it can be made to support future SCRAM standards should they emerge. At that point the value can be made into key:value pairs with an undefined key as a default which will be backwards compatible with this. Reviewed-by: Michael Paquier <michael@paquier.xyz> Reviewed-by: Jonathan S. Katz <jkatz@postgresql.org> Discussion: https://postgr.es/m/F72E7BC7-189F-4B17-BF47-9735EB72C364@yesql.se
1 parent c15631f commit b577743

File tree

16 files changed

+94
-10
lines changed

16 files changed

+94
-10
lines changed

doc/src/sgml/config.sgml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,26 @@ include_dir 'conf.d'
11321132
</listitem>
11331133
</varlistentry>
11341134

1135+
<varlistentry>
1136+
<term><varname>scram_iterations</varname> (<type>integer</type>)
1137+
<indexterm>
1138+
<primary><varname>scram_iterations</varname> configuration parameter</primary>
1139+
</indexterm>
1140+
</term>
1141+
<listitem>
1142+
<para>
1143+
The number of computational iterations to be performed when encrypting
1144+
a password using SCRAM-SHA-256. The default is <literal>4096</literal>.
1145+
A higher number of iterations provides additional protection against
1146+
brute-force attacks on stored passwords, but makes authentication
1147+
slower. Changing the value has no effect on existing passwords
1148+
encrypted with SCRAM-SHA-256 as the iteration count is fixed at the
1149+
time of encryption. In order to make use of a changed value, a new
1150+
password must be set.
1151+
</para>
1152+
</listitem>
1153+
</varlistentry>
1154+
11351155
<varlistentry id="guc-krb-server-keyfile" xreflabel="krb_server_keyfile">
11361156
<term><varname>krb_server_keyfile</varname> (<type>string</type>)
11371157
<indexterm>

src/backend/libpq/auth-scram.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@ static char *scram_mock_salt(const char *username,
191191
pg_cryptohash_type hash_type,
192192
int key_length);
193193

194+
/*
195+
* The number of iterations to use when generating new secrets.
196+
*/
197+
int scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
198+
194199
/*
195200
* Get a list of SASL mechanisms that this module supports.
196201 341A
*
@@ -496,7 +501,7 @@ pg_be_scram_build_secret(const char *password)
496501

497502
result = scram_build_secret(PG_SHA256, SCRAM_SHA_256_KEY_LEN,
498503
saltbuf, SCRAM_DEFAULT_SALT_LEN,
499-
SCRAM_DEFAULT_ITERATIONS, password,
504+
scram_sha_256_iterations, password,
500505
&errstr);
501506

502507
if (prep_password)
@@ -717,7 +722,7 @@ mock_scram_secret(const char *username, pg_cryptohash_type *hash_type,
717722
encoded_salt[encoded_len] = '\0';
718723

719724
*salt = encoded_salt;
720-
*iterations = SCRAM_DEFAULT_ITERATIONS;
725+
*iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
721726

722727
/* StoredKey and ServerKey are not used in a doomed authentication */
723728
memset(stored_key, 0, SCRAM_MAX_KEY_LEN);

src/backend/utils/misc/guc_tables.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@
4141
#include "commands/trigger.h"
4242
#include "commands/user.h"
4343
#include "commands/vacuum.h"
44+
#include "common/scram-common.h"
4445
#include "jit/jit.h"
4546
#include "libpq/auth.h"
4647
#include "libpq/libpq.h"
48+
#include "libpq/scram.h"
4749
#include "nodes/queryjumble.h"
4850
#include "optimizer/cost.h"
4951
#include "optimizer/geqo.h"
@@ -3468,6 +3470,17 @@ struct config_int ConfigureNamesInt[] =
34683470
NULL, NULL, NULL
34693471
},
34703472

3473+
{
3474+
{"scram_iterations", PGC_USERSET, CONN_AUTH_AUTH,
3475+
gettext_noop("Sets the iteration count for SCRAM secret generation."),
3476+
NULL,
3477+
GUC_REPORT
3478+
},
3479+
&scram_sha_256_iterations,
3480+
SCRAM_SHA_256_DEFAULT_ITERATIONS, 1, INT_MAX,
3481+
NULL, NULL, NULL
3482+
},
3483+
34713484
/* End-of-list marker */
34723485
{
34733486
{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL

src/backend/utils/misc/postgresql.conf.sample

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595

9696
#authentication_timeout = 1min # 1s-600s
9797
#password_encryption = scram-sha-256 # scram-sha-256 or md5
98+
#scram_iterations = 4096
9899
#db_user_namespace = off
99100

100101
# GSSAPI using Kerberos

src/common/scram-common.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,7 @@ scram_build_secret(pg_cryptohash_type hash_type, int key_length,
214214
/* Only this hash method is supported currently */
215215
Assert(hash_type == PG_SHA256);
216216

217-
if (iterations <= 0)
218-
iterations = SCRAM_DEFAULT_ITERATIONS;
217+
Assert(iterations > 0);
219218

220219
/* Calculate StoredKey and ServerKey */
221220
if (scram_SaltedPassword(password, hash_type, key_length,

src/include/common/scram-common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
* Default number of iterations when generating secret. Should be at least
4848
* 4096 per RFC 7677.
4949
*/
50-
#define SCRAM_DEFAULT_ITERATIONS 4096
50+
#define SCRAM_SHA_256_DEFAULT_ITERATIONS 4096
5151

5252
extern int scram_SaltedPassword(const char *password,
5353
pg_cryptohash_type hash_type, int key_length,

src/include/libpq/scram.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
#include "libpq/libpq-be.h"
1919
#include "libpq/sasl.h"
2020

21+
/* Number of iterations when generating new secrets */
22+
extern PGDLLIMPORT int scram_sha_256_iterations;
23+
2124
/* SASL implementation callbacks */
2225
extern PGDLLIMPORT const pg_be_sasl_mech pg_be_scram_mech;
2326

src/interfaces/libpq/fe-auth-scram.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -895,7 +895,7 @@ verify_server_signature(fe_scram_state *state, bool *match,
895895
* error details.
896896
*/
897897
char *
898-
pg_fe_scram_build_secret(const char *password, const char **errstr)
898+
pg_fe_scram_build_secret(const char *password, int iterations, const char **errstr)
899899
{
900900
char *prep_password;
901901
pg_saslprep_rc rc;
@@ -927,7 +927,7 @@ pg_fe_scram_build_secret(const char *password, const char **errstr)
927927

928928
result = scram_build_secret(PG_SHA256, SCRAM_SHA_256_KEY_LEN, saltbuf,
929929
SCRAM_DEFAULT_SALT_LEN,
930-
SCRAM_DEFAULT_ITERATIONS, password,
930+
iterations, password,
931931
errstr);
932932

933933
free(prep_password);

src/interfaces/libpq/fe-auth.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1341,7 +1341,9 @@ PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user,
13411341
{
13421342
const char *errstr = NULL;
13431343

1344-
crypt_pwd = pg_fe_scram_build_secret(passwd, &errstr);
1344+
crypt_pwd = pg_fe_scram_build_secret(passwd,
1345+
conn->scram_sha_256_iterations,
1346+
&errstr);
13451347
if (!crypt_pwd)
13461348
libpq_append_conn_error(conn, "could not encrypt password: %s", errstr);
13471349
}

src/interfaces/libpq/fe-auth.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ extern char *pg_fe_getauthname(PQExpBuffer errorMessage);
2626
/* Mechanisms in fe-auth-scram.c */
2727
extern const pg_fe_sasl_mech pg_scram_mech;
2828
extern char *pg_fe_scram_build_secret(const char *password,
29+
int iterations,
2930
const char **errstr);
3031

3132
#endif /* FE_AUTH_H */

0 commit comments

Comments
 (0)
0