2017-07-06 57 views
0

我在本地服務器上建立了一個身份驗證系統,以使用PHP和MYSQL測試運行某些腳本以供我個人使用。我跑了下面的代碼,選擇從「用戶」表中的「用戶名」和「密碼」列,但我基普輸入正確的憑據後收到此錯誤:無法選擇用戶名和密碼用戶表(MySql)的列

Invalid username/password combination 

下面是腳本:

<?php // authentication.php 

require_once 'login.php'; 

$connection = new mysqli($hn, $un, $pw, $db); 
if ($connection->connect_error) die($connection->connect_error); 


if (isset($_SERVER['PHP_AUTH_USER']) && 
    isset($_SERVER['PHP_AUTH_PW'])) { 

     $un_temp = mysql_entities_fix_string($connection, $_SERVER['PHP_AUTH_USER']); 
     $pw_temp = mysql_entities_fix_string($connection, $_SERVER['PHP_AUTH_PW']); 

     $query = "SELECT * FROM users WHERE username='$un_temp' AND password='$pw_temp'"; 
     $result = $connection->query($query); 
     if (!$result) die($connection->error); 

    else if ($result->num_rows) { 

     $row = $result->fetch_array(MYSQLI_NUM); 
     $result->close(); 


      if (password_verify($pw_temp == $row[3])) { 

       echo "$row[0] $row[1] : Hi $row[0], you are now logged in as '$row[2]'"; 

      } 

     } 

      else die("Invalid username/password combination"); 

    } else { 

      header('WWW-Authenticate: Basic realm="Restricted Section"'); 
      header('HTTP/1.0 401 Unauthorized'); 
      die("Pleaser enter your username and password"); 
    } 

    $connection->close(); 

    function mysql_entities_fix_string($connection, $string) { 

     return htmlentities(mysql_fix_string($connection, $string)); 
    } 

    function mysql_fix_string($connection, $string) { 

     if (get_magic_quotes_gpc()) $string = stripslashes($string); 
     return $connection->real_escape_string($string); 
    } 

?> 
+1

** WARNING **:當使用'mysqli'你應該使用[參數化查詢( http://php.net/manual/en/mysqli.quickstart.prepared-statements.php)和['bind_param'](http://php.net/manual/en/mysqli-stmt.bind-param.php )將用戶數據添加到您的查詢。 **不要**使用手動轉義和字符串插值或串聯來實現此目的,因爲您將創建嚴重的[SQL注入漏洞](http://bobby-tables.com/)。意外地未經轉義的數據是一個嚴重的風險。使用綁定參數不那麼冗長,並且更容易檢查以檢查您是否正確地進行了操作。 – tadman

+0

如果你使用'mysql_entities_fix_string',那麼你在這裏遇到了一些嚴重的問題,那大概是手動滾動的函數是不夠的。 – tadman

+2

**警告**:編寫您自己的訪問控制層並不容易,並且有很多機會使其嚴重錯誤。請不要在[Laravel](http://laravel.com/)等任何現代開發框架(http://codegeekz.com/best-php-frameworks-for-developers/)上編寫自己的認證系統,內置了強大的[認證系統](https://laravel.com/docs/5.4/authentication)。絕對不會遵循[推薦的安全最佳實踐](http://www.phptherightway.com/#security),並且從不使用無用的弱散列(如SHA1或MD5 **)存儲密碼。 – tadman

回答

2

password_verify接受提交的密碼及其相關的密碼哈希值,但提供了一個布爾值($pw_temp == $row[3])請參閱:http://php.net/manual/en/function.password-verify.php

假設您使用不帶靜態鹽的password_hash將值保存在數據庫中。查詢密碼列是不可能的,因爲password_hash將自動以特定值對鹽密碼進行密碼驗證。這會阻止您將提交的值的第二個散列值與數據庫中的散列值進行比較。因此,您需要將用戶名存儲爲唯一索引或迭代重複的用戶名,並撥打password_verify來比較每個用戶的密碼。

假設用戶名在您的表中是唯一的,您應該更新您的代碼,如下所示。

if (!isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) { 
    header('WWW-Authenticate: Basic realm="Restricted Section"'); 
    header('HTTP/1.0 401 Unauthorized'); 
    die("Please enter your username and password"); 
} 
$un_temp = mysql_entities_fix_string($connection, $_SERVER['PHP_AUTH_USER']); 
$pw_temp = mysql_entities_fix_string($connection, $_SERVER['PHP_AUTH_PW']); 
$query = "SELECT * FROM `users` WHERE `username`='$un_temp'"; 
if (!$result = $connection->query($query)) { 
    die($connection->error); 
} 
if (!$result->num_rows) { 
    die("Invalid username/password combination"); 
} 
$row = $result->fetch_array(MYSQLI_NUM); 
$result->close(); 
if (password_verify($pw_temp, $row[3])) { 
    echo "$row[0] $row[1] : Hi $row[0], you are now logged in as '$row[2]'"; 
} 
$connection->close(); 

Demonstration請注意每個哈希密碼是如何不同的。 請記住,因爲我無法查詢數據庫,我使用了一個數組來顯示等效的過程。


也有在原始代碼的一些語法有關的問題,這將是一個有點多在評論注意。

else if應該是一個單詞,使它看起來像elseif[sic]以避免出現語法衝突,但由於在呼喚die()你的病情的結果,是不是需要一個else

isset可以驗證多個參數,因此如果不需要與&&比較,則再次調用它。[sic]

使用標識符引號(反引號)包裝列名和表名將有助於避免MySQL預留的關鍵字問題[sic]

SELECT * FROM `users` WHERE `username`='$un_temp' AND `password`='$pw_temp' 

最後,由於加密算法和成本受制於PHP安全更新[sic]之間切換。當使用password_hashpassword_verify,你應該始終確保密碼仍然是加密安全,使用password_needs_rehash[sic]像這樣:

if (password_verify($password, $oldHash)) { 
    //verify legacy password to new password_hash options 
    if (password_needs_rehash($oldHash, \PASSWORD_DEFAULT)) { 
     //rehash/store plain-text password using new hash 
     $newHash = password_hash($password, \PASSWORD_DEFAULT); 
     $updateSQL = "UPDATE `users` SET `password`='$newHash' WHERE `username`='$un_temp' AND `password`='$oldHash'"; 
     $connection->query($updateSQL); 
    } 
} 
+0

這解決了我的問題。我發現舊代碼中我錯了。我用你發佈的內容更新後運行腳本,現在一切正常。謝謝 – shallowGeek

相關問題