繁体   English   中英

如何在PHP登录表单中调试密码验证问题?

[英]How to debug password verification problems in PHP login form?

注册表格一切正常,但我不知道如何填写登录表格。 我进行了很多搜索,但是没有运气,我是PHP的新手。 请给我提示和解决方案。

if (isset($_POST['username']) && isset($_POST['password']))
{
  $username = $_POST['username'];
  $_SESSION['LoggedIn'] = $username; //store username in session
  $password = $_POST['password'];

  // To protect MySQL injection (more detail about MySQL injection)
  $username = stripslashes($username);
  $password = stripslashes($password);
  // $username = mysql_real_escape_string($username);
  // $password = mysql_real_escape_string($password);
  $hash_password = password_hash($password , PASSWORD_DEFAULT);
  $verify_password = password_verify($_POST['password'] , $hash_password);


  // check login errors
  $check_login_errors = LoginErrors($username , $password);
  if ($check_login_errors)
     {
       //search database
       $query = "SELECT * FROM users WHERE Username='$username' AND Password='$hash_password'";
       $query_result = mysqli_query($connection , $query);

       //check database for username
      if (mysqli_fetch_array($query_result,MYSQLI_NUM > 0))
       {
        //verify password and username
        if($verify_password == $username)
         {
          echo "logged in";
          $_SESSION['LoggedIn'];
          RedirectTo("profile.php");
         }
        else
         {
          echo "wrong password or username";
         }
       }
      else
      {
        echo "error with checking username in database";
      }
    }
  }

 ?> 

我尝试的一切都会给我最后一个错误:

检查数据库中的用户名时出错

注意,我也在PHP代码的顶部添加了session_start()

我相信您在这里没有正确使用password_verify哈希密码已经存在于数据库中(大概否则哈希的意义是什么?),因此您需要将该值与发布的密码进行比较。 我修改了代码以使用准备好的语句,因为原始语句可能仍然容易受到SQL注入的攻击。

同样,在某些情况下,在哈希/验证密码之前使用stripslashes会损坏密码。 例如,这将阻止包含反斜杠( \\ )的密码正常工作,并且这是密码中完全合法的字符。

if( isset( $_POST['username'], $_POST['password'] ) ){

    $username = $_POST['username'];
    $password = $_POST['password'];

    $stmt=$connection->prepare(
        'select `username`,`password` from `users` where `username`=?'
    );
    if( $stmt ){

        $stmt->bind_param( 's', $username );
        $result = $stmt->execute();

        if( $result ){
            $stmt->store_result();
            $stmt->bind_result( $uname,$upwd );
            $stmt->fetch();

            $stmt->free_result();
            $stmt->close();

            /* compare POSTed password and HASH from db */
            $verify = password_verify( $password, $upwd );

            if( $verify ){
                $_SESSION['LoggedIn'] = $username;
                header('Location: profile.php' );
            } else {
                /* more bad foo */
                echo "wrong password or username";
            }
        } else {
            echo "bad foo: error with checking username in database";
        }
    } else {
        echo "Failed to prepare sql query";
    }
}

-

PHP手册

准备好的语句执行包括两个阶段:准备和执行。 在准备阶段,将语句模板发送到数据库服务器。 服务器执行语法检查并初始化服务器内部资源以供以后使用。

准备之后是执行 在执行期间,客户端绑定参数值,并将其发送到服务器。 服务器根据语句模板和绑定值创建一条语句,以使用先前创建的内部资源执行该语句。

因此,要分解它:

$sql='select `username`,`password` from `users` where `username`=?';

sql语句获取两列,尽管实际上只需要密码。 注意使用? -这是我们将绑定变量的占位符-在本例中为$username 如果prepare方法失败,它将返回false,因此我们可以将其用作进行或救援的逻辑测试。

$stmt->prepare( $sql );

准备SQL查询,并返回一个语句句柄,以用于对该语句的进一步操作。 该查询必须包含一个SQL语句。
[阅读有关$ stmt-> prepare()的更多信息]

$stmt->bind_param( 's', $username );

此时必须已经成功准备了该语句,因此我们将$username变量绑定到占位符。 由于用户名是字符串,因此我们使用s作为类型。 可能有四种类型,它们如下:

i   corresponding variable has type integer
d   corresponding variable has type double
s   corresponding variable has type string
b   corresponding variable is a blob and will be sent in packets

[阅读有关$ stmt-> bind_param()的更多信息]

$result = $stmt->execute();

现在已经准备好该语句,并且所有变量都绑定到它们的占位符,提交查询并使用响应进行进一步的逻辑测试,因为这将在成功时返回TRUE或在失败时返回FALSE。
[阅读有关$ stmt-> execute()的更多信息]

$stmt->store_result();

使我们能够处理返回的记录集
[了解有关$ stmt-> store_result()的更多信息]

$stmt->bind_result( $uname,$upwd );

将变量绑定到准备好的语句以存储结果。 当查询获取两列时,我们绑定了两个变量-在此阶段它们不存在,但是在fetch实际记录集时将可用。
[阅读有关$ stmt-> bind_result()的更多信息]

$stmt->fetch();

从准备好的语句中获取结果到绑定变量中。 这使得$uname$upwd可以用作变量,但是我们希望(在合理范围内)
[阅读有关$ stmt-> fetch()的更多信息]

如果出现以下情况,则您在下面的地方犯了一个小错误:

if (mysqli_fetch_array($query_result,MYSQLI_NUM > 0))

使用此代替:

if (mysqli_fetch_array($query_result,MYSQLI_NUM) > 0)

语法:-mysqli_fetch_array(result,resulttype);

只是出于理智起见,在现实生活中可以使用来自已接受答案的代码。 当然,您不会编写一小段代码来运行一个单独的查询,是吗?

if( isset( $_POST['username'], $_POST['password'] ) ){
    $sql = 'select `username`,`password` from `users` where `username`=?';
    $stmt = $connection->prepare($sql);
    $stmt->bind_param( 's', $_POST['username'] );
    $stmt->execute();
    $stmt->bind_result( $uname,$upwd );
    if ($stmt->fetch() && password_verify( $_POST['password'], $upwd );
        $_SESSION['LoggedIn'] = $username;
        header('Location: profile.php' );
        exit;
    }
    echo "wrong password or username";
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM