如何在PHP上将哈希密码与openssl_random_pseudo_bytes盐进行比较

时间:2019-02-16 19:49:39

标签: php

//generating Excel File
$setSql = "SELECT * from demo table";
$setRec = mysqli_query($db, $setSql);  

$header_name="DATA LIST IN EXCEL";
$Event= "This is a demo";
date_default_timezone_set("Asia/Kolkata");
$date='Export Date:-'.date("l, jS \of F Y h:i:s A");
$columnHeader = ''; 
$columnHeader = "Name" . "\t" . "Date" . "\t". "Mode No" . "\t". "Address" . "\t". "eduction"."\t"."Organisation" . "\t". "Paid Status" . "\t";    
$setData = '';  

while ($rec = mysqli_fetch_row($setRec)) {  
    $rowData = '';  
    foreach ($rec as $value) {  
        $value = '"' . $value . '"' . "\t";  
        $rowData .= $value;  
    }  
    $setData .= trim($rowData) . "\n";  
}    
header("Content-type: application/octet-stream");  
header("Content-Disposition: attachment; filename= file_name.xls");  
header("Pragma: no-cache");  
header("Expires: 0");  
echo $header_name ."\t\t\t\t\t\t\t\n". $Event ."\t\t\t". $date ."\n". ucwords($columnHeader) . "\n" . $setData . "\n";  

1 个答案:

答案 0 :(得分:2)

首先...

相反,只需使用password_hashpassword_verify,并且进行自己的加密(散列)是一个坏主意。也不建议在没有适当安全知识的情况下进行用户登录系统。

但是,为了争辩(由于准备好的语句,这不起作用):

public static function make($string, $salt = ''){   
    if(empty($salt)) $salt = self::salt(rand(10,20)); //if you do this make sure the field is big enaugh
    return hash('sha256', $string . $salt).$salt; //add salt to end of password
}

public static function salt($length){
    return openssl_random_pseudo_bytes($length);
}

public static function authenticate($username, $password)
{

    //prepare your queries!!!! (see below)
    $sql = 'SELECT * FROM users WHERE email = ? AND status = 1'; //do not look up the password
    /*
       other DB code here
    */
    $found = self::read($sql, PDO::FETCH_CLASS, __CLASS__);

    if($found){ //should check for only 1 row returned as usernames should be unique index in the DB
        $row_pass = substr($row['password'], 0, 64); //pull password from DB
        $row_salt = substr($row['password'], 64); //pull salt from password

         //security compare hashes, in a safe way
        if(hash_equals($row_pass,self::make($password, $row_salt))){
            echo '<div class="alert alert-success text-center">
                      <strong>Found</strong>
                   </div>';
        }else {
            echo '<div class="alert alert-danger text-center">
                      <strong>Not Found</strong>
                   </div>';
        }
}

请参阅http://php.net/manual/en/function.hash-equals.php

一些笔记

  • 您的盐是空的$encpassword = Hash::make($password);
  • 我不知道您如何访问数据库,因此我只将$row放在其中。
  • 将哈希字段的排序规则更改为UTF8-bin或UTF8二进制,然后在搜索时区分大小写(可选)。
  • 由于上述原因(其他原因),请不要通过密码进行查找。不可能有2个相似的哈希,只是大小写不同。在这种情况下,一个用户可以以另一个用户身份登录。
  • 准备查询。

SQLInjection 如果我通过(对您的方法进行身份验证)

  $username = "' OR 1 LIMIT 1 --";

我会通过此查询(这是最常见的攻击类型之一)来绕过您的登录

$sql = "SELECT * FROM users WHERE email = '' OR 1 LIMIT 1 --' AND password = '".$encpassword."' AND status = 1";

--是SQL中注释的开始,因此之后没有任何关系,OR 1始终为真。哪一个(有限制,您甚至不检查仅一个返回行)都会(每次)返回1行,并以$found绕过登录true。不创建自己的登录系统的众多原因之一。

换句话说,无论您多么难以设置密码,现在我都可以使用LIMIT和OFFSET以所需的任何人身份登录到您的网站。显然应该避免一些事情。

另一种方法是将盐单独保存并从表中检索出来。但是,没有关于您最初如何设置和保存密码的代码。所以我就这样走了。另外,我将不深入讨论如何正确准备查询,有很多有关如何执行查询的示例,并且由于缺少有关如何使用数据库的代码,因此没有用。

正如我在评论中所说

  

salt的目的不仅是减少哈希的可猜测性,而且还可以防止来自字典列表和彩虹表(预先完成的哈希)的攻击。如果知道这一点,例如攻击者控制了数据库,那么它仍然使他们的任务变得复杂,因为他们必须为每个密码重做彩虹表。他们将遭受暴力或字典攻击

加盐的想法是为每个密码赋予不同的密码,然后攻击者无法使用庞大的已编译哈希表(彩虹表)数据库来获取密码。通过使该词不是一个明智的词,还会使字典攻击(从站点外部)变得复杂。

在使用彩虹表的情况下,即使攻击者知道了盐也没有帮助(他们需要为每个密码重新编译彩虹表中的所有哈希,这时攻击者会更好使用以下两种方法之一)。在字典表的情况下,它们必须以完全相同的方式包含盐,并且在蛮力的情况下(即使他们有盐也可能不知道)。即使他们都知道这两个方面,但如果您从不加盐,那也不会比他们更好。更糟糕的是,除非它是有针对性的攻击,否则它实际上消除了彩虹表。正如我所说的,即使在这种情况下,当他们重做彩虹桌时,他们也可以蛮力地将它撞上。

因此,上面的观点是,盐的安全性并非来自攻击者是否知道它。因此,将其存储在数据库中是安全的,因为如果攻击者可以获取数据库,则他们可能仍然拥有您的服务器,并且您会遇到更大的问题。而且它无济于事,因为在最坏的情况下他们可以将其强行使用,但不使用彩虹表,即使已知,它也会使字典攻击变得复杂。

希望这一切都有道理。