Hello,Despite the addition of SCRAM authentification to PostgreSQL 10, MITM attack can be performed by saying that the server supports, for example, only md5 authentication. The possible solution for it is checking authentification method on a client side and reject connections that could be unsafe.
Postgresql server can require unencrypted password passing, md5, scram, gss or sspi authentification.
In the attached patch you can find the solution for it. The new provided features are the following: The parameter with acceptable authentification methods can be passed into connection methods of libpq library. Also, this parameter can be specified to psql as a command line argument. The documentation for command line arguments of psql and arguments of libpq methods are also presented.
Thank you for attention! Best, -- ------ Victor Drobny Postgres Professional: http://www.postgrespro.com The Russian Postgres Company
diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c index 8068a28..1877b2d 100644 --- a/src/bin/psql/startup.c +++ b/src/bin/psql/startup.c @@ -75,6 +75,7 @@ struct adhoc_opts bool no_psqlrc; bool single_txn; bool list_dbs; + char *authtype; SimpleActionList actions; }; @@ -213,7 +214,7 @@ main(int argc, char *argv[]) /* loop until we have a password if requested by backend */ do { -#define PARAMS_ARRAY_SIZE 8 +#define PARAMS_ARRAY_SIZE 9 const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords)); const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values)); @@ -232,8 +233,10 @@ main(int argc, char *argv[]) values[5] = pset.progname; keywords[6] = "client_encoding"; values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto"; - keywords[7] = NULL; - values[7] = NULL; + keywords[7] = "acc_auth"; + values[7] = options.authtype; + keywords[8] = NULL; + values[8] = NULL; new_pass = false; pset.db = PQconnectdbParams(keywords, values, true); @@ -441,6 +444,7 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options) {"single-line", no_argument, NULL, 'S'}, {"tuples-only", no_argument, NULL, 't'}, {"table-attr", required_argument, NULL, 'T'}, + {"authtype", required_argument, NULL, 'u'}, {"username", required_argument, NULL, 'U'}, {"set", required_argument, NULL, 'v'}, {"variable", required_argument, NULL, 'v'}, @@ -458,7 +462,7 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options) memset(options, 0, sizeof *options); - while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01", + while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:h:HlL:no:p:P:qR:sStT:u:U:v:VwWxXz?01", long_options, &optindex)) != -1) { switch (c) @@ -566,6 +570,9 @@ parse_psql_options(int argc, char *argv[], struct adhoc_opts * options) case 'T': pset.popt.topt.tableAttr = pg_strdup(optarg); break; + case 'u': + options->authtype = pg_strdup(optarg); + break; case 'U': options->username = pg_strdup(optarg); break; diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 4dc8924..b8e77d4 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -304,6 +304,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = { "Target-Session-Attrs", "", 11, /* sizeof("read-write") = 11 */ offsetof(struct pg_conn, target_session_attrs)}, + {"acc_auth", NULL, NULL, NULL, + "Acceptable authentification methods", "", 20, + offsetof(struct pg_conn, acc_auth)}, + /* Terminating entry --- MUST BE LAST */ {NULL, NULL, NULL, NULL, NULL, NULL, 0} @@ -1000,6 +1004,43 @@ connectOptions2(PGconn *conn) } } + /* Validate acceptable authentification methods */ + if (conn->acc_auth) + { + char * pvalue = conn->acc_auth; + char * comma = pvalue; + while ((comma = strchr(pvalue, ','))) + { + *comma = '\0'; + if (strcmp(pvalue, "password") != 0 + && strcmp(pvalue, "md5") != 0 + && strcmp(pvalue, "scram") != 0 + && strcmp(pvalue, "gss") != 0 + && strcmp(pvalue, "sspi") != 0) + { + conn->status = CONNECTION_BAD; + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("invalid authtype value: \"%s\"\n"), + pvalue); + return false; + } + *comma = ','; + pvalue = comma + 1; + } + if (strcmp(pvalue, "password") != 0 + && strcmp(pvalue, "md5") != 0 + && strcmp(pvalue, "scram") != 0 + && strcmp(pvalue, "gss") != 0 + && strcmp(pvalue, "sspi") != 0) + { + conn->status = CONNECTION_BAD; + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("invalid authtype value: \"%s\"\n"), + pvalue); + return false; + } + } + /* * validate sslmode option */ @@ -1822,6 +1863,43 @@ restoreErrorMessage(PGconn *conn, PQExpBuffer savedMessage) termPQExpBuffer(savedMessage); } +static bool +isAllowableAuth(int areq, char* acc_auth) +{ + /* Allowable authentification scheme is not specified. */ + if (acc_auth == 0) + return true; + switch (areq) + { + case AUTH_REQ_OK: + return true; + case AUTH_REQ_KRB4: + return false; // Since it is not supported anymore + case AUTH_REQ_KRB5: + return false; // Since it is not supported anymore + case AUTH_REQ_PASSWORD: + return strstr(acc_auth, "password") != NULL; + case AUTH_REQ_CRYPT: + return false; // Since it is not supported anymore + case AUTH_REQ_MD5: + return strstr(acc_auth, "md5") != NULL; + case AUTH_REQ_SCM_CREDS: + break; + case AUTH_REQ_GSS: + return strstr(acc_auth, "gss") != NULL; + case AUTH_REQ_GSS_CONT: + return strstr(acc_auth, "gss") != NULL + || strstr(acc_auth, "sspi") != NULL; + case AUTH_REQ_SSPI: + return strstr(acc_auth, "sspi") != NULL; + case AUTH_REQ_SASL: + case AUTH_REQ_SASL_CONT: + case AUTH_REQ_SASL_FIN: + return strstr(acc_auth, "scram") != NULL; + } + return true; +} + /* ---------------- * PQconnectPoll * @@ -2680,6 +2758,13 @@ keep_going: /* We will come back to here until there is } msgLength -= 4; + /* Check if authentification method is allowedable */ + if (!isAllowableAuth(areq, conn->acc_auth)) + { + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("Authentification scheme is not allowed\n")); + goto error_return; + } /* * Ensure the password salt is in the input buffer, if it's an * MD5 request. All the other authentication methods that diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 34d0492..ce55951 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -488,6 +488,8 @@ struct pg_conn * connection */ #endif + char *acc_auth; /* Acceptable authentification methods */ + /* Buffer for current error message */ PQExpBufferData errorMessage; /* expansible string */
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers