密码散列SELECT(PHP)

时间:2015-08-04 17:15:02

标签: hash mysql salt

是否可以仅使用发布的密码从MySql DB中选择哈希和盐渍密码?如果是这样,怎么样?

如果我以这种方式散列密码:

    $password = "blabla";
    $hash = password_hash($password, PASSWORD_DEFAULT);
例如,

$hash$2y$10$8zzd3lj6oIPlBPnCxsU7nOmtsEFlKw/BdqTXyMgbuojjVpiEe4rVm,它将存储在数据库中。

在登录期间,如何仅针对哈希密码列进行检查,如果密码匹配,只检查表的列,仅将“blabla”作为数据?

3 个答案:

答案 0 :(得分:0)

我认为您的意思是如何从数据库中选择哈希和盐渍密码,然后使用明文密码进行验证?如果是这样,这里是如何使用bcrypt。

请注意,这需要PHP 5> = 5.5.0。

另外,我建议使用scrypt而不是bcrypt,但你必须手动安装scrypt。

SQL的东西

CREATE DATABASE `example`;
USE `example`;
CREATE TABLE `users` (
    `id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    `username` VARCHAR(16),
    `password` VARCHAR(255)
);

哈希类(classes / Hash.class.php)

<?php
class Hash
{
    public static function make($string)
    {
        $options = array('cost' => 11);
        return password_hash($string, PASSWORD_BCRYPT, $options)
    }

    public static function check($password, $hash)
    {
        return password_verify($password, $hash);
    }
}

数据库类(classes / DB.class.php)

<?php
class DB
{
    private $dbhost = '127.0.0.1';
    private $dbname = 'example';
    private $dbuser = 'root';
    private $dbpass = 'pass';

    public function Connect()
    {
        return new PDO('mysql:host=' . $this->dbhost . ';dbname=' . $this->dbname, $this->dbuser, $this->pass);
    }
}

用户类(classes / User.class.php)

<?php
require_once('DB.class.php');
require_once('Hash.class.php');

class User
{
    private $db;

    public function __construct()
    {
        $this->db = new DB();
        $this->db = $this->db->Connect();
    }

    public function find($username)
    {
        $st = $this->db->prepare('SELECT * FROM `users` WHERE `username` = :username LIMIT 1');
        $st->bindParam(':username', $username, PDO::PARAM_STR);
        $st->execute();

        if($st->rowCount())
        {
            return $st->fetch(PDO::FETCH_ASSOC);
        }

        return false;
    }

    public function create($username, $password)
    {
        $password = Hash::make($password);

        $st = $this->db->prepare('INSERT INTO `users` (`username`, `password`) VALUES (:username, :password)');
        $st->bindParam(':username', $username, PDO::PARAM_STR);
        $st->bindParam(':password', $password, PDO::PARAM_STR);
        $st->execute();
    }

    public function verify($username, $password)
    {
        $user = $this->find($username);

        if($user)
        {
            if(Hash::check($password, $user['password']))
            {
                $_SESSION['isLoggedIn'] = true;
                return true;
            }
        }

        return false;
    }

    public function isLoggedIn()
    {
        if(isset($_SESSION['isLoggedIn']))
        {
            return true;
        }

        return false;
    }
}

注册(register.php)

<?php
require_once('classes/User.class.php');

$user = new User();

if($user->isLoggedIn())
{
    header('Location: index.php');
    die();
}

if($_SERVER['REQUEST_METHOD'] == 'POST')
{
    $username = $_POST['username'];
    $password = $_POST['password'];

    // Check if username and password exist
    if(!isset($username) || !isset($password))
    {
        die('Username and password required');
    }

    // Check if values are not empty
    if(empty($username) || empty($password))
    {
        die('Blank fields not allowed');
    }


    // Check if username length is in between 4 and 16
    if(strlen($username) < 4 && strlen($username) > 16)
    {
        die('Username must be in between 4 and 16 characters');
    }

    // Check if username is alphanumeric
    if(!ctype_alnum($username))
    {
        die('Username must be alphanumeric');
    }

    // Check password length
    if(strlen($password) < 8)
    {
        die('Passwords should be at least 8 characters long');
    }

    // Check if username exists
    $exists = $user->find($username);

    if($exists)
    {
        die('Username already in use');
    }

    // Create account
    $user->create($username, $password);
    header('Location: login.php');
    die();

}
?>

// HTML goes here

登录(login.php)

<?php
require_once('classes/User.class.php');

$user = new User();

if($user->isLoggedIn())
{
    header('Location: index.php');
    die();
}

if($_SERVER['REQUEST_METHOD'] == 'POST')
{
    $username = $_POST['username'];
    $password = $_POST['password'];

    // Check if username and password exist
    if(!isset($username) || !isset($password))
    {
        die('Username and password required');
    }

    // Check if values are not empty
    if(empty($username) || empty($password))
    {
        die('Blank fields not allowed');
    }


    // Check if username length is in between 4 and 16
    if(strlen($username) < 4 && strlen($username) > 16)
    {
        die('Username must be in between 4 and 16 characters');
    }

    // Check if username is alphanumeric
    if(!ctype_alnum($username))
    {
        die('Username must be alphanumeric');
    }

    // Check password length
    if(strlen($password) < 8)
    {
        die('Passwords should be at least 8 characters long');
    }

    // Try to login
    $verified = $user->verify($username, $password);

    if($verified)
    {
        header('Location: index.php');
        die();
    } else {
        die('Invalid username/password');
    }
}
?>

// HTML goes here

退出(logout.php)

<?php
require_once('classes/User.class.php');

$user = new User();

if($user->isLoggedIn())
{
    unset($_SESSION['isLoggedIn']);
}

header('Location: login.php');
die();

索引(index.php)

<?php
require_once('classes/User.class.php');

if(!$user->isLoggedIn())
{
    header('Location: login.php');
    die();
}
?>

<!DOCTYPE html>

<html lang="en">

<head>

    <title>Welcome</title>

</head>

<body>

    <h1>Menu</h1>
    <ul>
        <li><a href="logout.php">Logout?</a></li>
    </ul>

</body>

</html>

答案 1 :(得分:0)

  

在登录期间,如何仅针对哈希密码列进行检查,如果密码匹配,只检查表的列,仅将“blabla”作为数据?

你做不到。密码存储旨在使许多操作无法进行。如果要在不使用用户名或其他密钥的情况下查找密码匹配项,则需要在每个密码上调用password_verify,直到获得匹配为止。按设计,这将非常缓慢。

作为密码不需要是唯一的,您可能有一个匹配许多条目的密码。

我的猜测是,这是一个坏主意而不是你想要的。

答案 2 :(得分:0)

使用数据库查询无法搜索正确的salted和哈希密码。您必须通过用户名/电子邮件/ ...搜索哈希值,然后您可以使用找到的哈希验证输入的密码。

1)首先查询存储的哈希

SELECT passwordhash FROM users WHERE email = ?

2)使用找到的哈希

验证输入的密码
$isPasswordCorrect = password_verify($password, $existingHashFromDb);

正是盐使搜索变得不可能,必须从存储的哈希中提取才能验证密码。这样的查询必须读取每个哈希,提取其盐并进行散列。因为哈希函数非常慢(故意),所以查询需要的时间太长而无法执行。