我在这里看到了类似的问题,但我认为答案不适用于我,如果适用,我很抱歉。
下面是包含两个过程的代码片段:
注意:登录和注册在没有哈希元素的情况下运行良好
if (isset($_POST['username']) && ($_POST['password'])) {
$username = trim($_POST['username']);
$username = strtolower($username);
$password = trim($_POST['password']);
$salt = hash('md5', "$username");
$password = hash('sha256', "$password"."$salt");
$stmt = $dbh->prepare("SELECT `id` FROM `1_users` WHERE username=? AND password=? LIMIT 1");
$stmt->bindValue(1, $username, PDO::PARAM_STR);
$stmt->bindValue(2, $password, PDO::PARAM_STR);
$stmt->execute();
if ($stmt->rowCount()) {
// Match
$results = $stmt->fetch(PDO::FETCH_ASSOC);
$_SESSION['id'] = $results['id'];
$_SESSION['logged_in'] = true;
$_SESSION['ip'] = hash('sha1', "{$_SERVER['REMOTE_ADDR']}");
header ("location: account.php");
}
else {
$error = 'Invalid username/password!';
}
}
if (isset($_POST['register'])) {
// check for all fields..
if ((empty($_POST['r_username'])) || (empty($_POST['r_password'])) || (empty($_POST['re_password'])) || (empty($_POST['email']))) {
$r_error = 'One of the fields was empty.';
}
$stmt = $dbh->prepare("SELECT `username` FROM `1_members` WHERE `username`=? LIMIT 1");
$username = strtolower($_POST['r_username']);
$username = trim($username);
$stmt->bindValue(1, $username, PDO::PARAM_STR);
$stmt->execute();
$row = $stmt->rowCount();
if ($row) {
$r_error = 'that username is already in use';
}
else if (($_POST['r_password']) !== ($_POST['re_password'])) {
$r_error = 'The passwords did not match.';
}
else if (strlen($_POST['r_username']) <= '3') {
$r_error = 'username too short - needs to be 4 more charicters.';
}
else if (strlen($_POST['r_password']) <='5'){
$r_error = 'password not long enough, please make it 6-255 charicters or more.';
}
else {
// woohoo lets make the account
$password = trim($_POST['r_password']);
$salt = hash('md5', "$username");
$password = hash('sha256', "$password"."$salt");
$email = trim($_POST['email']);
$stmt = $dbh->prepare("INSERT INTO `1_members` (`username`, `password`, `email`) VALUES(?,?,?)");
$stmt->bindValue(1,$username,PDO::PARAM_STR);
$stmt->bindValue(2,$password,PDO::PARAM_STR);
$stmt->bindValue(3,$email,PDO::PARAM_STR);
$stmt->execute();
$_SESSION['id'] = $dbh->lastInsertId();
$_SESSION['logged_in'] = true;
$_SESSION['ip'] = hash('sha1', "{$_SERVER['REMOTE_ADDR']}");
if ($_SESSION['active_cart']) {
header ("location: cart.php");
}
else {
header ("location: account.php");
}
}
}
在将哈希添加到密码之前,它正常工作,我不确定我的问题是什么。
调试:
username: admin1
password: admin1
登录过程将密码转换为:927364bb72cee168bd52c45a5d131b5923e2926eb6e8f0f46d6d7e5765cc3401
注册过程将密码创建为:927364bb72cee168bd52c45a5d131b5923e2926eb6e8f0f46d6d7e5765cc3401
他们匹配,出了什么问题?
此外,如果我在这里有错误的想法,或者如果我忽略了重要的安全步骤,请你建议更好的方法。
此外,我不太担心电子邮件验证,我完全知道有很多预制的片段可用于验证电子邮件,我稍后会了解。
任何CC都非常受欢迎。
编辑:脚本返回"无效的用户名/密码组合"
我怀疑哈希密码的数据库字段太小,该字段必须能够存储64个字符。
即使你能解决这个问题,你也有一个不安全的密码存储方案(SHA256对哈希密码来说太快了)。看看PHP函数password_hash(),它将生成一个BCrypt哈希,并负责生成一个安全的salt。盐将是生成的62个字符串的一部分,因此不需要单独存储盐。还有一个针对旧PHP版本的兼容性包。
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
这也意味着,您不能直接在SQL语句中验证密码,而是从数据库中读取哈希(按用户名),然后使用此哈希调用password_verify()。
在SELECT查询上执行时,PDOStatement::rowCount()可能不会返回"1"。看看这里:
http://www.php.net/manual/en/pdostatement.rowcount.php
(特别是示例2)