2016-01-12 34 views
-6

我已經建立,它使用密碼散列函數如下一個非常簡單的登錄/註冊腳本:瞭解password_verify();

$password = password_hash($password, PASSWORD_DEFAULT); 

所有這一切確實需要我的密碼並彈出它到我在我所預期的格式DB。我遇到登錄部分和使用password_verify()函數的問題,我的登錄腳本我現在很簡單,很容易進行SQL注入,但我只是想了解它是如何工作的。

這裏是我的登錄腳本:

<?php 

ini_set('display_errors',1); 
error_reporting(E_ALL); 

ob_start(); 

include('db_con.php'); 

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

$username = stripslashes($username); 
$password = stripslashes($password); 

$sql="SELECT * FROM users WHERE username='$username' and password='$password'"; 
$result=mysqli_query($db,$sql); 

$count=mysqli_num_rows($result); 

if($count==1){ 

session_start(); 
    $_SESSION['loggedin'] = true; 
    $_SESSION['username'] = $username; 
header("location:home.php"); 
} 
else { 
echo "Wrong Username or Password"; 
} 
ob_end_flush(); 
?> 

我不知道在這一點我需要使用password_verify(),因爲我知道它有兩個參數,一個是密碼,另一個是哈希?

+0

你在這個代碼,將讓您的網站被黑客入侵的主要SQL注入漏洞。你爲什麼用這種方式編碼?從第一天開始練習安全代碼。該文檔包含一個使用'password_verify'的明確例子。 http://php.net/password_verify – ceejayoz

+2

你讀過我的問題了嗎?我知道它容易發生SQL注入 – PhpDude

+2

首先,請使用PDO並準備好語句。其次,你應該搜索用戶名,然後比較密碼,這樣你就知道用戶是否存在以及密碼是否正確。第三,當你比較數據庫中的密碼時,你沒有散列密碼。第四,你應該使用隨機生成的鹽,而不是所有密碼都相同的鹽,這會破壞用鹽散列的目的。 – Vilsol

回答

2

我看你用過mysqli_*函數。但是,如果您不使用準備好的語句,那麼它無法幫助您。這裏是你的問題的解決方案以及更好地利用預處理語句mysqli_*功能 -

首先通過用戶名從DB獲得哈希密碼。

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

//NO NEED of stripslashes if using prepared statements. 

$sql="SELECT password FROM users WHERE username = ?"; 
$stmt = mysqli_prepare($link, $sql); 

/* bind parameters for markers */ 
$stmt->bind_param("s", $username); 

/* execute query */ 
$stmt->execute(); 

/* store result (So that you can check num_rows immediately.) */ 
$stmt->store_result(); 

如果沒有行裏找到你已經可以拋出「無效的用戶」的錯誤!否則,只要使用password_verify()驗證密碼這種方式 -

if($stmt->num_rows()) { 
    /* bind result variables */ 
    $stmt->bind_result($hashed_password); 

    /* fetch value */ 
    $stmt->fetch(); 

    if(password_verify($password, $hashed_password)) { 
     //Login 
    } else { 
     //Password mismatch 
    } 
} else { 
    //User not found. 
} 
/* free result */ 
$stmt->free_result(); 

/* close statement */ 
$stmt->close(); 

如果你正確地使用準備好的語句,你將不再需要使用stripslashes()了。只是刪除這兩條線:

$username = stripslashes($username); //REMOVE THIS LINE 
$password = stripslashes($password); //REMOVE THIS LINE 
+0

叫我傻但第二個參數'$ hashed_pa​​ssword'它從哪裏獲得從? – PhpDude

+0

已經在前面的行中聲明瞭,旁邊的註釋已經提到「從返回的行中獲取」,我知道這個OP如何從結果行中獲取數據到變量中。 –

+0

我一定是這一切混亂在我的腦海 - 它看起來應該是簡單的,但我是在它的複雜,我認爲。我已經通過代碼更改了上述內容,現在頁面失敗 – PhpDude

-3

password_hash和password_verify在編寫時使用bcrypt。每次散列密碼時,bcrypt都不會返回相同的字符串。

步驟,使用哈希從數據庫中:

  1. 通過用戶名或電子郵件
  2. 如果沒有找到,顯示錯誤選擇用戶或重定向回形成。
  3. 使用password_verify
9

本質password_hash創造的東西的哈希稱爲。這個salt對於這個散列是唯一的,並且是散列的前幾個字符,並且運行password_hash會再次爲您提供不同的salt,因爲它是隨機生成的。

將salt添加到散列過程中的密碼中,以避免發生攻擊,例如僅僅爲查看結果查看哈希數據庫。看看下面的例子:

$2a$10$4m/TjukW7De5OszVFYL9quIXNz5pSDc2P.jX5A138G493Vqr0vUiO 

$2a是標識符說哈希是bcrypt

$10$告訴我們有10輪bcrypt

4m/TjukW7De5OszVFYL9qu的散列是鹽

IXNz5pSDc2P.jX5A138G493Vqr0vUiO這是哈希值。

因此,如果您只是使用password_hash來生成哈希,它將生成一個不同的隨機鹽,因此哈希將會不同。 password_verify函數捕獲你已經創建的散列,從中取出鹽並使用你擁有的鹽散列你的值。

password_verify($value, $hash)用作$value將是用戶輸入的密碼,並且需要$hash用於salt和來自舊散列的回合數量。

+0

這是解釋爲什麼你應該使用'password_verify'而不只是產生輸入的密碼和查詢應該是一個新的哈希唯一的答案。如果你能解釋一下password_hash可能會改變爲不同的哈希算法,那麼這可能會更加完整,這也可以被'password_verify'所覆蓋。最後,在用戶登錄後建議存儲密碼的新哈希值並不會造成什麼影響。這樣,如果新版本可用,而且完全透明,您將自動使用更強大的哈希更新密碼。 – GolezTrol

+0

所以我會把鹽放在與登錄腳本相同的文件中? – PhpDude

+0

鹽被存儲爲HASH的一部分,你不需要擔心它,當然它被'password_verify()'使用來驗證用戶輸入的文本字符串密碼與用' password_hash()'原本 – RiggsFolly