好的,所以我正在我的网站的这个更改密码部分编码。
请注意,我只有几个星期大的PHP。
这就是为什么我以前使用md5进行密码加密,但我研究了密码安全性,并决定使用PHP的crypt()函数来散列我的密码,而不仅仅是md5左右
我以前的更改密码功能遇到了一个问题,在将新密码保存到数据库后,用户会话被中止,导致用户注销。旧密码更改站点供参考:http://pastebin.com/hf6WhtEQ
我最初的方法是使用session_regenerate_id()
来更新会话,因为简单地更新cookie中的密码似乎不起作用。
这种方法一开始似乎有效,但经过进一步的测试,很明显它是无用的。
所以我从头开始,并创建了以下代码。
我还没有实现cookie,因为我仍然不确定如何进行,并且希望在设置新cookie之前首先确保我有强大的密码安全性。
现在我的计划是这样的:
-
我检查用户是否已登录以及帐户的所有者。
-
我想检查数据库中的密码是否与
$oldpass
中的密码匹配。 -
我想比较
$newpass
和$repeatpass
,如果两个密码匹配,那么我想使用crypt()
加密$newpass
。 -
最后,我想用新的加密密码更新数据库,并用新的通行证更新cookie,同时确保用户保持登录状态。
现在,我的问题是:
-
为什么我一直收到消息"该用户不存在或尚未激活,请按后退",尽管标题中显然有用户名。
-
我怎么能把一切都安排得井井有条,一切都按照我的计划进行。(现在它有点无序,我不确定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.hp:
<?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);
}
}
?>
当他们登录时,您有他们的旧通行证,因为他们需要在登录时以明文形式提供给您。如果是这种情况,为什么不从数据库中提取两个密码(旧密码和新密码)呢。如果是旧的通行证,md5 it,如果相等,则将新的加密密码(基于他们输入的内容)存储到数据库中(同时清除旧通行证),如果是新通行证,则通过新的密码方法进行比较。
此外,顺便说一句,因为我们谈论的是安全。绑定参数,而不是像那样把它们放在代码中!这实际上消除了sql注入的可能性,并允许您不必对所有输入运行regex。
在您的方法中,我想到了一些事情。首先你提到使用crypt加密密码。这是对数据进行哈希处理的一种方式,而不是真正的加密。php和mysql中有适当加密的内置函数,这意味着密码可以在必要时解密,但存储安全。散列例程,如MD5,是不安全的,并且已经被破坏,因此一种更稳健的方法是使用256密码和一个非常复杂的密钥来加密密码。
例如,在mysql:中
aes_encrypt('password','complex key') /*to encrypt*/
aes_decrypt( '<encrypted pwd>,'complex key' ) /*to decrypt*/
第二:为了同意Danbopes的观点,bindParams实际上消除了sql注入攻击,这是一件好事。
Thridly:你提到将密码存储在cookie中,即使是以哈希形式。这是一个非常糟糕的主意,需要避免。如果攻击者截获了那个cookie怎么办?
最后,mysqli很好,但在我看来,PDO是一个更好的选择,但这可能只是个人的选择。