Как проверить пароль, сгенерированный WordPress в базе данных с помощью PHP?

25 окт. 2011 г., 01:27:04
Просмотры: 18.9K
Голосов: 5

Я работаю с сайтом, созданным на WordPress, и мне нужно добавить некоторые элементы вне WP, а также проверять вход пользователей вне WordPress.

Я пробовал использовать md5 пароля, но это не работает...

Я пробовал этот код:

require_once( 'wp-includes/class-phpass.php' );
$wp_hasher = new PasswordHash( 8, TRUE );
$password = "passwordhere";
$hashed_password = $wp_hasher->HashPassword( $password );
$encryptedpass = md5($hashed_password);

Но это работает только при первом создании пароля, и он всегда получается разным.

Мне нужен код, который можно использовать в таком запросе:

SELECT * FROM wp_customers WHERE email = "ccc@aaa.com" AND password = "<что здесь должно быть?>"

Возможно ли это как-то реализовать?

Спасибо.

0
Все ответы на вопрос 4
2

Судя по вашему другому вопросу... похоже, что вы пытаетесь проверить введённый пароль в открытом виде с тем, что хранится в базе данных. Вот функция, которую использует WordPress для этой цели:

function wp_check_password($password, $hash, $user_id = '') {
    global $wp_hasher;

    // Если хеш всё ещё в md5...
    if ( strlen($hash) <= 32 ) {
        $check = ( $hash == md5($password) );
        if ( $check && $user_id ) {
            // Перехешируем с использованием нового алгоритма.
            wp_set_password($password, $user_id);
            $hash = wp_hash_password($password);
        }

        return apply_filters('check_password', $check, $password, $hash, $user_id);
    }

    // Если сохранённый хеш длиннее MD5, предполагаем,
    // что это новый стиль phpass portable hash.
    if ( empty($wp_hasher) ) {
        require_once ( ABSPATH . 'wp-includes/class-phpass.php');
        // По умолчанию используем portable hash из phpass
        $wp_hasher = new PasswordHash(8, TRUE);
    }

    $check = $wp_hasher->CheckPassword($password, $hash);

    return apply_filters('check_password', $check, $password, $hash, $user_id);
}

Сначала этот плагин проверяет, совпадает ли MD5-хеш введённого пароля с сохранённым (захешированным) паролем пользователя. Также он проверяет, совпадает ли PHPass-хеш введённого пароля с сохранённым паролем пользователя.

Вы можете следовать аналогичной логике.

Допустим, у вас есть имя пользователя и пароль, которые нужно проверить (my_password_validation( $username, $password )). Вы используете имя пользователя для получения захешированного пароля из базы данных. Затем сравниваете хеш введённого пароля с сохранённым значением, чтобы проверить его валидность.

Вот непроверенный псевдокод:

function my_password_validation( $username, $password ) {
    // Выбираем хеш пароля пользователя из базы данных
    $stored = query( 'SELECT * FROM wp_customers WHERE email = ' . $username );

    require_one( 'class-phpass.php' );
    $hasher = new PasswordHash(8, TRUE);

    return $hasher->CheckPassword( $password, $stored );
}

Если пароль, переданный в функцию, после хеширования совпадает с сохранённым значением, функция вернёт true. В противном случае вернётся false.

Судя по комментариям к другому вопросу, у вас есть и другие проблемы. Цитирую:

Итак, я получаю:

$P$BqVYujC/jqNY4aylZpHi475jwcaSUs1 Но как сравнить его с тем, что в БД?

В БД хранится:

fa063a4ed35e092a2d4e15c1b6a61871 Как сравнить эти два значения в MySQL?

Могу сразу сказать, что пароль в базе данных не хешировался с помощью утилиты PHPass. Такие хеши всегда начинаются с $P$B, потому что это указывает системе, как они были захешированы. PHPass основан на Blowfish, который использует такой префикс для зашифрованных строк.

Ваш хеш fa063... больше похож на стандартный MD5-хеш... так что если MD5-хеш открытого текста не совпадает, возможно, у вас неверный пароль.

Отвечая на вопрос "как сравнить эти два значения в MySQL"... никак. MySQL — это хранилище данных, не выполняйте бизнес-логику или сравнения в хранилище. Читайте данные из БД, а затем используйте PHP-скрипт для сравнения.

25 окт. 2011 г. 06:08:41
Комментарии

Эти утверждения вроде "MySQL — это хранилище данных... не выполняйте бизнес-логику или сравнения в хранилище данных" немного преувеличены, если честно. Серверы баз данных — это мощные инструменты. Они определенно не являются "просто" хранилищами данных, и в последние годы их недооценивают, что, на мой взгляд, вредит всем.

Craig Tullis Craig Tullis
17 июн. 2015 г. 02:35:53

В базе данных WordPress есть таблица пользователей, и в этой таблице есть поле user_pass. Это тот "сохраненный" хэш, который вы передаете вторым параметром в функцию $hasher->CheckPassword()?

Millar248 Millar248
11 апр. 2021 г. 08:34:47
3

Это очень просто..

<?php
include_once($_SERVER['DOCUMENT_ROOT'].'/wp-includes/class-phpass.php' );

// подготовка подключения к базе данных
$ip_address="localhost";
$user_db="userdb";
$pass_db="passdb";

$conn= mysql_connect($ip_address,$user_db,$pass_db);
mysql_select_db("dbname",$conn);
if (!$conn){
            echo "Не удалось подключиться: " . mysql_error();
            exit();
}

// имя пользователя WordPress, пароль которого нужно сравнить
$user = 'test';
$user_name = htmlspecialchars($user,ENT_QUOTES);

// обычный пароль для сравнения
$password = 'tespass';

$hasher = new PasswordHash(8, TRUE);

// получаем хешированный пароль пользователя из базы данных WordPress
$queryx = "select * from wa1gty5f_users where user_login='$user_name'";
$Resultx = mysql_query($queryx,$conn);

while($row = mysql_fetch_array($Resultx)){
     $passnya = $row[user_pass];
}

// сравниваем обычный пароль с хешированным
if ($hasher->CheckPassword( $password, $passnya )){
    echo "СОВПАДАЕТ";
} else {
    echo "НЕ СОВПАДАЕТ";
}
?>
25 сент. 2013 г. 06:14:19
Комментарии

PasswordHash не является классом ядра PHP, поэтому если вы его не подключите, вы получите ошибку. Помните, что пользователь просил проверить пароль вне WordPress, поэтому классы и функции WP недоступны.

gmazzap gmazzap
25 сент. 2013 г. 07:56:26

@ialocin это класс ядра WordPress, а не ядра PHP.

gmazzap gmazzap
10 июл. 2015 г. 13:54:05

Моя ошибка! Надо было внимательнее прочитать.. @gmazzap

Nicolai Grossherr Nicolai Grossherr
10 июл. 2015 г. 13:56:19
0

У меня возникла эта проблема, и я нашел решение прямо в wp_hash_password()

Сравнение уже захэшированного пароля с его текстовой строкой

<?php

$wp_hasher = new PasswordHash(8, TRUE);

$password_hashed = '$P$B55D6LjfHDkINU5wF.v2BuuzO0/XPk/';
$plain_password = 'test';

if($wp_hasher->CheckPassword($plain_password, $password_hashed)) {
    echo "ДА, совпадает";
} else {
    echo "Нет, неверный пароль";
}

?>
17 июл. 2015 г. 03:32:19
2

Наконец, спустя почти 10 лет. Нашел точный ответ на вопрос, который искали.

Вы хотите сделать это с использованием чистого PHP, верно? Вот код для вас! Сначала вам нужно добавить класс: -> просто скопируйте его из wp-includes/class-phpass.php -> не волнуйтесь, он написан на чистом PHP.

class PasswordHash {
    var $itoa64;
    var $iteration_count_log2;
    var $portable_hashes;
    var $random_state;

    /**
     * Конструктор PHP5.
     */
    function __construct( $iteration_count_log2, $portable_hashes )
    {
        $this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

        if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
            $iteration_count_log2 = 8;
        $this->iteration_count_log2 = $iteration_count_log2;

        $this->portable_hashes = $portable_hashes;

        $this->random_state = microtime() . uniqid(rand(), TRUE); // удален getmypid() для совместимости
    }

    /**
     * Конструктор PHP4.
     */
    public function PasswordHash( $iteration_count_log2, $portable_hashes ) {
        self::__construct( $iteration_count_log2, $portable_hashes );
    }

    function get_random_bytes($count)
    {
        $output = '';
        if ( @is_readable('/dev/urandom') &&
            ($fh = @fopen('/dev/urandom', 'rb'))) {
            $output = fread($fh, $count);
            fclose($fh);
        }

        if (strlen($output) < $count) {
            $output = '';
            for ($i = 0; $i < $count; $i += 16) {
                $this->random_state =
                    md5(microtime() . $this->random_state);
                $output .=
                    pack('H*', md5($this->random_state));
            }
            $output = substr($output, 0, $count);
        }

        return $output;
    }

    function encode64($input, $count)
    {
        $output = '';
        $i = 0;
        do {
            $value = ord($input[$i++]);
            $output .= $this->itoa64[$value & 0x3f];
            if ($i < $count)
                $value |= ord($input[$i]) << 8;
            $output .= $this->itoa64[($value >> 6) & 0x3f];
            if ($i++ >= $count)
                break;
            if ($i < $count)
                $value |= ord($input[$i]) << 16;
            $output .= $this->itoa64[($value >> 12) & 0x3f];
            if ($i++ >= $count)
                break;
            $output .= $this->itoa64[($value >> 18) & 0x3f];
        } while ($i < $count);

        return $output;
    }

    function gensalt_private($input)
    {
        $output = '$P$';
        $output .= $this->itoa64[min($this->iteration_count_log2 +
            ((PHP_VERSION >= '5') ? 5 : 3), 30)];
        $output .= $this->encode64($input, 6);

        return $output;
    }

    function crypt_private($password, $setting)
    {
        $output = '*0';
        if (substr($setting, 0, 2) == $output)
            $output = '*1';

        $id = substr($setting, 0, 3);
        # Мы используем "$P$", phpBB3 использует "$H$" для того же самого
        if ($id != '$P$' && $id != '$H$')
            return $output;

        $count_log2 = strpos($this->itoa64, $setting[3]);
        if ($count_log2 < 7 || $count_log2 > 30)
            return $output;

        $count = 1 << $count_log2;

        $salt = substr($setting, 4, 8);
        if (strlen($salt) != 8)
            return $output;

        # Мы вынуждены использовать MD5 здесь, так как это единственная
        # криптографическая примитивная функция, доступная во всех версиях PHP
        # в настоящее время. Реализация собственной низкоуровневой криптографии
        # на PHP приведет к значительному снижению производительности и,
        # следовательно, к уменьшению количества итераций и хешей, которые
        # легче взломать (не-PHP кодом).
        if (PHP_VERSION >= '5') {
            $hash = md5($salt . $password, TRUE);
            do {
                $hash = md5($hash . $password, TRUE);
            } while (--$count);
        } else {
            $hash = pack('H*', md5($salt . $password));
            do {
                $hash = pack('H*', md5($hash . $password));
            } while (--$count);
        }

        $output = substr($setting, 0, 12);
        $output .= $this->encode64($hash, 16);

        return $output;
    }

    function gensalt_extended($input)
    {
        $count_log2 = min($this->iteration_count_log2 + 8, 24);
        # Это должно быть нечетным, чтобы не раскрывать слабые ключи DES, и
        # максимальное допустимое значение (2**24 - 1) в любом случае нечетное.
        $count = (1 << $count_log2) - 1;

        $output = '_';
        $output .= $this->itoa64[$count & 0x3f];
        $output .= $this->itoa64[($count >> 6) & 0x3f];
        $output .= $this->itoa64[($count >> 12) & 0x3f];
        $output .= $this->itoa64[($count >> 18) & 0x3f];

        $output .= $this->encode64($input, 3);

        return $output;
    }

    function gensalt_blowfish($input)
    {
        # Здесь нужно использовать другой порядок символов и другую
        # схему кодирования, чем в encode64() выше.
        # Это важно, потому что последний символ в закодированной строке будет
        # представлять только 2 бита. Хотя две известные реализации
        # bcrypt спокойно принимают и исправляют строку соли, в которой
        # 4 неиспользуемых бита установлены в ненулевое значение, мы не хотим
        # рисковать и также не хотим терять дополнительный байт энтропии.
        $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

        $output = '$2a$';
        $output .= chr(ord('0') + $this->iteration_count_log2 / 10);
        $output .= chr(ord('0') + $this->iteration_count_log2 % 10);
        $output .= '$';

        $i = 0;
        do {
            $c1 = ord($input[$i++]);
            $output .= $itoa64[$c1 >> 2];
            $c1 = ($c1 & 0x03) << 4;
            if ($i >= 16) {
                $output .= $itoa64[$c1];
                break;
            }

            $c2 = ord($input[$i++]);
            $c1 |= $c2 >> 4;
            $output .= $itoa64[$c1];
            $c1 = ($c2 & 0x0f) << 2;

            $c2 = ord($input[$i++]);
            $c1 |= $c2 >> 6;
            $output .= $itoa64[$c1];
            $output .= $itoa64[$c2 & 0x3f];
        } while (1);

        return $output;
    }

    function HashPassword($password)
    {
        if ( strlen( $password ) > 4096 ) {
            return '*';
        }

        $random = '';

        if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
            $random = $this->get_random_bytes(16);
            $hash =
                crypt($password, $this->gensalt_blowfish($random));
            if (strlen($hash) == 60)
                return $hash;
        }

        if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
            if (strlen($random) < 3)
                $random = $this->get_random_bytes(3);
            $hash =
                crypt($password, $this->gensalt_extended($random));
            if (strlen($hash) == 20)
                return $hash;
        }

        if (strlen($random) < 6)
            $random = $this->get_random_bytes(6);
        $hash =
            $this->crypt_private($password,
            $this->gensalt_private($random));
        if (strlen($hash) == 34)
            return $hash;

        # Возврат '*' при ошибке безопасен здесь, но не был бы безопасен
        # в функции, подобной crypt(3), используемой как для генерации новых
        # хешей, так и для проверки паролей против существующих хешей.
        return '*';
    }

    function CheckPassword($password, $stored_hash)
    {
        if ( strlen( $password ) > 4096 ) {
            return false;
        }

        $hash = $this->crypt_private($password, $stored_hash);
        if ($hash[0] == '*')
            $hash = crypt($password, $stored_hash);

        return $hash === $stored_hash;
    }
}

Вы почти закончили.

$password = 'binary1001';//пароль, который вы хотите проверить

$hasher = new PasswordHash(8, TRUE);
$passnya = '$P$BFG8I1k171qgRKqZvj0K3tn3bBSrsW/';//хеш этого пароля из базы данных WordPress


// сравнение обычного пароля с хешированным паролем
if ($hasher->CheckPassword( $password, $passnya )){
    echo "СОВПАДАЕТ";
} else {
    echo "НЕ СОВПАДАЕТ";
}

Я сделал это здесь методом проб и ошибок. Теперь ваша очередь разобраться. Удачного кодинга!!!

28 мар. 2021 г. 18:43:44
Комментарии

Но это же просто ответ BagusS с удалённым доступом к базе данных, не так ли? И даже это по сути просто часть ответа EAMann, помеченная как 'непроверенный псевдокод', который был опубликован десять лет назад.

Rup Rup
29 мар. 2021 г. 00:54:36

да! ты прав! я просто хотел показать, что это действительно работает и полный ответ в одном месте!

Md. Hasan Mahmud Md. Hasan Mahmud
30 мар. 2021 г. 05:29:24