是否可以仅使用发布的密码从MySql DB中选择哈希和盐渍密码?如果是这样,怎么样?
如果我以这种方式散列密码:
$password = "blabla";
$hash = password_hash($password, PASSWORD_DEFAULT);
例如, $hash
将$2y$10$8zzd3lj6oIPlBPnCxsU7nOmtsEFlKw/BdqTXyMgbuojjVpiEe4rVm
,它将存储在数据库中。
在登录期间,如何仅针对哈希密码列进行检查,如果密码匹配,只检查表的列,仅将“blabla”作为数据?
答案 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);
正是盐使搜索变得不可能,必须从存储的哈希中提取才能验证密码。这样的查询必须读取每个哈希,提取其盐并进行散列。因为哈希函数非常慢(故意),所以查询需要的时间太长而无法执行。