Cum să validezi parola generată de WordPress în baza de date folosind PHP?
Lucrez la un site construit cu WordPress și trebuie să adaug unele părți în afara WP, inclusiv verificarea autentificării utilizatorilor în afara platformei WordPress.
Am încercat cu md5 al parolei dar nu funcționează...
Am testat acest cod:
require_once( 'wp-includes/class-phpass.php' );
$wp_hasher = new PasswordHash( 8, TRUE );
$password = "parolaAici";
$hashed_password = $wp_hasher->HashPassword( $password );
$encryptedpass = md5($hashed_password);
Dar acest cod funcționează doar pentru crearea inițială a parolei, iar rezultatul este mereu diferit.
Am nevoie de un cod care poate fi folosit astfel:
SELECT * FROM wp_customers WHERE email = "ccc@aaa.com" AND password = "<ce pun aici?>"
Este posibil acest lucru cumva?
Mulțumesc.
Pe baza celeilalte întrebări... se pare că încerci să validezi o parolă în clar față de cea stocată în baza de date. Iată funcția pe care WordPress o folosește pentru asta:
function wp_check_password($password, $hash, $user_id = '') {
global $wp_hasher;
// Dacă hash-ul este încă md5...
if ( strlen($hash) <= 32 ) {
$check = ( $hash == md5($password) );
if ( $check && $user_id ) {
// Regenerează hash-ul folosind noua metodă.
wp_set_password($password, $user_id);
$hash = wp_hash_password($password);
}
return apply_filters('check_password', $check, $password, $hash, $user_id);
}
// Dacă hash-ul stocat este mai lung decât un MD5, presupunem
// că este un hash portabil phpass de tip nou.
if ( empty($wp_hasher) ) {
require_once ( ABSPATH . 'wp-includes/class-phpass.php');
// Implicit, folosește hash-ul portabil din phpass
$wp_hasher = new PasswordHash(8, TRUE);
}
$check = $wp_hasher->CheckPassword($password, $hash);
return apply_filters('check_password', $check, $password, $hash, $user_id);
}
Mai întâi, acest plugin verifică dacă hash-ul MD5 al parolei date este același cu parola stocată (hashed) pentru un utilizator. De asemenea, verifică dacă hash-ul PHPass al parolei date este același cu parola stocată pentru un utilizator.
Poți urma un model similar.
Să presupunem că ai primit un nume de utilizator și o parolă de la utilizator și vrei să le validezi (my_password_validation( $username, $password )
). Vei folosi numele de utilizator pentru a extrage parola hashed din baza de date. Apoi vei compara hash-ul parolei date cu valoarea stocată pentru a vedea dacă este validă.
Iată niște pseudocod netestat:
function my_password_validation( $username, $password ) {
// Selectează hash-ul parolei utilizatorului din baza de date
$stored = query( 'SELECT * FROM wp_customers WHERE email = ' . $username );
require_one( 'class-phpass.php' );
$hasher = new PasswordHash(8, TRUE);
return $hasher->CheckPassword( $password, $stored );
}
Dacă parola pe care o transmiți funcției are același hash ca valoarea stocată, funcția va returna true. Altfel, va returna false.
Analizând comentariile lăsate la cealaltă întrebare, se pare că ai alte probleme, totuși. Ca să citez:
Deci obțin:
$P$BqVYujC/jqNY4aylZpHi475jwcaSUs1
Dar cum pot să compar asta cu cea din DB?Cea din DB este:
fa063a4ed35e092a2d4e15c1b6a61871
Cum să compar aceste două cu MySQL?
Îți pot spune imediat că parola pe care o obții din baza de date nu a fost hashed folosind utilitarul PHPass. Acele hash-uri vor începe întotdeauna cu $P$B
pentru că asta indică sistemului cum a fost generat hash-ul. PHPass se bazează pe Blowfish care folosește acest tip de prefix pentru șirurile criptate.
Hash-ul tău fa063...
arată mai degrabă ca un hash MD5 standard... deci dacă hash-ul MD5 al parolei în clar nu se potrivește, atunci cred că ai parola greșită.
Ca să răspund la întrebarea ta "cum compar aceste două cu MySQL"... nu o faci. MySQL este depozitul de date... nu implementa logica de afaceri sau comparații în depozitul de date. Citește datele și folosește un script PHP pentru a face comparația.

Aceste afirmații "MySQL este doar un depozit de date... nu faceți nicio logică de afaceri sau comparații în depozitul de date" sunt puțin exagerate, sincer să fiu. Serverele de baze de date sunt instrumente puternice. Cu siguranță nu sunt "doar" depozite de date și în ultimii ani au fost subestimate, în detrimentul tuturor, după părerea mea.

Este foarte ușor..
<?php
include_once($_SERVER['DOCUMENT_ROOT'].'/wp-includes/class-phpass.php' );
// pregătește conexiunea la baza de date
$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 "Nu s-a putut conecta: " . mysql_error();
exit();
}
// numele de utilizator WordPress a cărui parolă va fi comparată
$user = 'test';
$user_name = htmlspecialchars($user,ENT_QUOTES);
// parola în clar pentru comparare
$password = 'tespass';
$hasher = new PasswordHash(8, TRUE);
// obține parola hashuită a utilizatorului din baza de date 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];
}
// compară parola în clar cu cea hashuită
if ($hasher->CheckPassword( $password, $passnya )){
echo "POTRIVITĂ";
} else {
echo "NU SE POTRIVEȘTE";
}
?>

PasswordHash
nu este o clasă PHP de bază, așa că dacă nu o includeți, veți primi o eroare. Amintiți-vă că utilizatorul a cerut să valideze parola în afara WordPress, deci clasele și funcțiile WP nu sunt disponibile.

Am avut această problemă și am descoperit soluția chiar pe wp_hash_password()
Compară o parolă deja hash-uită cu șirul ei în clar
<?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 "DA, Se potrivește";
} else {
echo "Nu, Parolă greșită";
}
?>

În sfârșit, după aproape 10 ani. Am găsit răspunsul exact la întrebarea căutată.
Vrei să faci asta folosind PHP Core, nu-i așa?
Iată codul pentru tine!
Mai întâi trebuie să adaugi o clasă:
-> copiaz-o pur și simplu din wp-includes/class-phpass.php
-> nu-ți face griji. e scrisă în PHP core.
class PasswordHash {
var $itoa64;
var $iteration_count_log2;
var $portable_hashes;
var $random_state;
/**
* Constructor 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); // eliminat getmypid() din motive de compatibilitate
}
/**
* Constructor 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);
# Folosim "$P$", phpBB3 folosește "$H$" pentru același lucru
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;
# Suntem cam obligați să folosim MD5 aici, deoarece este singura
# primitivă criptografică disponibilă în toate versiunile PHP
# utilizate în prezent. Implementarea propriei criptări low-level
# în PHP ar duce la performanțe mult mai slabe și, în consecință,
# la număr mai mic de iterații și hash-uri mai ușor de spart (de cod non-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);
# Acesta ar trebui să fie impar pentru a nu expune chei slabe DES, iar
# valoarea maximă validă este (2**24 - 1) care este oricum impară.
$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)
{
# Acesta trebuie să folosească o ordine diferită de caractere și o
# schemă de codare diferită de cea din encode64() de mai sus.
# Ne pasă deoarece ultimul caracter din șirul codat va
# reprezenta doar 2 biți. Deși două implementări cunoscute ale
# bcrypt vor accepta și corecta un șir salt care
# are cei 4 biți neutilizați setați pe non-zero, nu vrem să ne
# asumăm riscuri și nu vrem să irosim un octet suplimentar
# de entropie.
$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;
# Returnarea '*' în caz de eroare este sigură aici, dar _nu_ ar fi sigură
# într-o funcție crypt(3)-like folosită _atât_ pentru generarea de
# hash-uri noi, cât și pentru validarea parolelor împotriva hash-urilor existente.
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;
}
}
Ești aproape gata.
$password = 'binary1001';//parola pe care vrei să o verifici
$hasher = new PasswordHash(8, TRUE);
$passnya = '$P$BFG8I1k171qgRKqZvj0K3tn3bBSrsW/';//hash-ul acelei parole din baza de date wp
// compară parola simplă cu parola hash-uită
if ($hasher->CheckPassword( $password, $passnya )){
echo "POTRIVIRE";
} else {
echo "NICI O POTRIVIRE";
}
Am ajuns aici prin încercări și erori. Acum e timpul să ajungi la subiect. Codare fericită!!!

Dar acesta este doar răspunsul lui BagusS cu accesul la baza de date eliminat, nu-i așa? Și chiar și acesta este în esență partea din răspunsul lui EAMann care este marcată ca 'pseudocod netestat', care a fost postată acum zece ani.
