0

我需要有关我的登录脚本的帮助 - 它似乎已损坏。如果我没有输入密码,我仍然可以正确登录。另外,如果我不输入任何内容。但是,如果我输入了错误的用户名和密码,则表示我的登录凭据错误。

<?php   
    $verbindung = mysql_connect("localhost", "root" , "")
    or die("Verbindung zur Datenbank konnte nicht hergestellt werden"); 
    mysql_select_db("v1nce_website") or die ("Datenbank konnte nicht ausgewählt werden"); 

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

    $abfrage = "SELECT username, password FROM logins WHERE username='$username' LIMIT 1"; 
    $ergebnis = mysql_query($abfrage);
    $row = mysql_fetch_object($ergebnis);

    if($row->password == $password) 
        {
        $_SESSION["username"] = $username; 
        echo "<p>Login erfolgreich.</p>"; 
        } 
    else 
        { 
        echo "<p>Benutzername oder Passwort waren falsch. <a href=\"index.php?p=login\">Login</a></p>"; 
        } 
?>

任何帮助,将不胜感激。

4

4 回答 4

3

这个脚本中有很多令人担忧的事情:

  1. 让我们从您在这里的实际问题开始。如果您的查询找不到匹配的行,$row将等于false. 并且由于因此$row不是一个对象,因此$row->password将评估为NULL。因此,如果$password是一个空字符串$row->password == $password将评估为真,因为NULL == ""它是真的。

    如果您打开错误显示,例如ini_set( 'display_errors', true );,结合足够的错误报告级别,您会收到通知error_reporting( E_ALL );

    当您输入错误的用户名和密码时,$row->password将再次为NULL,但由于您输入了非空字符串作为密码,因此这次$row->password == $password将评估为假。

    因此,为了缓解这个问题,您需要确保在开始比较密码之前首先检查是否确实存在匹配的行,例如mysql_num_rows( $ergebnis )首先进行评估。

  2. 您的脚本容易受到SQL 注入的攻击。这意味着您的脚本的用户在输入 SQL hack 作为$_POST[ 'username' ]. 例如,如果我要输入' OR 1 = 1 --您的 SQL 查询,将导致以下结果(为显示目的而格式化):

    SELECT username, password
    FROM logins
    WHERE username='' OR 1 = 1 --' LIMIT 1
    

    ...如果表非空,则总是至少产生一行,因为WHERE username='' OR 1 = 1总是评估为真(--在 SQL 中表示注释,因此' LIMIT 1甚至不再评估)。

    为了缓解这个问题,在您当前的设置中,您需要先使用 清理输入值mysql_real_escape_string(),然后再将它们传递给 SQL 查询,如下所示:

    $username = mysql_real_escape_string( $_POST["username"] );
    

    但正如其他人已经建议的那样,您最好开始使用兼容 MySQL 的库,该库提供带有参数化查询的准备好的语句,例如PDOMySQLi,因为该mysql_*库正在被弃用,因为它提供的性能很差防御SQL注入的手段。

  3. 您的密码逐字(作为纯文本)存储在数据库中。这提供了账户(以及可能与用户相关的账户)被泄露的各种潜在风险。任何有权访问数据库的人(无论是直接访问、授权访问还是数据库遭到入侵时)都可以以明文形式查看密码,因此可以使用这些密码登录您的站点,或将其用作潜在的登录其他网站和/或服务。毕竟,人们在各种其他网站和服务中使用相同的用户名和密码组合并不少见。

    为了缓解这个问题,明智的做法是在将密码存储到数据库之前对密码进行散列(单向加密),然后,当用户想要登录时,将存储的散列值与散列值进行比较(使用相同的散列功能再次)的用户输入的密码。强烈建议使用每个用户密码的唯一作为额外的安全措施,因为这可以防止所谓的彩虹表攻击。

    有关首选散列算法是什么以及为什么要使用的更详尽解释,请参阅用户 Andrew Moore对此问题的回答。

于 2012-12-10T15:03:45.407 回答
1
$abfrage = "SELECT username, password FROM logins WHERE username='$username' LIMIT 1"; 
    $ergebnis = mysql_query($abfrage);
if(mysql_num_rows($ergebnis) > 0) // you can check for one
{
    $row = mysql_fetch_object($ergebnis);
//rest code goes inside here
// redirect to any page or do whatever you like
}
于 2012-12-10T14:45:29.640 回答
1

我假设您以这种方式登录以防止 SQL 注入,但是,mysql_real_escape_string() 将很快解决该问题。我会做这样的事情:

 $login = mysql_query("SELECT id FROM users WHERE username='" . mysql_real_escape_string($username) . "' AND password='" . mysql_real_escape_string($password) . "' LIMIT 1");
 if ( mysql_num_rows($login) > 0 ) {
      $user = mysql_fetch_array($login);
      $_SESSION['userID'] = $user['id'];
      echo 'Login successful!';
 } else { // login failed
      echo 'Login failed.';
 }

请注意,我将用户的 ID 存储在会话中,而不是他们的用户名。这通常是一个更好的主意,因为基于唯一的 auto_increment 索引值而不是文本用户名来管理用户活动要容易得多。大多数网站都没有,但如果您愿意,此方法允许您让多个用户拥有相同的用户名。但是,如果您这样做,请确保您根据他们的电子邮件地址而不是他们的用户名登录,因为您不希望有人以其他人的身份登录,因为他们共享相同的用户名。

此外,您应该加密密码。MD5 是一个简单的解决方案,可以这样实现:

 $password = md5($_POST['password']);

如果你 md5 输入密码,你也不需要担心斜线。希望有帮助。

于 2012-12-10T14:52:19.210 回答
1

也许密码没有从数据库中正确获取。用来print_r($row)确保那里的一切都很好。

还可以使用带有盐的 sha1 加密来提高安全性。还可以:

$username = mysql_real_escape_string($_POST["username"]);
$password = mysql_real_escape_string($_POST["password"]);

避免注射。

希望这可以帮助。

于 2012-12-11T06:06:56.103 回答