Hace algún tiempo te enseñé como autenticar un usuario existente de WordPress sin usar Wordpress, solo PHP, beneficiándote del ecosistema WP para cargar y autentificar a tus usuarios en tu propia app.

Recientemente salió la versión 6.8 de WordPress y con ello ha cambiado la función de Hashing, así que toca actualizar.

El aviso está en: https://make.wordpress.org/core/2025/02/17/wordpress-6-8-will-use-bcrypt-for-password-hashing/

Comprobar contraseña de WordPress

Lo que te voy a mostrar no usa plugins y se ejecuta fuera de WP. Es una manera sucia (pero no insegura) de comprobar las contraseñas.

Previamente teníamos este código que usaba PasswordHash.php:

<?php
function autenticarUsuario($username, $password)
{
    # Obtener usuario. Si no existe, regresamos false inmediatamente
    $usuario = obtenerUsuarioDeWordPress($username);
    if (!$usuario) return false;
    # Incluimos PasswordHash pues vamos a realizar algunas comprobaciones
    include_once "PasswordHash.php";
    # Esta es la contraseña almacenada en la base de datos:
    $storedHash = $usuario->user_pass;
    # Crear instancia de PasswordHash
    $passwordHash = new PasswordHash(8, false);
    $metaValue = unserialize($usuario->meta_value);
    # Nota: en mi caso solo permito usuarios administradores y colaboradores; ignoro a los demás.
    # Si tú quieres permitirlos, modifica el código
    if (!isset($metaValue["administrator"]) && !isset($metaValue["contributor"])) {
        return false;
    }
    if ((isset($metaValue["administrator"]) && !$metaValue["administrator"]) && (isset($metaValue["contributor"]) && !$metaValue["contributor"])) {
        return false;
    }
    # Ahora sí comprobamos la contraseña plana ($password) con la hasheada almacenada ($storedHash)
    if ($passwordHash->CheckPassword($password, $storedHash)) {
        # Si llegamos aquí, el usuario y contraseña son correctos
        # Lo único que hacemos es poner el rol del mismo
        if ((isset($metaValue["administrator"])) && $metaValue["administrator"]) {
            $usuario->role = "administrator";
        } else if (isset($metaValue["contributor"]) && $metaValue["contributor"]) {
            $usuario->role = "contributor";
        }
        # Y regresamos el usuario
        return $usuario;
    } else {
        # Caso contrario (la contraseña no coincide) regresamos igualmente false
        return false;
    }
}

Esto era porque las contraseñas tenían el formato de $P$B8La1sd3sa12634as5d1sa pero con esta actualización tienen un formato como $wp$2y$10$uhy32178321321b21j321 que es bcrypt con modificaciones extra.

Leyendo el comunicado de actualización me di cuenta que $wp es solo un prefijo para que el propio WordPress pueda identificar sus hashes, pero si lo removemos tenemos un hash totalmente válido para bcrypt.

Eso sí: antes de comprobar la contraseña plana hay que calcular su SHA384, remover el $wp y ahora sí enviarla a bcrypt.

Me guié de los siguientes enlaces:

Para terminar con la siguiente función:

function loginUser($username, $password)
{
    $user = getUserFromWordPressDatabase($username);

    if (!$user) return false;
    include_once "PasswordHash.php";
    $storedHash = $user->user_pass;
    $passwordHash = new PasswordHash(8, false);
    $metaValue = unserialize($user->meta_value);
    if (!isset($metaValue["administrator"]) && !isset($metaValue["contributor"]) && !isset($metaValue["subscriber"])) {
        return false;
    }
    if ((isset($metaValue["administrator"]) && !$metaValue["administrator"]) && (isset($metaValue["contributor"]) && !$metaValue["contributor"]) && (isset($metaValue["subscriber"]) && !$metaValue["subscriber"])) {
        return false;
    }
    $passwordCorrecta = false;
    /**
     * Tenemos que comprobar si el hash es nuevo porque a WP se le ocurrió actualizar su hash unos 20 años después
     * https://make.wordpress.org/core/2025/02/17/wordpress-6-8-will-use-bcrypt-for-password-hashing/
     */
    # Entonces es nueva 6.8
    if (str_starts_with($storedHash, '$wp$2y')) {
        $password_to_hash = base64_encode(hash_hmac('sha384', trim($password), 'wp-sha384', true));
        $passwordCorrecta = password_verify($password_to_hash, substr($storedHash, 3));
    } else {
        $passwordCorrecta = $passwordHash->CheckPassword($password, $storedHash);
    }
    if ($passwordCorrecta) {
        if ((isset($metaValue["administrator"])) && $metaValue["administrator"]) {
            $user->role = "administrator";
        } else if (isset($metaValue["contributor"]) && $metaValue["contributor"]) {
            $user->role = "contributor";
        } else if (isset($metaValue["subscriber"]) && $metaValue["subscriber"]) {
            $user->role = "subscriber";
        }
        return $user;
    } else {
        return false;
    }
}
Si el post ha sido de tu agrado te invito a que me sigas para saber cuando haya escrito un nuevo post, haya actualizado algún sistema o publicado un nuevo software. Facebook | X | Instagram | Telegram | También estoy a tus órdenes para cualquier contratación en mi página de contacto