From d75f025337fdc3b7dab5ba951152c4b7e66532cd Mon Sep 17 00:00:00 2001 From: John Blackbourn Date: Fri, 28 Feb 2025 18:53:23 +0000 Subject: [PATCH] Security: Reintroduce support for passwords hashed with MD5. This reinstates the ability for a user to log in to an account where the password is hashed using MD5. This means that the ability to reset a password directly in the database using an SQL query or a database administration tool will be retained without the need to implement or integrate with bcrypt or phpass. A password hashed with MD5 will get upgraded to bcrypt at the point where a user successfully logs in, just as is the case with a phpass hash. Props audrasjb, aaronjorbin, johnbillion, david-innes, benniledl. See #21022. Built from https://develop.svn.wordpress.org/trunk@59893 git-svn-id: http://core.svn.wordpress.org/trunk@59235 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/pluggable.php | 39 +++++++++++++++++---------------------- wp-includes/version.php | 2 +- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/wp-includes/pluggable.php b/wp-includes/pluggable.php index 3a6190beff..e7ce2edb41 100644 --- a/wp-includes/pluggable.php +++ b/wp-includes/pluggable.php @@ -2724,7 +2724,6 @@ if ( ! function_exists( 'wp_check_password' ) ) : * @since 2.5.0 * @since 6.8.0 Passwords in WordPress are now hashed with bcrypt by default. A * password that wasn't hashed with bcrypt will be checked with phpass. - * Passwords hashed with md5 are no longer supported. * * @global PasswordHash $wp_hasher phpass object. Used as a fallback for verifying * passwords that were hashed with phpass. @@ -2742,30 +2741,14 @@ if ( ! function_exists( 'wp_check_password' ) ) : ) { global $wp_hasher; - $check = false; - - // If the hash is still md5 or otherwise truncated then invalidate it. if ( strlen( $hash ) <= 32 ) { - /** - * Filters whether the plaintext password matches the hashed password. - * - * @since 2.5.0 - * @since 6.8.0 Passwords are now hashed with bcrypt by default. - * Old passwords may still be hashed with phpass. - * - * @param bool $check Whether the passwords match. - * @param string $password The plaintext password. - * @param string $hash The hashed password. - * @param string|int $user_id Optional ID of a user associated with the password. - * Can be empty. - */ - return apply_filters( 'check_password', $check, $password, $hash, $user_id ); - } - - if ( ! empty( $wp_hasher ) ) { + // Check the hash using md5 regardless of the current hashing mechanism. + $check = hash_equals( $hash, md5( $password ) ); + } elseif ( ! empty( $wp_hasher ) ) { // Check the password using the overridden hasher. $check = $wp_hasher->CheckPassword( $password, $hash ); } elseif ( strlen( $password ) > 4096 ) { + // Passwords longer than 4096 characters are not supported. $check = false; } elseif ( str_starts_with( $hash, '$wp' ) ) { // Check the password using the current prefixed hash. @@ -2780,7 +2763,19 @@ if ( ! function_exists( 'wp_check_password' ) ) : $check = password_verify( $password, $hash ); } - /** This filter is documented in wp-includes/pluggable.php */ + /** + * Filters whether the plaintext password matches the hashed password. + * + * @since 2.5.0 + * @since 6.8.0 Passwords are now hashed with bcrypt by default. + * Old passwords may still be hashed with phpass or md5. + * + * @param bool $check Whether the passwords match. + * @param string $password The plaintext password. + * @param string $hash The hashed password. + * @param string|int $user_id Optional ID of a user associated with the password. + * Can be empty. + */ return apply_filters( 'check_password', $check, $password, $hash, $user_id ); } endif; diff --git a/wp-includes/version.php b/wp-includes/version.php index 68b35ec79c..efdf0a000b 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.8-alpha-59892'; +$wp_version = '6.8-alpha-59893'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.