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

时间:2015-02-20 08:02:14

标签: php cookies crypt

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

请注意,我只用PHP几周了。

这就是我之前使用md5进行密码加密的原因,但我研究了密码安全性,并决定使用PHP的crypt()函数来哈希我的密码,而不仅仅是md5左右。

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

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

这种方法似乎最初起作用,但经过进一步的测试,很明显它没用了。

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

我还没有实现cookie,因为我仍然不确定如何去做,并且在我设置新cookie之前要确保我拥有强大的密码安全性。

现在我的计划如下:

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

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

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

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

  5. 现在,我的问题是:

    1. 为什么我一直收到消息"该用户不存在或尚未激活,请按"即使标题明显包含用户名。

    2. 如何按照我的计划将一切都按照良好的方式进行处理。 (现在它是无序的,我不知道if语句的正确顺序应该是什么)。

    3. 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);
          }
      }
      ?>
      

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

我的方法出现了几件事。 首先,您提到使用crypt加密密码。这是数据散列的一种方式,而不是真正的加密。在php和mysql中,内置了正确加密的功能 - 这意味着密码可以在必要时解密,但可以安全存储。哈希例程(例如MD5)不安全且已被破坏,因此更强大的方法是使用256cipher和非常复杂的密钥加密密码。

例如,在mysql中:

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

第二:为了同意上面的Danbopes,bindParams几乎消除了sql注入攻击,这必须是一件好事。

Thridly:你提到将密码存储在cookie中 - 即使是以散列形式存储。这是一个非常糟糕的主意,是值得避免的。如果攻击者截获该cookie会怎么样?

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