更改密码类、crypt()和比较+检查旧密码


Change password class, crypt() and comparison + checking old pass

好的,所以我正在我的网站的这个更改密码部分编码。

请注意,我只有几个星期大的PHP。

这就是为什么我以前使用md5进行密码加密,但我研究了密码安全性,并决定使用PHP的crypt()函数来散列我的密码,而不仅仅是md5左右

我以前的更改密码功能遇到了一个问题,在将新密码保存到数据库后,用户会话被中止,导致用户注销。旧密码更改站点供参考:http://pastebin.com/hf6WhtEQ

我最初的方法是使用session_regenerate_id()来更新会话,因为简单地更新cookie中的密码似乎不起作用。

这种方法一开始似乎有效,但经过进一步的测试,很明显它是无用的。

所以我从头开始,并创建了以下代码。

我还没有实现cookie,因为我仍然不确定如何进行,并且希望在设置新cookie之前首先确保我有强大的密码安全性。

现在我的计划是这样的:

  1. 我检查用户是否已登录以及帐户的所有者。

  2. 我想检查数据库中的密码是否与$oldpass中的密码匹配。

  3. 我想比较$newpass$repeatpass,如果两个密码匹配,那么我想使用crypt()加密$newpass

  4. 最后,我想用新的加密密码更新数据库,并用新的通行证更新cookie,同时确保用户保持登录状态。

现在,我的问题是:

  1. 为什么我一直收到消息"该用户不存在或尚未激活,请按后退",尽管标题中显然有用户名。

  2. 我怎么能把一切都安排得井井有条,一切都按照我的计划进行。(现在它有点无序,我不确定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是一个更好的选择,但这可能只是个人的选择。