Deprecate MD5 passwords.
authorNathan Bossart <nathan@postgresql.org>
Mon, 2 Dec 2024 19:30:07 +0000 (13:30 -0600)
committerNathan Bossart <nathan@postgresql.org>
Mon, 2 Dec 2024 19:30:07 +0000 (13:30 -0600)
MD5 has been considered to be unsuitable for use as a cryptographic
hash algorithm for some time.  Furthermore, MD5 password hashes in
PostgreSQL are vulnerable to pass-the-hash attacks, i.e., knowing
the username and hashed password is sufficient to authenticate.
The SCRAM-SHA-256 method added in v10 is not subject to these
problems and is considered to be superior to MD5.

This commit marks MD5 password support in PostgreSQL as deprecated
and to be removed in a future release.  The documentation now
contains several deprecation notices, and CREATE ROLE and ALTER
ROLE now emit deprecation warnings when setting MD5 passwords.  The
warnings can be disabled by setting the md5_password_warnings
parameter to "off".

Reviewed-by: Greg Sabino Mullane, Jim Nasby
Discussion: https://postgr.es/m/ZwbfpJJol7lDWajL%40nathan

16 files changed:
contrib/passwordcheck/expected/passwordcheck.out
contrib/passwordcheck/expected/passwordcheck_1.out
contrib/passwordcheck/sql/passwordcheck.sql
doc/src/sgml/catalogs.sgml
doc/src/sgml/client-auth.sgml
doc/src/sgml/config.sgml
doc/src/sgml/libpq.sgml
doc/src/sgml/protocol.sgml
doc/src/sgml/ref/create_role.sgml
doc/src/sgml/runtime.sgml
src/backend/libpq/crypt.c
src/backend/utils/misc/guc_tables.c
src/backend/utils/misc/postgresql.conf.sample
src/include/libpq/crypt.h
src/test/regress/expected/password.out
src/test/regress/expected/password_1.out

index 2027681daf664c24ccdb0641523979444517e5fe..dfb2ccfe00851a7b34e3d71be0b52256710afedb 100644 (file)
@@ -1,3 +1,4 @@
+SET md5_password_warnings = off;
 LOAD 'passwordcheck';
 CREATE USER regress_passwordcheck_user1;
 -- ok
index 5d8d5dcc1c21b8f1eba47dabfda83ceff0b080eb..9519d60a495e2a4296b83168d58879c80dda48e3 100644 (file)
@@ -1,3 +1,4 @@
+SET md5_password_warnings = off;
 LOAD 'passwordcheck';
 CREATE USER regress_passwordcheck_user1;
 -- ok
index 1fbd6b0e96e08ad57f48d25be2668647d152a6e9..5953ece5c26a88d467dde277a60009f3db06b2c3 100644 (file)
@@ -1,3 +1,4 @@
+SET md5_password_warnings = off;
 LOAD 'passwordcheck';
 
 CREATE USER regress_passwordcheck_user1;
index 59bb833f48dd3a6d08293b31d881600b93d2543a..bf3cee08a93c7495119ab9016093f8be0a52b182 100644 (file)
    will store the md5 hash of <literal>xyzzyjoe</literal>.
   </para>
 
+  <warning>
+   <para>
+    Support for MD5-encrypted passwords is deprecated and will be removed in a
+    future release of <productname>PostgreSQL</productname>.  Refer to
+    <xref linkend="auth-password"/> for details about migrating to another
+    password type.
+   </para>
+  </warning>
+
   <para>
    If the password is encrypted with SCRAM-SHA-256, it has the format:
 <synopsis>
index 51343de7cadbeb6ff66f06aeef1e0e0b448fe63d..782b49c85ac5689562b6810a0ece16793ecd8da6 100644 (file)
@@ -531,6 +531,15 @@ include_dir         <replaceable>directory</replaceable>
           user's password. See <xref linkend="auth-password"/>
           for details.
          </para>
+         <warning>
+          <para>
+           Support for MD5-encrypted passwords is deprecated and will be
+           removed in a future release of
+           <productname>PostgreSQL</productname>.  Refer to
+           <xref linkend="auth-password"/> for details about migrating to
+           another password type.
+          </para>
+         </warning>
         </listitem>
        </varlistentry>
 
@@ -1260,6 +1269,14 @@ omicron         bryanh                  guest1
        server is encrypted for SCRAM (see below), then SCRAM-based
        authentication will automatically be chosen instead.
       </para>
+
+      <warning>
+       <para>
+        Support for MD5-encrypted passwords is deprecated and will be removed
+        in a future release of <productname>PostgreSQL</productname>.  Refer to
+        the text below for details about migrating to another password type.
+       </para>
+      </warning>
      </listitem>
     </varlistentry>
 
index 76ab72db9640cad19b8e3fa3def763933d22361b..e0c8325a39cbe43769e31140aa1ede7a89349a7d 100644 (file)
@@ -1124,6 +1124,14 @@ include_dir 'conf.d'
         mechanism, and hence not work with passwords encrypted with
         SCRAM-SHA-256.  See <xref linkend="auth-password"/> for more details.
        </para>
+       <warning>
+        <para>
+         Support for MD5-encrypted passwords is deprecated and will be removed
+         in a future release of <productname>PostgreSQL</productname>.  Refer
+         to <xref linkend="auth-password"/> for details about migrating to
+         another password type.
+        </para>
+       </warning>
       </listitem>
      </varlistentry>
 
@@ -7913,6 +7921,22 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-md5-password-warnings" xreflabel="md5_password_warnings">
+      <term><varname>md5_password_warnings</varname> (<type>boolean</type>)
+      <indexterm>
+       <primary><varname>md5_password_warnings</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Controls whether a <literal>WARNING</literal> about MD5 password
+        deprecation is produced when a <command>CREATE ROLE</command> or
+        <command>ALTER ROLE</command> statement sets an MD5-encrypted password.
+        The default value is <literal>on</literal>.
+       </para>
+      </listitem>
+     </varlistentry>
+
      </variablelist>
     </sect2>
      <sect2 id="runtime-config-logging-csvlog">
index bfefb1289e8a777753808034a3391599db665dfc..01f259fd0dc40f54b3d3fd5349d1d3148611f646 100644 (file)
@@ -1341,6 +1341,15 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
            <para>
             The server must request MD5 hashed password authentication.
            </para>
+           <warning>
+            <para>
+             Support for MD5-encrypted passwords is deprecated and will be
+             removed in a future release of
+             <productname>PostgreSQL</productname>.  Refer to
+             <xref linkend="auth-password"/> for details about migrating to
+             another password type.
+            </para>
+           </warning>
           </listitem>
          </varlistentry>
 
index cff0c4099e98c16ccf99a85b7cc77c034bffecb6..fb5dec1172e169548a13898f642802cbaa60d803 100644 (file)
         (Keep in mind the <function>md5()</function> function returns its
         result as a hex string.)
        </para>
+        <warning>
+         <para>
+          Support for MD5-encrypted passwords is deprecated and will be removed
+          in a future release of <productname>PostgreSQL</productname>.  Refer
+          to <xref linkend="auth-password"/> for details about migrating to
+          another password type.
+         </para>
+        </warning>
       </listitem>
      </varlistentry>
 
index f72ba9affc2d1339c0da29d14828405b44af1580..cee23b1ea6b4dcf2d9d356d07a582e64808c2912 100644 (file)
@@ -273,6 +273,14 @@ in sync when changing the above synopsis!
         different format).  This allows reloading of encrypted passwords
         during dump/restore.
        </para>
+       <warning>
+        <para>
+         Support for MD5-encrypted passwords is deprecated and will be removed
+         in a future release of <productname>PostgreSQL</productname>.  Refer
+         to <xref linkend="auth-password"/> for details about migrating to
+         another password type.
+        </para>
+       </warning>
       </listitem>
      </varlistentry>
 
index bcd81e241581d0a7ee5e545e19bfa01ab2e064de..94135e9d5ee36d0ac86b31136f19bc90d7b9552b 100644 (file)
@@ -2053,6 +2053,16 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
      is an Internet standard and is more secure than the PostgreSQL-specific
      MD5 authentication protocol.
     </para>
+
+    <warning>
+     <para>
+      Support for MD5-encrypted passwords is deprecated and will be removed in
+      a future release of <productname>PostgreSQL</productname>.  Refer to
+      <xref linkend="auth-password"/> for details about migrating to another
+      password type.
+     </para>
+    </warning>
+
    </listitem>
   </varlistentry>
 
index b01525dc28a032972a48b81151645c90d426a2b9..d37c70901b8014ccc08cff43626172d1ff0c9c98 100644 (file)
@@ -24,6 +24,8 @@
 #include "utils/syscache.h"
 #include "utils/timestamp.h"
 
+/* Enables deprecation warnings for MD5 passwords. */
+bool       md5_password_warnings = true;
 
 /*
  * Fetch stored password for a user, for authentication.
@@ -174,6 +176,14 @@ encrypt_password(PasswordType target_type, const char *role,
                           MAX_ENCRYPTED_PASSWORD_LEN)));
    }
 
+   if (md5_password_warnings &&
+       get_password_type(encrypted_password) == PASSWORD_TYPE_MD5)
+       ereport(WARNING,
+               (errcode(ERRCODE_WARNING_DEPRECATED_FEATURE),
+                errmsg("setting an MD5-encrypted password"),
+                errdetail("MD5 password support is deprecated and will be removed in a future release of PostgreSQL."),
+                errhint("Refer to the PostgreSQL documentation for details about migrating to another password type.")));
+
    return encrypted_password;
 }
 
index 9845abd6932215c13832041a34bacbedf03f0d28..8cf1afbad20c9e46fd7fb90d51e5481b28843a38 100644 (file)
@@ -2086,6 +2086,15 @@ struct config_bool ConfigureNamesBool[] =
        NULL, NULL, NULL
    },
 
+   {
+       {"md5_password_warnings", PGC_USERSET, CONN_AUTH_AUTH,
+           gettext_noop("Enables deprecation warnings for MD5 passwords."),
+       },
+       &md5_password_warnings,
+       true,
+       NULL, NULL, NULL
+   },
+
    /* End-of-list marker */
    {
        {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL
index 407cd1e08ca3e705541f77bf1cb0556042fc4c90..a2ac7575ca7e3a96b0f8f07f55d65eebb7a14459 100644 (file)
@@ -96,6 +96,7 @@
 #authentication_timeout = 1min     # 1s-600s
 #password_encryption = scram-sha-256   # scram-sha-256 or md5
 #scram_iterations = 4096
+#md5_password_warnings = on
 
 # GSSAPI using Kerberos
 #krb_server_keyfile = 'FILE:${sysconfdir}/krb5.keytab'
index 0bb44004353c434cdc4a2585f76ce163b1b5a583..db7ea7bd1f557febc3c65f50a9e71d984a6848ba 100644 (file)
@@ -25,6 +25,9 @@
  */
 #define MAX_ENCRYPTED_PASSWORD_LEN (512)
 
+/* Enables deprecation warnings for MD5 passwords. */
+extern PGDLLIMPORT bool md5_password_warnings;
+
 /*
  * Types of password hashes or secrets.
  *
index df3857460c2b6f208c495e50ac83589b06971da2..9bb3ab2818bfbb4212a23b8cc232802c3302f5f2 100644 (file)
@@ -14,8 +14,14 @@ SET password_encryption = 'scram-sha-256'; -- ok
 SET password_encryption = 'md5';
 CREATE ROLE regress_passwd1;
 ALTER ROLE regress_passwd1 PASSWORD 'role_pwd1';
+WARNING:  setting an MD5-encrypted password
+DETAIL:  MD5 password support is deprecated and will be removed in a future release of PostgreSQL.
+HINT:  Refer to the PostgreSQL documentation for details about migrating to another password type.
 CREATE ROLE regress_passwd2;
 ALTER ROLE regress_passwd2 PASSWORD 'role_pwd2';
+WARNING:  setting an MD5-encrypted password
+DETAIL:  MD5 password support is deprecated and will be removed in a future release of PostgreSQL.
+HINT:  Refer to the PostgreSQL documentation for details about migrating to another password type.
 SET password_encryption = 'scram-sha-256';
 CREATE ROLE regress_passwd3 PASSWORD 'role_pwd3';
 CREATE ROLE regress_passwd4 PASSWORD NULL;
@@ -57,14 +63,23 @@ ALTER ROLE regress_passwd2_new RENAME TO regress_passwd2;
 SET password_encryption = 'md5';
 -- encrypt with MD5
 ALTER ROLE regress_passwd2 PASSWORD 'foo';
+WARNING:  setting an MD5-encrypted password
+DETAIL:  MD5 password support is deprecated and will be removed in a future release of PostgreSQL.
+HINT:  Refer to the PostgreSQL documentation for details about migrating to another password type.
 -- already encrypted, use as they are
 ALTER ROLE regress_passwd1 PASSWORD 'md5cd3578025fe2c3d7ed1b9a9b26238b70';
+WARNING:  setting an MD5-encrypted password
+DETAIL:  MD5 password support is deprecated and will be removed in a future release of PostgreSQL.
+HINT:  Refer to the PostgreSQL documentation for details about migrating to another password type.
 ALTER ROLE regress_passwd3 PASSWORD 'SCRAM-SHA-256$4096:VLK4RMaQLCvNtQ==$6YtlR4t69SguDiwFvbVgVZtuz6gpJQQqUMZ7IQJK5yI=:ps75jrHeYU4lXCcXI4O8oIdJ3eO8o2jirjruw9phBTo=';
 SET password_encryption = 'scram-sha-256';
 -- create SCRAM secret
 ALTER ROLE  regress_passwd4 PASSWORD 'foo';
 -- already encrypted with MD5, use as it is
 CREATE ROLE regress_passwd5 PASSWORD 'md5e73a4b11df52a6068f8b39f90be36023';
+WARNING:  setting an MD5-encrypted password
+DETAIL:  MD5 password support is deprecated and will be removed in a future release of PostgreSQL.
+HINT:  Refer to the PostgreSQL documentation for details about migrating to another password type.
 -- This looks like a valid SCRAM-SHA-256 secret, but it is not
 -- so it should be hashed with SCRAM-SHA-256.
 CREATE ROLE regress_passwd6 PASSWORD 'SCRAM-SHA-256$1234';
index bd0c2e48de040a63dcba1c9170990e4a31108622..8f613e976a6b80082af36c00f8e353dd7ddef37f 100644 (file)
@@ -61,12 +61,18 @@ ALTER ROLE regress_passwd2 PASSWORD 'foo';
 ERROR:  password encryption failed: unsupported
 -- already encrypted, use as they are
 ALTER ROLE regress_passwd1 PASSWORD 'md5cd3578025fe2c3d7ed1b9a9b26238b70';
+WARNING:  setting an MD5-encrypted password
+DETAIL:  MD5 password support is deprecated and will be removed in a future release of PostgreSQL.
+HINT:  Refer to the PostgreSQL documentation for details about migrating to another password type.
 ALTER ROLE regress_passwd3 PASSWORD 'SCRAM-SHA-256$4096:VLK4RMaQLCvNtQ==$6YtlR4t69SguDiwFvbVgVZtuz6gpJQQqUMZ7IQJK5yI=:ps75jrHeYU4lXCcXI4O8oIdJ3eO8o2jirjruw9phBTo=';
 SET password_encryption = 'scram-sha-256';
 -- create SCRAM secret
 ALTER ROLE  regress_passwd4 PASSWORD 'foo';
 -- already encrypted with MD5, use as it is
 CREATE ROLE regress_passwd5 PASSWORD 'md5e73a4b11df52a6068f8b39f90be36023';
+WARNING:  setting an MD5-encrypted password
+DETAIL:  MD5 password support is deprecated and will be removed in a future release of PostgreSQL.
+HINT:  Refer to the PostgreSQL documentation for details about migrating to another password type.
 -- This looks like a valid SCRAM-SHA-256 secret, but it is not
 -- so it should be hashed with SCRAM-SHA-256.
 CREATE ROLE regress_passwd6 PASSWORD 'SCRAM-SHA-256$1234';
@@ -100,6 +106,9 @@ SELECT rolname, regexp_replace(rolpassword, '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+
 CREATE ROLE regress_passwd_empty PASSWORD '';
 NOTICE:  empty string is not a valid password, clearing password
 ALTER ROLE regress_passwd_empty PASSWORD 'md585939a5ce845f1a1b620742e3c659e0a';
+WARNING:  setting an MD5-encrypted password
+DETAIL:  MD5 password support is deprecated and will be removed in a future release of PostgreSQL.
+HINT:  Refer to the PostgreSQL documentation for details about migrating to another password type.
 ALTER ROLE regress_passwd_empty PASSWORD 'SCRAM-SHA-256$4096:hpFyHTUsSWcR7O9P$LgZFIt6Oqdo27ZFKbZ2nV+vtnYM995pDh9ca6WSi120=:qVV5NeluNfUPkwm7Vqat25RjSPLkGeoZBQs6wVv+um4=';
 NOTICE:  empty string is not a valid password, clearing password
 SELECT rolpassword FROM pg_authid WHERE rolname='regress_passwd_empty';