Сценарий изменения пароля работает, но не записывает правильный пароль в базу данных

У меня есть этот скрипт для смены пароля:

<?php
/*
Page/Script Created by Shawn Holderfield
*/

//Establish output variable - For displaying Error Messages
$msg = "";

//Check to see if the form has been submitted
if (mysql_real_escape_string($_POST['submit'])):

//Establish Post form variables
$username = mysql_real_escape_string($_POST['username']);
$password = mysql_real_escape_string(md5($_POST['password']));
$npassword = mysql_real_escape_string(md5($_POST['npassword']));
$rpassword = mysql_real_escape_string(md5($_POST['rpassword']));

//Connect to the Database Server
mysql_connect("mysql..", "", "")or die(mysql_error());

// Connect to the database
mysql_select_db("") or die(mysql_error());

// Query the database - To find which user we're working with
$sql = "SELECT * FROM members WHERE username = '$username' ";
$query = mysql_query($sql);
$numrows = mysql_num_rows($query);
//Gather database information
while ($rows = mysql_fetch_array($query)):

$username == $rows['username'];
$password == $rows['password'];endwhile;

//Validate The Form
if (empty($username) || empty($password) || empty($npassword) || empty($rpassword)):

$msg = "All fields are required";

elseif ($numrows == 0):

$msg = "This username does not exist";

elseif ($password != $password):

$msg = "The CURRENT password you entered is incorrect.";

elseif ($npassword != $rpassword):

$msg = "Your new passwords do not match";

elseif ($npassword == $password):

$msg = "Your new password cannot match your old password";

else:

//$msg = "Your Password has been changed.";
mysql_query("UPDATE members SET password = '$npassword' WHERE username = '$username'");endif;
endif;

?>
<html>
<head>
<title>Change Password</title>
</head>
<body>
<form method="POST" action="">
<table border="0">
<tr>
<td align="right">Username: </td>
<td><input type="TEXT" name="username" value=""/></td>
</tr>
<tr>
<td align="right">Current Password: </td>
<td><input type="password" name="password" value=""/></td>
</tr>
<tr>
<td align="right">New Password: </td>
<td><input type="password" name="npassword" value=""/></td>
</tr>
<tr>
<td align="right">Repeat New Password: </td>
<td><input type="password" name="rpassword" value=""/></td>
</tr>
<tr><td>
<input type="submit" name="submit" value="Change Password"/>
</td>
</tr>
</table>
</form>
<br>
<?php echo $msg; ?>
</body>
</html>

Это на самом деле работает нормально, доступ к базе данных и перезаписать текущий пароль, но он не хеширует пароль, как при регистрации
Сценарий процесса регистрации:

<?php
include_once 'db_connect.php';
include_once 'psl-config.php';

$error_msg = "";

if (isset($_POST['username'], $_POST['email'], $_POST['p'])) {
// Sanitize and validate the data passed in
$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);
$email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL);
$email = filter_var($email, FILTER_VALIDATE_EMAIL);
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
// Not a valid email
$error_msg .= '<p class="error">The email address you entered is not valid</p>';
}

$password = filter_input(INPUT_POST, 'p', FILTER_SANITIZE_STRING);
if (strlen($password) != 128) {
// The hashed pwd should be 128 characters long.
// If it's not, something really odd has happened
$error_msg .= '<p class="error">Invalid password configuration.</p>';
}

// Username validity and password validity have been checked client side.
// This should should be adequate as nobody gains any advantage from
// breaking these rules.
//

$prep_stmt = "SELECT id FROM members WHERE email = ? LIMIT 1";
$stmt = $mysqli->prepare($prep_stmt);

// check existing email
if ($stmt) {
$stmt->bind_param('s', $email);
$stmt->execute();
$stmt->store_result();

if ($stmt->num_rows == 1) {
// A user with this email address already exists
$error_msg .= '<p class="error">A user with this email address already exists.</p>';
$stmt->close();
}
$stmt->close();
} else {
$error_msg .= '<p class="error">Database error Line 39</p>';
$stmt->close();
}

// check existing username
$prep_stmt = "SELECT id FROM members WHERE username = ? LIMIT 1";
$stmt = $mysqli->prepare($prep_stmt);

if ($stmt) {
$stmt->bind_param('s', $username);
$stmt->execute();
$stmt->store_result();

if ($stmt->num_rows == 1) {
// A user with this username already exists
$error_msg .= '<p class="error">A user with this username already exists</p>';
$stmt->close();
}
$stmt->close();
} else {
$error_msg .= '<p class="error">Database error line 55</p>';
$stmt->close();
}

// TODO:
// We'll also have to account for the situation where the user doesn't have
// rights to do registration, by checking what type of user is attempting to
// perform the operation.

if (empty($error_msg)) {
// Create a random salt
//$random_salt = hash('sha512', uniqid(openssl_random_pseudo_bytes(16), TRUE)); // Did not work
$random_salt = hash('sha512', uniqid(mt_rand(1, mt_getrandmax()), true));

// Create salted password
$password = hash('sha512', $password . $random_salt);

// Insert the new user into the database
if ($insert_stmt = $mysqli->prepare("INSERT INTO members (username, email, password, salt) VALUES (?, ?, ?, ?)")) {
$insert_stmt->bind_param('ssss', $username, $email, $password, $random_salt);
// Execute the prepared query.
if (! $insert_stmt->execute()) {
header('Location: ../error.php?err=Registration failure: INSERT');
}
}
header('Location: ./continue.php');
}
}
?>

Что я могу сделать, чтобы это исправить? Я хочу, чтобы пароль был изменен в формате, как при регистрации. Потому что теперь, когда я меняю пароль, он хэшируется, но не + соленый, поэтому он не работает при входе с новым паролем.

РЕДАКТИРОВАТЬ:
Вот скрипт входа в систему:

<?php
include_once 'psl-config.php';

function sec_session_start() {
$session_name = 'sec_session_id';   // Set a custom session name
$secure = SECURE;
// This stops JavaScript being able to access the session id.
$httponly = true;
// Forces sessions to only use cookies.
if (ini_set('session.use_only_cookies', 1) === FALSE) {
header("Location: ../error.php?err=Could not initiate a safe session (ini_set)");
exit();
}
// Gets current cookies params.
$cookieParams = session_get_cookie_params();
session_set_cookie_params($cookieParams["lifetime"],
$cookieParams["path"],
$cookieParams["domain"],
$secure,
$httponly);
// Sets the session name to the one set above.
session_name($session_name);
session_start();            // Start the PHP session
session_regenerate_id(true);    // regenerated the session, delete the old one.
}
function login($email, $password, $mysqli) {
// Using prepared statements means that SQL injection is not possible.
if ($stmt = $mysqli->prepare("SELECT id, username, password
FROM members
WHERE email = ?
LIMIT 1")) {
$stmt->bind_param('s', $email);  // Bind "$email" to parameter.
$stmt->execute();    // Execute the prepared query.
$stmt->store_result();

// get variables from result.
$stmt->bind_result($user_id, $username, $db_password );
$stmt->fetch();

// hash the password
$passwordHash = password_hash($password, PASSWORD_BCRYPT);
if ($stmt->num_rows == 1) {
// If the user exists we check if the account is locked
// from too many login attempts

if (checkbrute($user_id, $mysqli) == true) {
// Account is locked
// Send an email to user saying their account is locked
return false;
} else {
// Check if the password in the database matches
// the password the user submitted.
if ($db_password == $password) {
// Password is correct!
// Get the user-agent string of the user.
$user_browser = $_SERVER['HTTP_USER_AGENT'];
// XSS protection as we might print this value
$user_id = preg_replace("/[^0-9]+/", "", $user_id);
$_SESSION['user_id'] = $user_id;
// XSS protection as we might print this value
$username = preg_replace("/[^a-zA-Z0-9_\-]+/",
"",
$username);
$_SESSION['username'] = $username;
$_SESSION['email'] = $email;
$_SESSION['login_string'] = hash('sha512',
$password . $user_browser);
// Login successful.
return true;
} else {
// Password is not correct
// We record this attempt in the database
$now = time();
$mysqli->query("INSERT INTO login_attempts(user_id, time)
VALUES ('$user_id', '$now')");
return false;
}
}
} else {
// No user exists.
return false;
}
}
}
function checkbrute($user_id, $mysqli) {
// Get timestamp of current time
$now = time();

// All login attempts are counted from the past 2 hours.
$valid_attempts = $now - (2 * 60 * 60);

if ($stmt = $mysqli->prepare("SELECT time
FROM login_attempts
WHERE user_id = ?
AND time > '$valid_attempts'")) {
$stmt->bind_param('i', $user_id);

// Execute the prepared query.
$stmt->execute();
$stmt->store_result();

// If there have been more than 5 failed logins
if ($stmt->num_rows > 5) {
return true;
} else {
return false;
}
}
}
function login_check($mysqli) {
// Check if all session variables are set
if (isset($_SESSION['user_id'],
$_SESSION['email'],
$_SESSION['username'],
$_SESSION['login_string'])) {

$user_id = $_SESSION['user_id'];
$email = $_SESSION['email'];
$login_string = $_SESSION['login_string'];
$username = $_SESSION['username'];

// Get the user-agent string of the user.
$user_browser = $_SERVER['HTTP_USER_AGENT'];

if ($stmt = $mysqli->prepare("SELECT password
FROM members
WHERE id = ? LIMIT 1")) {
// Bind "$user_id" to parameter.
$stmt->bind_param('i', $user_id);
$stmt->execute();   // Execute the prepared query.
$stmt->store_result();

if ($stmt->num_rows == 1) {
// If the user exists get variables from result.
$stmt->bind_result($password);
$stmt->fetch();
$login_check = hash('sha512', $password . $user_browser);

if ($login_check == $login_string) {
// Logged In!!!!
return true;
} else {
// Not logged in
return false;
}
} else {
// Not logged in
return false;
}
} else {
// Not logged in
return false;
}
} else {
// Not logged in
return false;
}
}
function esc_url($url) {

if ('' == $url) {
return $url;
}

$url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url);

$strip = array('%0d', '%0a', '%0D', '%0A');
$url = (string) $url;

$count = 1;
while ($count) {
$url = str_replace($strip, '', $url, $count);
}

$url = str_replace(';//', '://', $url);

$url = htmlentities($url);

$url = str_replace('&amp;', '&#038;', $url);
$url = str_replace("'", '&#039;', $url);

if ($url[0] !== '/') {
// We're only interested in relative links from $_SERVER['PHP_SELF']
return '';
} else {
return $url;
}
}

1

Решение

Пожалуйста, посмотрите на password_hash () и password_verify () функция, MD5 или sha512 являются не подходит для хеширования паролей, потому что они слишком быстрые и слишком легко могут быть взломаны. Функция password_hash сама создаст соль, вам не понадобится дополнительное поле в базе данных для ее хранения.

// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);

// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);

Примечание: при использовании функции password_hash нет необходимости экранировать пароль с помощью mysql_real_escape_string, просто используйте исходную запись пользователя.

Редактировать:

Поэтому я постараюсь указать на некоторые проблемы в вашем коде, честно говоря, это выглядит немного странно. Я попытался бы начать заново и использовать PDO или mysqli вместо функций mysql, это облегчит защиту от SQL-инъекций.

Сценарий смены пароля

Одна проблема состоит в том, что вы повторно используете переменную $ password, что приводит к неправильному сравнению, хотя, поскольку вы использовали == вместо =, это ничего не делает:

$password = mysql_real_escape_string(md5($_POST['password']));
...
$password == $rows['password'];
...
elseif ($password != $password):
$msg = "The CURRENT password you entered is incorrect.";

Я сам трачу много времени на поиск описательных имен переменных, это помогает предотвратить подобные ошибки.

$oldPassword = $_POST['password'];
...
$passwordHashFromDb = $rows['password'];
...
elseif (!password_verify($oldPassword, $passwordHashFromDb))
$msg = "The CURRENT password you entered is incorrect.";

Затем, прежде чем сохранить новый пароль в базе данных, вы вычисляете хеш:

$username = mysql_real_escape_string($_POST['username']);
$newPassword = $_POST['npassword'];
...
$newPasswordHash = password_hash($newPassword, PASSWORD_BCRYPT);
mysql_query("UPDATE members SET password = '$newPasswordHash' WHERE username = '$username'");

Учетно-скрипт

В вашем сценарии регистрации есть другие проблемы, вы наверняка не ожидаете, что пользователь введет 128-значный пароль?

if (strlen($password) != 128) { // looks strange to me

Вместо использования другого хэш-алгоритма, вы должны использовать то же, что и выше:

// Create salted password
$passwordHash = password_hash($password, PASSWORD_BCRYPT);

// Insert the new user into the database
if ($insert_stmt = $mysqli->prepare("INSERT INTO members (username, email, password) VALUES (?, ?, ?)")) {
$insert_stmt->bind_param('sss', $username, $email, $passwordHash);
...

Логин-скрипт

В вашем скрипте входа вы проверяете, совпадает ли пароль с паролем, хранящимся в базе данных.

if ($db_password == $password) {
// Password is correct!

Там вы должны проверить хеш следующим образом:

if (password_verify($password, $db_password) {
// Password is correct!

Вызов функции password_hash () не помогает в сценарии входа и должен быть удален.

2

Другие решения

Есть еще несколько комментариев в модифицированном коде. Вот как вы должны это сделать.
Получить старую соль из вашей базы данных

//Gather database information
while ($rows = mysql_fetch_array($query)):

$username = $rows['username']; //single equals to assign value
$password = $rows['password'];
$user_salt = $rows['salt']; // here get old salt

endwhile;

и эту часть, чтобы прочитать и использовать старую соль

else:

//$msg = "Your Password has been changed.";
$salted_password = hash('sha512', $npassword . $user_salt);// here use old salt
mysql_query("UPDATE members SET password = '$salted_password' WHERE username = '$username'");endif;
0

По вопросам рекламы [email protected]