2010-12-16 88 views
1

我在这里有一些用于登录系统的代码,纯粹是为了学习的目的,它是由来自stackoverflow的伟大人物的一些主要帮助创建的,并且我被告知不要存储salt和hash分离,而是一起存储。我想知道如何在用户尝试登录时比较密码。如果盐不存储,我怎么能比较这两个。谁能帮忙?如何比较使用此代码登录的用户密码?

require("constants.php"); 
$DBH = new mysqli($dbhost, $dbuser, $dbpass, $dbname); 

function createSalt() { 
    $length = mt_rand(64, 128); 
    $salt = ''; 
    for ($i = 0; $i < $length; $i++) { 
     $salt .= chr(mt_rand(33, 255)); 
    } 
    return $salt; 
} 
//Salt function created by ircmaxell 

function registerNewUser() { 
    //Check to see if  Username Is In Use// 
    $q = $DBH->prepare("SELECT id FROM users WHERE username = ?"); 
    $username = filter_var($username, FILTER_SANITIZE_STRING); 
    $data = array($username); 
    $q->execute($data); 
    $row = $q->fetch(); 

    if ($row === false) { 
     //If Username Is Not Already In Use Insert Data// 
     $hash = hash('sha256', $pass); 
     $salt = createSalt(); 
     $hash = hash('sha256', $salt . $hash . $pass); //UPDATED 
     $data = array($username, $hash, $salt); 
     $qInsert = $DBH->prepare(
      "INSERT INTO users (username, password, salt) values (?, ?, ?)" 
     ); 
     $qInsert->execute($data); //Inserts User Data Into Table// 
    } 
} 
+0

你可以安全地跳过'$ hash = hash('sha256',$ pass);' – Jacco 2010-12-16 09:36:31

回答

2

你要查询数据库检索用户行(如果有的话),得到盐,并使用相同的算法在由用户提供的密码。如果两个哈希都匹配,则用户提供了一个好的密码。

做一些代码,它将使这样的:

$qSelect = $DBH->prepare('SELECT salt,password FROM users WHERE username = ?'); 
$qSelect->execute(); 
$qSelect->bind_result($salt, $db_password); 
$qSelect->fetch(); 

if($salt == null){ 
    // username doesn't exist 
    return; 
}  

$hash = hash('sha256', $pass); 
$hash = hash('sha256', $salt . $hash . $pass); 
if($hash == $db_password){ 
    // login ok 
} else { 
    // login nok 
} 
+0

我是否需要将salt存储在某个地方?因为再次运行盐的代码不会产生相同的结果,所以我想不出另一种重新创建哈希的方法。 – mcbeav 2010-12-16 03:49:10

+0

@mcbeav:相同的盐和相同的密码应**总是**产生相同的散列。 – zerkms 2010-12-16 03:49:45

+0

“我需要将盐储存在什么地方吗?” - 你已经做到了 - 你将它存储在'salt'字段中。 – zerkms 2010-12-16 03:50:18

2

做同样的工作:根据用户名

$hash = hash('sha256', $row['salt'] . hash('sha256', $pass) . $pass); 
if ($row['password'] == $hash) { 
    // the password is correct 
} 

$row已经从数据库中获取,而$pass是从表单中检索密码。

此外,它是没有意义的包括在散列密码两次:散列和纯文本一个

$hash = hash('sha256', $salt . $pass); // this would be enough 
+0

@zerkms:这并不是毫无意义,因为它增加了破解密码的复杂性。因为你必须做两次sha256。另外,即使短密码也很难破解,因为无论如何hash都是一个很长的字符串。 – RageZ 2010-12-16 03:53:27

+0

谢谢!我不知道这一点。代码被改变为实际上不存储盐,没有看到我发布了错误的代码,但我假设我必须在这里存储盐,以使事情能够工作。是否将数据库中的盐储存起来使其不那么安全? – mcbeav 2010-12-16 03:53:51

+0

@RageZ:实际上,在这部分中,2个计算比1慢,但确实没有更长的字符串更安全(因为它是从相同的数据准备的)。 – zerkms 2010-12-16 03:54:39

1

问题:

1)你的用于创建哈希+盐的密码散列法是非传统的。这不是严格的问题,它只是不是你想要的。 zerkms非常清楚地表达了这一点。

2)你的数据库插入要求要么用户名是一个独特的列,缺少一些异常处理,或者很容易受到一场比赛,这将导致多个用户使用相同的用户名和不同的密码(如果是不同的ID是一个关键)

+0

我很抱歉,我不确定我是否完全理解你的答案。对于第二部分,你是否说过检查用户名是否正在使用的函数编写不正确?如果是这样,关于如何解决这个问题的任何想法?我是mysqli和PDO的新手,虽然这是mysqli。至于第一部分,你认为这可能会导致任何问题?也许表演? – mcbeav 2010-12-16 04:03:40

相关问题