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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers