【问题标题】:Change password class, crypt() and comparison + checking old pass更改密码类、crypt() 和比较 + 检查旧通行证
【发布时间】:2015-02-20 08:02:14
【问题描述】:

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

请注意,我才刚接触 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.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);
    }
}
?>

【问题讨论】:

  • 如果你把这个问题稍微精简一点,每个人都会真正受益。您正在就三个充满代码的屏幕提出四个不同的问题,其中的序言似乎大多无关紧要且难以理解。这种方式很难得到有用的答案。如果有的话,一次问一个问题。
  • 是的,确实如此,需要回答的输入很多,我只是认为最好将所有内容都包含在一篇文章中,而不是将所有内容分开并冒着因问太多问题而受到惩罚的风险。

标签: php cookies crypt


【解决方案1】:

他们登录时您拥有他们的旧通行证,因为他们需要在登录时以明文形式提供给您。如果是这种情况,为什么不将两个密码都从数据库(旧密码和新密码)中提取出来。如果它是旧通行证,md5 它,如果它相等,则将新的加密密码(基于他们输入的内容)存储到数据库中(连同清除旧通行证),如果是新通行证,然后通过你的新通行证进行比较crypt 方法。

另外,顺便说一句,因为我们正在谈论安全性。 Bind your parameters 而不是像那样把它们放在你的代码中!这实际上消除了 sql 注入的可能性,并允许您不必针对所有输入运行正则表达式。

【讨论】:

  • 出于安全原因,我认为最好不要真正从数据库中提取密码,而是将用户提供的旧密码与存储在数据库中的密码进行比较。把数据库里的密码拿到代码里会不会很危险?
  • 并非如此。他们已经在 $_POST 数组中以明文形式提供了密码,所以我不明白为什么从数据库中提取加密密码并通过 php 进行比较会是一个问题。
  • 好的,谢谢你的建议,我会用你的方法来比较旧密码。
  • 这也消除了对密码重置屏幕的需要!带来更好的最终用户体验。
  • 我计划扩展这个站点,让用户能够更改数据库中的用户数据。你的意思是一个额外的网站来更改他们的密码?
【解决方案2】:

你的方法让我想到了几件事。 首先,您提到使用 crypt 对密码进行加密。这是数据散列的一种方式,而不是真正的加密。在 php 和 mysql 中,内置了用于正确加密的函数——这意味着密码可以在必要时被解密,但可以安全地存储。诸如 MD5 之类的哈希例程不安全并且已被破坏,因此更可靠的方法是使用 256cipher 和非常复杂的密钥来加密密码。

例如在mysql中:

aes_encrypt('password','complex key') /*to encrypt*/
aes_decrypt( '<encrypted pwd>,'complex key' ) /*to decrypt*/

第二:同意上面 Danbopes 的观点,bindParams 实际上消除了 sql 注入攻击,这一定是件好事。

第三:您提到将密码存储在 cookie 中——即使是散列形式。这是一个非常糟糕的主意,应该避免。如果攻击者截获了该 cookie 怎么办?

最后 - mysqli 很好,但在我看来,PDO 是更好的选择 - 但这可能只是个人选择。

【讨论】:

  • 很棒的输入!谢谢你。然后,我认为我应该将用户的一些其他数据存储在 cookie 中,而不是密码。这是一个很好的观点。由于我还是新手,所以我只是学习了一些使用 mysqli 的教程,我决定稍后学习 pdo,因为它更复杂并且能够使用所有数据库,我认为作为初学者学习对我来说太难了。
猜你喜欢
  • 2011-09-10
  • 1970-01-01
  • 2011-03-09
  • 1970-01-01
  • 1970-01-01
  • 2014-10-10
  • 2014-07-27
  • 1970-01-01
  • 2021-09-27
相关资源
最近更新 更多