WordPress.org

Make WordPress Core

Ticket #21022: 21022.4.diff

File 21022.4.diff, 14.0 KB (added by bgermann, 2 years ago)

Use password_hash instead of phpass

  • src/wp-includes/class-wp-recovery-mode-key-service.php

     
    3737         *
    3838         * @since 5.2.0
    3939         *
    40          * @global PasswordHash $wp_hasher
    41          *
    4240         * @param string $token A token generated by {@see generate_recovery_mode_token()}.
    4341         * @return string $key Recovery mode key.
    4442         */
    4543        public function generate_and_store_recovery_mode_key( $token ) {
    4644
    47                 global $wp_hasher;
    48 
    4945                $key = wp_generate_password( 22, false );
    5046
    51                 if ( empty( $wp_hasher ) ) {
    52                         require_once ABSPATH . WPINC . '/class-phpass.php';
    53                         $wp_hasher = new PasswordHash( 8, true );
    54                 }
     47                $hashed = password_hash( $key, PASSWORD_BCRYPT );
    5548
    56                 $hashed = $wp_hasher->HashPassword( $key );
    57 
    5849                $records = $this->get_keys();
    5950
    6051                $records[ $token ] = array(
  • src/wp-includes/pluggable.php

     
    18821882         * @since 4.6.0 The `$notify` parameter accepts 'user' for sending notification only to the user created.
    18831883         *
    18841884         * @global wpdb         $wpdb      WordPress database object for queries.
    1885          * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
    18861885         *
    18871886         * @param int    $user_id    User ID.
    18881887         * @param null   $deprecated Not used (argument deprecated).
     
    18991898                        return;
    19001899                }
    19011900
    1902                 global $wpdb, $wp_hasher;
     1901                global $wpdb;
    19031902                $user = get_userdata( $user_id );
    19041903
    19051904                // The blogname option is escaped with esc_html on the way into the database in sanitize_option
     
    19661965                do_action( 'retrieve_password_key', $user->user_login, $key );
    19671966
    19681967                // Now insert the key, hashed, into the DB.
    1969                 if ( empty( $wp_hasher ) ) {
    1970                         require_once ABSPATH . WPINC . '/class-phpass.php';
    1971                         $wp_hasher = new PasswordHash( 8, true );
    1972                 }
    1973                 $hashed = time() . ':' . $wp_hasher->HashPassword( $key );
     1968                $hashed = time() . ':' . password_hash( $key, PASSWORD_BCRYPT );
    19741969                $wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user->user_login ) );
    19751970
    19761971                $switched_locale = switch_to_locale( get_user_locale( $user ) );
     
    22712266         *
    22722267         * @since 2.5.0
    22732268         *
    2274          * @global PasswordHash $wp_hasher PHPass object
    2275          *
    22762269         * @param string $password Plain text user password to hash
    22772270         * @return string The hash string of the password
    22782271         */
    22792272        function wp_hash_password( $password ) {
    2280                 global $wp_hasher;
    2281 
    2282                 if ( empty( $wp_hasher ) ) {
    2283                         require_once( ABSPATH . WPINC . '/class-phpass.php' );
    2284                         // By default, use the portable hash from phpass
    2285                         $wp_hasher = new PasswordHash( 8, true );
    2286                 }
    2287 
    2288                 return $wp_hasher->HashPassword( trim( $password ) );
     2273                return password_hash( trim( $password ), PASSWORD_BCRYPT );
    22892274        }
    22902275endif;
    22912276
     
    22942279         * Checks the plaintext password against the encrypted Password.
    22952280         *
    22962281         * Maintains compatibility between old version and the new cookie authentication
    2297          * protocol using PHPass library. The $hash parameter is the encrypted password
     2282         * protocol using password_hash. The $hash parameter is the encrypted password
    22982283         * and the function compares the plain text password when encrypted similarly
    22992284         * against the already encrypted password to see if they match.
    23002285         *
     
    23032288         *
    23042289         * @since 2.5.0
    23052290         *
    2306          * @global PasswordHash $wp_hasher PHPass object used for checking the password
    2307          *  against the $hash + $password
    23082291         * @uses PasswordHash::CheckPassword
    23092292         *
    23102293         * @param string     $password Plaintext user's password
     
    23132296         * @return bool False, if the $password does not match the hashed password
    23142297         */
    23152298        function wp_check_password( $password, $hash, $user_id = '' ) {
    2316                 global $wp_hasher;
    23172299
    2318                 // If the hash is still md5...
    2319                 if ( strlen( $hash ) <= 32 ) {
    2320                         $check = hash_equals( $hash, md5( $password ) );
     2300                if ( password_needs_rehash( $hash, PASSWORD_BCRYPT ) ) {
     2301                        if ( strlen( $hash ) <= 32 ) {
     2302                                $check = hash_equals( $hash, md5( $password ) );
     2303                        } else {
     2304                                require_once( ABSPATH . WPINC . '/class-phpass.php' );
     2305                                $wp_hasher = new PasswordHash( 8, true );
     2306                                $check = $wp_hasher->CheckPassword( $password, $hash );
     2307                        }
     2308
    23212309                        if ( $check && $user_id ) {
    23222310                                // Rehash using new hash.
    23232311                                wp_set_password( $password, $user_id );
    23242312                                $hash = wp_hash_password( $password );
    23252313                        }
    2326 
    2327                         /**
    2328                          * Filters whether the plaintext password matches the encrypted password.
    2329                          *
    2330                          * @since 2.5.0
    2331                          *
    2332                          * @param bool       $check    Whether the passwords match.
    2333                          * @param string     $password The plaintext password.
    2334                          * @param string     $hash     The hashed password.
    2335                          * @param string|int $user_id  User ID. Can be empty.
    2336                          */
    2337                         return apply_filters( 'check_password', $check, $password, $hash, $user_id );
     2314                } else {
     2315                        $check = password_verify( $password, $hash );
    23382316                }
    23392317
    2340                 // If the stored hash is longer than an MD5, presume the
    2341                 // new style phpass portable hash.
    2342                 if ( empty( $wp_hasher ) ) {
    2343                         require_once( ABSPATH . WPINC . '/class-phpass.php' );
    2344                         // By default, use the portable hash from phpass
    2345                         $wp_hasher = new PasswordHash( 8, true );
    2346                 }
    2347 
    2348                 $check = $wp_hasher->CheckPassword( $password, $hash );
    2349 
    2350                 /** This filter is documented in wp-includes/pluggable.php */
     2318                /**
     2319                 * Filters whether the plaintext password matches the encrypted password.
     2320                 *
     2321                 * @since 2.5.0
     2322                 *
     2323                 * @param bool       $check    Whether the passwords match.
     2324                 * @param string     $password The plaintext password.
     2325                 * @param string     $hash     The hashed password.
     2326                 * @param string|int $user_id  User ID. Can be empty.
     2327                 */
    23512328                return apply_filters( 'check_password', $check, $password, $hash, $user_id );
    23522329        }
    23532330endif;
  • src/wp-includes/post-template.php

     
    866866                return apply_filters( 'post_password_required', true, $post );
    867867        }
    868868
    869         require_once ABSPATH . WPINC . '/class-phpass.php';
    870         $hasher = new PasswordHash( 8, true );
    871 
    872869        $hash = wp_unslash( $_COOKIE[ 'wp-postpass_' . COOKIEHASH ] );
    873         if ( 0 !== strpos( $hash, '$P$B' ) ) {
     870        if ( 0 !== strpos( $hash, '$2y$' ) ) {
    874871                $required = true;
    875872        } else {
    876                 $required = ! $hasher->CheckPassword( $post->post_password, $hash );
     873                $required = ! $password_verify( $post->post_password, $hash );
    877874        }
    878875
    879876        /**
  • src/wp-includes/user.php

     
    22052205 * @since 4.4.0
    22062206 *
    22072207 * @global wpdb         $wpdb      WordPress database abstraction object.
    2208  * @global PasswordHash $wp_hasher Portable PHP password hashing framework.
    22092208 *
    22102209 * @param WP_User $user User to retrieve password reset key for.
    22112210 *
     
    22122211 * @return string|WP_Error Password reset key on success. WP_Error on error.
    22132212 */
    22142213function get_password_reset_key( $user ) {
    2215         global $wpdb, $wp_hasher;
     2214        global $wpdb;
    22162215
    22172216        if ( ! ( $user instanceof WP_User ) ) {
    22182217                return new WP_Error( 'invalidcombo', __( '<strong>ERROR</strong>: There is no account with that username or email address.' ) );
     
    22742273        do_action( 'retrieve_password_key', $user->user_login, $key );
    22752274
    22762275        // Now insert the key, hashed, into the DB.
    2277         if ( empty( $wp_hasher ) ) {
    2278                 require_once ABSPATH . WPINC . '/class-phpass.php';
    2279                 $wp_hasher = new PasswordHash( 8, true );
    2280         }
    2281         $hashed    = time() . ':' . $wp_hasher->HashPassword( $key );
     2276        $hashed    = time() . ':' . password_hash( $key, PASSWORD_BCRYPT );
    22822277        $key_saved = $wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user->user_login ) );
    22832278        if ( false === $key_saved ) {
    22842279                return new WP_Error( 'no_password_key_update', __( 'Could not save password reset key to database.' ) );
     
    22982293 * @since 3.1.0
    22992294 *
    23002295 * @global wpdb         $wpdb      WordPress database object for queries.
    2301  * @global PasswordHash $wp_hasher Portable PHP password hashing framework instance.
    23022296 *
    23032297 * @param string $key       Hash to validate sending user's password.
    23042298 * @param string $login     The user login.
     
    23052299 * @return WP_User|WP_Error WP_User object on success, WP_Error object for invalid or expired keys.
    23062300 */
    23072301function check_password_reset_key( $key, $login ) {
    2308         global $wpdb, $wp_hasher;
     2302        global $wpdb;
    23092303
    23102304        $key = preg_replace( '/[^a-z0-9]/i', '', $key );
    23112305
     
    23222316                return new WP_Error( 'invalid_key', __( 'Invalid key.' ) );
    23232317        }
    23242318
    2325         if ( empty( $wp_hasher ) ) {
    2326                 require_once ABSPATH . WPINC . '/class-phpass.php';
    2327                 $wp_hasher = new PasswordHash( 8, true );
    2328         }
    2329 
    23302319        /**
    23312320         * Filters the expiration time of password reset keys.
    23322321         *
     
    23482337                return new WP_Error( 'invalid_key', __( 'Invalid key.' ) );
    23492338        }
    23502339
    2351         $hash_is_correct = $wp_hasher->CheckPassword( $key, $pass_key );
     2340        $hash_is_correct = password_verify( $key, $pass_key );
    23522341
    23532342        if ( $hash_is_correct && $expiration_time && time() < $expiration_time ) {
    23542343                return get_userdata( $row->ID );
     
    35423531 * @return string Confirmation key.
    35433532 */
    35443533function wp_generate_user_request_key( $request_id ) {
    3545         global $wp_hasher;
    35463534
    35473535        // Generate something random for a confirmation key.
    35483536        $key = wp_generate_password( 20, false );
    35493537
    35503538        // Return the key, hashed.
    3551         if ( empty( $wp_hasher ) ) {
    3552                 require_once ABSPATH . WPINC . '/class-phpass.php';
    3553                 $wp_hasher = new PasswordHash( 8, true );
    3554         }
    3555 
    35563539        wp_update_post(
    35573540                array(
    35583541                        'ID'            => $request_id,
    35593542                        'post_status'   => 'request-pending',
    3560                         'post_password' => $wp_hasher->HashPassword( $key ),
     3543                        'post_password' => password_hash( $key, PASSWORD_BCRYPT ),
    35613544                )
    35623545        );
    35633546
     
    35743557 * @return bool|WP_Error WP_Error on failure, true on success.
    35753558 */
    35763559function wp_validate_user_request_key( $request_id, $key ) {
    3577         global $wp_hasher;
    35783560
    35793561        $request_id = absint( $request_id );
    35803562        $request    = wp_get_user_request_data( $request_id );
     
    35913573                return new WP_Error( 'missing_key', __( 'Missing confirm key.' ) );
    35923574        }
    35933575
    3594         if ( empty( $wp_hasher ) ) {
    3595                 require_once ABSPATH . WPINC . '/class-phpass.php';
    3596                 $wp_hasher = new PasswordHash( 8, true );
    3597         }
    3598 
    35993576        $key_request_time = $request->modified_timestamp;
    36003577        $saved_key        = $request->confirm_key;
    36013578
     
    36173594        $expiration_duration = (int) apply_filters( 'user_request_key_expiration', DAY_IN_SECONDS );
    36183595        $expiration_time     = $key_request_time + $expiration_duration;
    36193596
    3620         if ( ! $wp_hasher->CheckPassword( $key, $saved_key ) ) {
     3597        if ( ! password_verify( $key, $saved_key ) ) {
    36213598                return new WP_Error( 'invalid_key', __( 'Invalid key.' ) );
    36223599        }
    36233600
  • src/wp-login.php

     
    508508                        exit();
    509509                }
    510510
    511                 require_once ABSPATH . WPINC . '/class-phpass.php';
    512                 $hasher = new PasswordHash( 8, true );
    513 
    514511                /**
    515512                 * Filters the life span of the post password cookie.
    516513                 *
     
    528525                } else {
    529526                        $secure = false;
    530527                }
    531                 setcookie( 'wp-postpass_' . COOKIEHASH, $hasher->HashPassword( wp_unslash( $_POST['post_password'] ) ), $expire, COOKIEPATH, COOKIE_DOMAIN, $secure );
     528                setcookie( 'wp-postpass_' . COOKIEHASH, password_hash( wp_unslash( $_POST['post_password'] ), PASSWORD_BCRYPT ), $expire, COOKIEPATH, COOKIE_DOMAIN, $secure );
    532529
    533530                wp_safe_redirect( wp_get_referer() );
    534531                exit();
  • tests/phpunit/tests/auth.php

     
    88        protected $user;
    99        protected static $_user;
    1010        protected static $user_id;
    11         protected static $wp_hasher;
    1211
    1312        /**
    1413         * action hook
     
    2322                );
    2423
    2524                self::$user_id = self::$_user->ID;
    26 
    27                 require_once( ABSPATH . WPINC . '/class-phpass.php' );
    28                 self::$wp_hasher = new PasswordHash( 8, true );
    2925        }
    3026
    3127        function setUp() {
     
    184180
    185181                wp_set_password( $limit, self::$user_id );
    186182                // phpass hashed password
    187                 $this->assertStringStartsWith( '$P$', $this->user->data->user_pass );
     183                $this->assertStringStartsWith( '$2y$', $this->user->data->user_pass );
    188184
    189185                $user = wp_authenticate( $this->user->user_login, 'aaaaaaaa' );
    190186                // Wrong Password
     
    236232                $wpdb->update(
    237233                        $wpdb->users,
    238234                        array(
    239                                 'user_activation_key' => strtotime( '-1 hour' ) . ':' . self::$wp_hasher->HashPassword( $key ),
     235                                'user_activation_key' => strtotime( '-1 hour' ) . ':' . password_hash( $key, PASSWORD_BCRYPT ),
    240236                        ),
    241237                        array(
    242238                                'ID' => $this->user->ID,
     
    273269                $wpdb->update(
    274270                        $wpdb->users,
    275271                        array(
    276                                 'user_activation_key' => strtotime( '-48 hours' ) . ':' . self::$wp_hasher->HashPassword( $key ),
     272                                'user_activation_key' => strtotime( '-48 hours' ) . ':' . password_hash( $key, PASSWORD_BCRYPT ),
    277273                        ),
    278274                        array(
    279275                                'ID' => $this->user->ID,
     
    310306                $wpdb->update(
    311307                        $wpdb->users,
    312308                        array(
    313                                 'user_activation_key' => self::$wp_hasher->HashPassword( $key ),
     309                                'user_activation_key' => password_hash( $key, PASSWORD_BCRYPT ),
    314310                        ),
    315311                        array(
    316312                                'ID' => $this->user->ID,
  • tests/phpunit/tests/comment-submission.php

     
    175175        public function test_submitting_comment_to_password_protected_post_succeeds() {
    176176
    177177                $password = 'password';
    178                 $hasher   = new PasswordHash( 8, true );
    179178
    180                 $_COOKIE[ 'wp-postpass_' . COOKIEHASH ] = $hasher->HashPassword( $password );
     179                $_COOKIE[ 'wp-postpass_' . COOKIEHASH ] = password_hash( $password, PASSWORD_BCRYPT );
    181180
    182181                $post    = self::factory()->post->create_and_get(
    183182                        array(