mirror of
git://develop.git.wordpress.org/
synced 2025-03-19 19:39:51 +01:00
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. git-svn-id: https://develop.svn.wordpress.org/trunk@59893 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
bcaaa16a1f
commit
360732e132
@ -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;
|
||||
|
@ -318,10 +318,10 @@ class Tests_Auth extends WP_UnitTestCase {
|
||||
/**
|
||||
* @ticket 21022
|
||||
*/
|
||||
public function test_wp_check_password_does_not_support_md5_hashes() {
|
||||
public function test_wp_check_password_supports_md5_hash() {
|
||||
$password = 'password';
|
||||
$hash = md5( $password );
|
||||
$this->assertFalse( wp_check_password( $password, $hash ) );
|
||||
$this->assertTrue( wp_check_password( $password, $hash ) );
|
||||
$this->assertSame( 1, did_filter( 'check_password' ) );
|
||||
}
|
||||
|
||||
@ -363,8 +363,6 @@ class Tests_Auth extends WP_UnitTestCase {
|
||||
|
||||
public function data_empty_values() {
|
||||
return array(
|
||||
// Integer zero:
|
||||
array( 0 ),
|
||||
// String zero:
|
||||
array( '0' ),
|
||||
// Zero-length string:
|
||||
@ -1079,6 +1077,42 @@ class Tests_Auth extends WP_UnitTestCase {
|
||||
$this->assertSame( self::$user_id, $user->ID );
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data_usernames
|
||||
*
|
||||
* @ticket 21022
|
||||
*/
|
||||
public function test_md5_password_is_rehashed_after_successful_user_password_authentication( $username_or_email ) {
|
||||
$password = 'password';
|
||||
|
||||
// Set the user password with the old md5 algorithm.
|
||||
self::set_user_password_with_md5( $password, self::$user_id );
|
||||
|
||||
// Verify that the password needs rehashing.
|
||||
$hash = get_userdata( self::$user_id )->user_pass;
|
||||
$this->assertTrue( wp_password_needs_rehash( $hash, self::$user_id ) );
|
||||
|
||||
// Authenticate.
|
||||
$user = wp_authenticate( $username_or_email, $password );
|
||||
|
||||
// Verify that the md5 password hash was valid.
|
||||
$this->assertNotWPError( $user );
|
||||
$this->assertInstanceOf( 'WP_User', $user );
|
||||
$this->assertSame( self::$user_id, $user->ID );
|
||||
|
||||
// Verify that the password no longer needs rehashing.
|
||||
$hash = get_userdata( self::$user_id )->user_pass;
|
||||
$this->assertFalse( wp_password_needs_rehash( $hash, self::$user_id ) );
|
||||
|
||||
// Authenticate a second time to ensure the new hash is valid.
|
||||
$user = wp_authenticate( $username_or_email, $password );
|
||||
|
||||
// Verify that the bcrypt password hash is valid.
|
||||
$this->assertNotWPError( $user );
|
||||
$this->assertInstanceOf( 'WP_User', $user );
|
||||
$this->assertSame( self::$user_id, $user->ID );
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data_usernames
|
||||
*
|
||||
@ -1772,6 +1806,38 @@ class Tests_Auth extends WP_UnitTestCase {
|
||||
clean_user_cache( $user_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the tests
|
||||
*
|
||||
* @covers Tests_Auth::set_user_password_with_md5
|
||||
*
|
||||
* @ticket 21022
|
||||
*/
|
||||
public function test_set_user_password_with_md5() {
|
||||
$password = 'password';
|
||||
|
||||
// Set the user password with the old md5 algorithm.
|
||||
self::set_user_password_with_md5( $password, self::$user_id );
|
||||
|
||||
// Ensure the password is hashed with md5.
|
||||
$hash = get_userdata( self::$user_id )->user_pass;
|
||||
$this->assertSame( md5( $password ), $hash );
|
||||
}
|
||||
|
||||
private static function set_user_password_with_md5( string $password, int $user_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$wpdb->update(
|
||||
$wpdb->users,
|
||||
array(
|
||||
'user_pass' => md5( $password ),
|
||||
),
|
||||
array(
|
||||
'ID' => $user_id,
|
||||
)
|
||||
);
|
||||
clean_user_cache( $user_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the tests
|
||||
|
Loading…
x
Reference in New Issue
Block a user