【问题标题】:How to check username and password matches the database values如何检查用户名和密码是否与数据库值匹配
【发布时间】:2018-03-30 21:24:11
【问题描述】:

如果这个问题看起来很愚蠢,我真的很抱歉。但是几天来我一直在尝试检查我在数据库中的usernamepassword 是否与我在html 页面中输入的内容相匹配...这是我的登录表单...

<form method="POST" action="Dashboard/Dashboard.php">

    <div class="form-group md-form">
        <!--<input type="email" class="form-control" id="email" value="" placeholder="Enter email address">-->
        <i class="fa fa-user prefix grey-text"></i>
        <input name="username" id="username" type="text" class="form-control" required>
        <label for="defaultForm-email">Username</label>
    </div>
    <div class="form-group md-form">
        <!--<input type="password" class="form-control" id="password" value="" placeholder="Enter password">-->
        <i class="fa fa-lock prefix grey-text"></i>
        <input name="password" id="password" type="password"  class="form-control" required>
        <label for="defaultForm-pass">Your password</label>
    </div>
    <div class="text-center">
        <button type="reset" class="btn btn-amber btn-sm"><strong>Reset</strong></button>
        <input type="submit" name="submit" id="submit" class="btn btn-green btn-sm" value="Sign in">                                           
    </div>

</form>

这是我在Dashboard.php中使用的代码(php)

<?php
    $servername = "localhost";
    $username = "root";
    $password = "";
    $databaseName = "test";

    $conn = mysqli_connect($servername, $username, $password, $databaseName);

    $un = $_POST['username'];
    $pw = $_POST['password'];
    print $pass . "_" . $email;

    $query = mysqli_query($conn, "SELECT log_username,log_password FROM login WHERE log_username='$un' AND log_password='$pw'");

    $result_can = mysqli_query($conn, $query);


    while ($row = mysql_fetch_assoc($result_can)) {


        $check_username = $row['username'];
        $check_password = $row['password'];
    }
    if ($un == $check_username && $pw == $check_password) {
        $message = "ok";
        echo "<script type='text/javascript'>alert('$message');</script>";
        header("Location: Doctors.php");
    } else {
        $message = "No";
        echo "<script type='text/javascript'>alert('$message');</script>";
        header("Location: Doctors.php");
    }
    ?>

我真的尝试了数千次,但无法弄清楚我哪里出错了......谁能帮帮我?

我知道我的代码对 SQL 注入开放,但我不关心它,因为这是我需要向朋友展示的示例所以忽略那部分。

【问题讨论】:

  • "我知道我的代码对 SQL 注入开放,但我不在乎"。曾经写过的一些最危险的词:)
  • 为什么要向你的朋友展示一个没人应该做的事情的例子?从一开始就向他们展示如何正确地做到这一点。此外,您还没有真正说明过您实际上遇到了什么问题。
  • 很高兴知道:您在数据库上将密码保存为纯文本,非常糟糕,但您并不关心。并且比较它们也是非常错误的。
  • 不要混合不同的数据库接口。当你使用mysqli时,你不能使用mysql_fetch_assoc
  • 您还尝试从数据库中获取log_usernamelog_password;但在 $row 数组中将它们引用为 usernamepassword

标签: php mysql passwords password-hash php-password-hash


【解决方案1】:

Stack Overflow 面向“专业和狂热的程序员”。恕我直言,您已经在您的问题中向我们展示了代码,这些代码甚至都不配得上任何一个名字。它非常不安全,如果您将其放在公共互联网上,您的网站会被网络犯罪分子破解。

StackOverflow 的人对糟糕的安全代码没有太多幽默感。你对像你这样的代码有强烈的反应,因为,Equifax、Ashley Madison、Adobe,以及所有其他被网络犯罪分子破解的地方。我们为什么要跳到你身上?因为我们不喜欢网络犯罪分子,也不想让他们的生活变得轻松。朋友不要让朋友做不好的密码安全。朋友不会向朋友显示非常不安全的密码验证码。

您的代码有什么问题?您将密码存储为纯文本,并且容易受到 SQL 注入的攻击。我将解决第一个问题。

幸运的是,php 具有出色的行业领先设施来确保密码安全。在此处阅读有关它们的信息。 http://php.net/manual/en/faq.passwords.php 使用它们。您如何处理密码?

  1. 当用户在您的网站上注册并首次提供密码时,您会在服务器上运行的代码中对密码进行哈希处理,类似这样。
  $usersPassword = $_POST['password']);
  $hash = password_hash( $usersPassword , PASSWORD_DEFAULT );
  // you then store the username and the hash in your dbms. 
  // the column holding the hash should be VARCHAR(255) for future-proofing
  // NEVER! store the plain text (unhashed) password in your database
  1. 当用户尝试登录时,您在服务器上执行如下查询:

     SELECT log_password FROM log_user WHERE log_username = TheUsernameGiven
    

    然后您将检索到的密码放入名为$hash 的变量中。

    然后您再次在您的服务器上使用php's password_verify() function 来检查您的潜在用户刚刚给您的密码是否与您的数据库中的密码匹配。

    最后,在您的服务器上检查用户的密码是否需要重新散列,因为您之前用来散列密码的方法已经过时了。

 $usersPassword = $_POST['password']);
 $valid = password_verify ( $usersPassword, $hash );
 if ( $valid ) {
   if ( password_needs_rehash ( $hash, PASSWORD_DEFAULT ) ) {
     $newHash = password_hash( $usersPassword, PASSWORD_DEFAULT );
     /* UPDATE the user's row in `log_user` to store $newHash */
   }
   /* log the user in, have fun! */
 }
 else {
  /* tell the would-be user the username/password combo is invalid */
 }

这个序列是面向未来的,因为如果旧的散列方法太容易让网络窃贼破解,它可以在以后重新散列密码。许多用户帐户的生命周期远远长于 php 等软件包的版本。

要使密码等凭据保密,您必须使用 https,而不是 http,在浏览器和服务器之间进行连接。否则,网络犯罪分子可以拦截从您的用户到您的服务器的流量并获取她的密码。安装支持 https 的服务器可能会让人头疼,但它是部署 Web 应用程序的关键部分。 (Heroku 等服务可让您轻松使用 https 测试您的应用。)

【讨论】:

  • 您的示例不太清楚何时对用户密码进行哈希处理。在客户端创建它并发送哈希不是一个好习惯吗?我的教授和一些同事批评我没有这样做。他们说:永远不要在网络上发送未散列的身份验证信息。它可以被嗅探。
  • 所有密码哈希和验证都发生在服务器端。您必须使用 https 而不是 http 将用户名和密码或其他凭据从 Web 浏览器发送到服务器。这样可以防止他们被嗅到。至于散列密码客户端,我从来没有见过事情是这样工作的。愚蠢的教授技巧:发明新的和奇怪的方案来处理密码凭证。直接说不吧。
【解决方案2】:

几个问题,上面的cmets提到了一些。

混合 mysql_* 与 mysqli_* API

您使用mysqli_query() 调用查询,但您尝试使用mysql_fetch_assoc() 获取结果。您不能混合使用这些不同的 API。 mysql_* 函数不会使用您通过mysqli_connect() 打开的连接,反之亦然。选择一个 MySQL 扩展并坚持下去。

提示:不要使用mysql_*。它已被弃用,并已从 PHP 7.0+ 中删除

查询两个用户名和密码的条件

只需搜索用户名,然后获取密码。如果您搜索both,则搜索将返回零行,除非使用了正确的密码。

你不想这样。您希望避免将明文密码放在 SQL 查询中。只需搜索用户名,获取存储的密码,然后将获取的内容与用户输入的密码进行比较。

未初始化的变量

如果您从查询中获取零行,则永远不会设置 $check_username$check_password。然后在 if 语句中比较这些变量。不是致命错误,而是糟糕的风格。

无密码散列

您似乎正在将用户输入(我假设是纯文本)直接与数据库中存储的内容进行比较。 You're Probably Storing Passwords Incorrectly.

相反,当您存储密码时,请先使用password_hash()

无查询参数

我知道您说过您不关心您的 SQL 注入漏洞,但这就像是一名电工并且说您不关心您的电气面板是否塞满了油腻的破布。请务必在您的 LinkedIn 个人资料上发布您对安全的漠视,以便雇主知道应该避免谁。

推荐的实施方式

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); // enable exceptions

$conn = new mysqli($servername, $mysql_username, $mysql_password, $databaseName);

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

$sql = "SELECT log_username, log_password_hash FROM login WHERE log_username=?";
$stmt = $conn->prepare($sql);
$stmt->bind_param('s', $log_username);
$stmt->execute();
$result = $stmt->get_result();

while ($row = $result->fetch_assoc()) {
    if (password_verify($log_password, $row['log_password_hash'])) {
        $message = "ok";
        // header must be called before any other output
        header("Location: Doctors.php");
        exit();
    }
}
$message = "No";
// header must be called before any other output
header("Location: Doctors.php");

【讨论】:

    【解决方案3】:

    这里有几个问题,无论是在您的代码中还是在思考过程中。让我们继续努力吧:

    $un = $_POST['username'];
    $pw = $_POST['password'];
    print $pass . "_" . $email;
    

    print应该给你一个警告。变量$pass$email 不存在。您应该删除该行,除非您试图 改为打印$un$pw

    $query = mysqli_query($conn, "SELECT log_username,log_password FROM login WHERE log_username='$un' AND log_password='$pw'");
    

    无需同时选择用户名和密码列。如果有匹配项,它们将始终与您已经拥有的 $un$pw 相同。您只是检查用户名和密码是否正确,因此选择单列就足够了。最好是用户 ID,但只有用户名就足够了。

    请记住——假设查询成功执行——$query 将包含一个mysqli_result 对象。

    $result_can = mysqli_query($conn, $query);
    

    需要删除此行。你已经执行了你的查询,$query 是它的结果,你在这里做的事情没有意义,应该给你一个警告,甚至可能是一个致命的错误。

    while ($row = mysql_fetch_assoc($result_can)) {
        $check_username = $row['username'];
        $check_password = $row['password'];
    }
    if ($un == $check_username && $pw == $check_password) {
        $message = "ok";
        echo "<script type='text/javascript'>alert('$message');</script>";
        header("Location: Doctors.php");
    } else {
        $message = "No";
        echo "<script type='text/javascript'>alert('$message');</script>";
        header("Location: Doctors.php");
    }
    

    不能混合使用 mysql_*mysqli_* 函数。在这里使用mysql_fetch_assoc() 应该会给你一个致命错误。您应该改用mysqli_fetch_assoc()(在$query 上而不是$result_can),但是:

    由于您只关心是否有任何结果,因此可以将整个部分更改为:

    if (mysqli_num_rows($query) > 0) {
        $message = "ok";
        echo "<script type='text/javascript'>alert('$message');</script>";
        header("Location: Doctors.php");
    } else {
        $message = "No";
        echo "<script type='text/javascript'>alert('$message');</script>";
        header("Location: Doctors.php");
    }
    

    这会带来其他问题,因为在回显&lt;script&gt; 标记后,您无法使用header() 重定向用户(您将收到“标头已发送”错误)。如果您想要 Javascript 警报,请同时使用 Javascript 执行重定向。还有,那个$message这个变量比较没用,还不如直接把消息放到alert里面:

    if (mysqli_num_rows($query) > 0) {
        echo "<script type='text/javascript'>alert('ok'); window.location.href='Doctors.php';</script>";
    } else {
        echo "<script type='text/javascript'>alert('No'); window.location.href='Doctors.php';</script>";
    }
    

    一旦你解决了所有这些问题,你还有一些想法要做。

    • 您应该永远在数据库中以纯文本形式存储密码。
    • 您现在可能不关心 SQL 注入,但根据您当前的查询,我可以通过输入用户名admin' AND 1 -- 以任何有效用户(例如“admin”)身份登录,或者如果我只想访问我可以使用any' OR 1 -- 的用户名并作为表中的第一个用户登录。查看准备好的语句及其工作原理。
    • 您根本没有错误处理。您应该添加检查以查看数据库连接是否成功打开、查询是否正确执行、表单是否已发布以及用户名/密码字段是否已填写,并考虑如何向用户显示有用的错误消息。李>

    这里的主要教训应该是:当您正在开发并且它不起作用时,请始终检查错误日志以查看它是否包含任何提示并打开 PHP 的错误报告功能,以便您可以看到您做错了什么在您的浏览器中。

    【讨论】:

      猜你喜欢
      • 2017-01-02
      • 1970-01-01
      • 2015-12-06
      • 2014-05-20
      • 1970-01-01
      • 2015-04-25
      • 1970-01-01
      • 1970-01-01
      • 2018-05-12
      相关资源
      最近更新 更多