一、重置密码
安装最新版 wordpress-5.4.2-zh_CN.zip
很长时间未维护,登录时候突然发现密码忘记了,记录下解决办法吧。
重置登录密码为:123456
UPDATE
wp_users SET user_pass = '$P$BiPHCyMrQlCHFzG/1ftoDdulGpfsoP0' WHERE ID =1
使用重置的登录后台设置安全密码
进入登录 后台 >> 用户 >> 所有用户 选项卡 ;点击 编辑 按钮,找到 新密码 >> 生成密码 按钮,输入想设置的密码,最后 更新个人资料
二、登录源码解读
1. 登录控制器方法
在 wp-login.php 1174 行 — 查询数据库用户信息
// If the user wants SSL but the session is not SSL, force a secure cookie.
if ( ! empty( $_POST[‘log’] ) && ! force_ssl_admin() ) {
$user_name = sanitize_user( wp_unslash( $_POST[‘log’] ) );
$user = get_user_by( ‘login’, $user_name ); // 这里查询数据库用户信息
// …
}
// …
$user = wp_signon( array(), $secure_cookie ); // 这里校验密码
其中 get_user_by() 方法最终执行类似下面的 SQL:
$user = $wpdb->get_row(
$wpdb->prepare(
“SELECT * FROM $wpdb->users WHERE $db_field = %s LIMIT 1”,
$value
)
);
2. 接下来是校验密码的逻辑:
主要使用 wp_signon() 方法获取;代码在 wp-includes/user.php
文件中第 95 行
$user = wp_authenticate( $credentials['user_login'], $credentials['user_password'] );
方法最终会调用 wp-includes/pluggable.php
文件的
function wp_check_password( $password, $hash, $user_id = '' ) {} // 去检测密码。
function wp_signon( $credentials = array(), $secure_cookie = '' ) {
// ...
$user = wp_authenticate( $credentials['user_login'], $credentials['user_password'] );
if ( is_wp_error( $user ) ) {
return $user;
}
// ...
return $user;
}
wp-includes/pluggable.php
>> 2405 行
$check = $wp_hasher->CheckPassword( $password, $hash );
方法,调用的是 wp-includes/class-phpass.php
文件的 CheckPassword()
function wp_check_password( $password, $hash, $user_id = '' ) {
global $wp_hasher;
// ...
$check = $wp_hasher->CheckPassword( $password, $hash );
}
wp-includes/class-phpass.php 文件的 CheckPassword
CheckPassword() 方法又调用内部
$hash = $this->crypt_private($password, $stored_hash);
crypt_private 继续调用 $output .= t h i s − > e n c o d e 64 ( this->encode64( this−>encode64(input, 6); 内部方法,最终返回的 o u t p u t = ′ output = ' output=′P$BlQ4L10EWkfoyGXC0EtVK.KdwW9WxW.'; 类似的字符串。
最终比较 return $hash === $stored_hash; 这两个字符串是否全等。
class PasswordHash {
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;
}
function crypt_private($password, $setting)
{
$output = '*0';
if (substr($setting, 0, 2) == $output)
$output = '*1';
$id = substr($setting, 0, 3);
# We use "$P$", phpBB3 uses "$H$" for the same thing
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;
# We're kind of forced to use MD5 here since it's the only
# cryptographic primitive available in all versions of PHP
# currently in use. To implement our own low-level crypto
# in PHP would result in much worse performance and
# consequently in lower iteration counts and hashes that are
# quicker to crack (by non-PHP code).
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 crypt_private($password, $setting)
{
$output = '*0';
if (substr($setting, 0, 2) == $output)
$output = '*1';
$id = substr($setting, 0, 3);
# We use "$P$", phpBB3 uses "$H$" for the same thing
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;
# We're kind of forced to use MD5 here since it's the only
# cryptographic primitive available in all versions of PHP
# currently in use. To implement our own low-level crypto
# in PHP would result in much worse performance and
# consequently in lower iteration counts and hashes that are
# quicker to crack (by non-PHP code).
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 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;
}
}
三、总结:
最终加密的算法就是在 wp-includes/class-phpass.php
文件的 crypt_private 方法,其中 $count = 1 << $count_log2; 决定了 md5 的 hash 值,有空可以读读上面的逻辑。