Хорошо, поэтому я кодирую эту секцию смены пароля моего сайта.
Обратите внимание, что мне всего несколько недель на PHP.
Вот почему я раньше использовал md5 для шифрования паролей, но я исследовал безопасность паролей и решил использовать функцию crypt() PHP для хеширования моих паролей, а не только md5 или так далее.
У меня возникла проблема с моей предыдущей функцией смены пароля, в которой пользователи были прерваны после сохранения нового пароля в базе данных, в результате чего пользователь вышел из системы. Старый сайт смены пароля для справки: http://pastebin.com/hf6WhtEQ
Мой первоначальный подход состоял в том, чтобы использовать session_regenerate_id()
для обновления сеанса, потому что казалось, что простое обновление пароля в файле cookie не сработало.
Первоначально этот подход работал, но затем при дальнейшем тестировании было ясно, что это бесполезно.
Поэтому я начал с нуля и создал свой следующий код.
Я еще не реализовал файл cookie, поскольку я до сих пор не уверен, как это сделать, и хочу, чтобы у меня была надежная защита паролем, прежде чем я установил новые куки.
Теперь мой план выглядит так:
Я проверяю, зарегистрирован ли пользователь и владелец учетной записи.
Я хочу проверить, соответствует ли пароль в базе данных паролю в $oldpass
.
Я хочу сравнить $newpass
и $repeatpass
, если оба пароля совпадают, тогда я хочу $newpass
с помощью crypt()
.
Наконец, я хочу обновить базу данных новым зашифрованным паролем, а также обновить файл cookie новым проходом, убедившись, что пользователь остается в системе.
Теперь, мой вопрос:
Почему я продолжаю получать сообщение "Этот пользователь не существует или еще не активирован, нажмите" назад ", хотя заголовок явно имеет имя пользователя в нем.
Как я могу принести все в порядке, где все выполняется в соответствии с моим планом. (прямо сейчас его вид неупорядоченного и im не уверен, какой должен быть правильный порядок операторов if и т.д.).
change_pass.php:
<?php
include 'check_login_status.php';
$u="";
$oldpass=md5("");
//stripping both strings of white spaces
$newpass = preg_replace('#[^a-z0-9]#i', '', $_POST['newpass']);
$repeatpass = preg_replace('#[^a-z0-9]#i', '', $_POST['repeatpass']);
//get the username from the header
if(isset($_GET["u"])){
$u = preg_replace('#[^a-z0-9]#i', '', $_GET['u']);
} else {
header("location: compare_pass.php?u=".$_SESSION["username"]);
exit();
}
// Select the member from the users table
$sql = "SELECT * FROM users WHERE username='$u' AND password='$oldpass' LIMIT 1";
$user_query = mysqli_query($db_conx, $sql);
// Now make sure that user exists in the table
$numrows = mysqli_num_rows($user_query);
if($numrows < 1){
echo "That user does not exist or is not yet activated, press back";
exit();
}
$isOwner = "no";
//check if user is logged in owner of account
if($u == $log_username && $user_ok == true){
$isOwner = "yes";
}
$passhash = "";
if (($newpass) === ($repeatpass)) {
$passhash = crypt_sha256("$newpass", "B-Pz=0%5mI~SAOcW0pMUdgKQh1_B7H6sbKAl+9~O98E9MBPrpGOtE65ro~8R");
} else {
echo "comparison failed! :(";
}
//
if (isset($_POST["submit"]) &&($isOwner == "yes") &&($user_ok == true) &&($newpass) === ($repeatpass)) {
$sql = "UPDATE users SET 'password'='$passhash' WHERE username='$u' LIMIT 1";
}
?>
<h3>Create new password</h3>
<form action="" method="post">
<div>Current Password</div>
<input type="text" class="form-control" id="password" name="oldpass" >
<div>New Password</div>
<input type="text" class="form-control" id="password" name="newpass" >
<div>Repeat Password</div>
<input type="text" class="form-control" id="password" name="repeatpass" >
<br /><br />
<input type="submit" name="submit" value="Submit">
<p id="status" ></p>
</form>
check_login_status.php:
<?php
session_start();
include_once("db_conx.php");
// Files that inculde this file at the very top would NOT require
// connection to database or session_start(), be careful.
// Initialize some vars
$user_ok = false;
$log_id = "";
$log_username = "";
$log_password = "";
// User Verify function
function evalLoggedUser($conx,$id,$u,$p){
$sql = "SELECT ip FROM users WHERE id='$id' AND username='$u' AND password='$p' AND activated='1' LIMIT 1";
$query = mysqli_query($conx, $sql);
$numrows = mysqli_num_rows($query);
if($numrows > 0){
return true;
}
}
if(isset($_SESSION["userid"]) && isset($_SESSION["username"]) && isset($_SESSION["password"])) {
$log_id = preg_replace('#[^0-9]#', '', $_SESSION['userid']);
$log_username = preg_replace('#[^a-z0-9]#i', '', $_SESSION['username']);
$log_password = preg_replace('#[^a-z0-9]#i', '', $_SESSION['password']);
// Verify the user
$user_ok = evalLoggedUser($db_conx,$log_id,$log_username,$log_password);
} else if(isset($_COOKIE["id"]) && isset($_COOKIE["user"]) && isset($_COOKIE["pass"])){
$_SESSION['userid'] = preg_replace('#[^0-9]#', '', $_COOKIE['id']);
$_SESSION['username'] = preg_replace('#[^a-z0-9]#i', '', $_COOKIE['user']);
$_SESSION['password'] = preg_replace('#[^a-z0-9]#i', '', $_COOKIE['pass']);
$log_id = $_SESSION['userid'];
$log_username = $_SESSION['username'];
$log_password = $_SESSION['password'];
// Verify the user
$user_ok = evalLoggedUser($db_conx,$log_id,$log_username,$log_password);
if($user_ok == true){
// Update their lastlogin datetime field
$sql = "UPDATE users SET lastlogin=now() WHERE id='$log_id' LIMIT 1";
$query = mysqli_query($db_conx, $sql);
}
}
?>
Несколько вещей происходят со мной с вашим подходом. Во-первых, вы упоминаете использование пароля с использованием crypt. Это одно из способов хэширования данных, а не шифрование. В php и mysql встроены функции для правильного шифрования - при необходимости пароли могут быть дешифрованы, но надежно сохранены. Процедуры хеширования, такие как MD5, не являются безопасными и были разбиты, поэтому более надежный подход заключался бы в шифровании паролей с использованием 256-битного и очень сложного ключа.
Например, в mysql:
aes_encrypt('password','complex key') /*to encrypt*/
aes_decrypt( '<encrypted pwd>,'complex key' ) /*to decrypt*/
Второе: чтобы согласиться с Danbopes выше, bindParams практически исключает атаки на SQL-инъекции, что должно быть хорошо.
Вкратце: вы упоминаете, как хранить пароль в файле cookie - даже в хешированной форме. Это очень плохая идея, и ее нужно избегать. Что делать, если злоумышленник перехватил этот файл cookie?
Наконец, mysqli хорош, но PDO, на мой взгляд, является лучшей альтернативой, но это, вероятно, просто личный выбор.
У вас есть свой старый проход, когда они входят в систему, потому что они должны предоставить его вам в открытом виде, когда они заходят в систему. Если это так, почему бы вам просто не вытащить оба пароля из базы данных (старые и новые). Если это старый проход, md5 он, и если он равен хранению нового зашифрованного пароля (на основе того, что они ввели) в базу данных (наряду с очисткой старого прохода), а если это новый проход, сравните его через новый криптографический метод.
Кроме того, на стороне примечание, поскольку мы говорим о безопасности. Привяжите свои параметры вместо того, чтобы вставлять их в свой код! Это практически исключает возможность внедрения sql и позволяет вам не запускать регулярное выражение против всех ваших входов.