如果我有一个用于登录系统的PHP脚本:
$user = $_POST['user_name'];
$pass = md5($_POST['user_pass']);
require_once("connection_file.php");
$sql = "SELECT * FROM login_table WHERE user_n = :us AND user_p = :password";
$stmt = $conn->prepare($sql);
$stmt->bindValue(':us', $user, PDO::PARAM_STR);
$stmt->bindValue(':password', $pass, PDO::PARAM_STR);
$stmt->execute();
$result = $stmt->fetchAll();
if($result)
{
//echo $msg = "user exist";
if(session_status() == PHP_SESSION_NONE)
{
session_start();
foreach($result as $row)
{
$hash = password_hash($row['user_pass'], PASSWORD_BCRYPT);
if(password_verify($row['user_pass'], $hash))
{
$_SESSION['userid'] = $row['user_id'];
$_SESSION['role'] = $row['user_role'];
header("Location: homepage.php");
}
}
}
}
else
{
$msg = "Wrong credentials";
header("Location: login_page.php");
}
如您所见,我已将密码保存在数据库MD5
中,并且我使用$pass = md5($_POST['user_pass']);
来验证用户输入的文本是否等于MD5
哈希。< / p>
现在我的问题是我应该使用password_hash
和password_verify
,因为我在这个脚本中使用了吗?或者使用MD5
就足够了?
我的第二个问题是我可以使用哈希字符串结果在数据库中保存密码,还是可以使用md5密码?
答案 0 :(得分:3)
是的,您应该立即迁移到新API并且永远不再使用MD5用于此目的。
如果您未使用password_hash()
/ password_verify()
并希望migrate your code to a more secure method, seamlessly:
legacy_password
(或等效的)。legacy_password
设置为TRUE
)。当用户尝试登录时,首先检查是否设置了legacy_password
标志。如果是,首先使用MD5预先哈希其密码,然后使用此预先设置的值代替其密码。然后,重新计算 bcrypt哈希并将新哈希存储在数据库中,从而禁用进程中的legacy_password
标志。 PHP 7+中一个非常宽松的例子如下:
/**
* This is example code. Please feel free to use it for reference but don't just copy/paste it.
*
* @param string $username Unsafe user-supplied data: The username
* @param string $password Unsafe user-supplied data: The password
* @return int The primary key for that user account
* @throws InvalidUserCredentialsException
*/
public function authenticate(string $username, string $password): int
{
// Database lookup
$stmt = $this->db->prepare("SELECT userid, passwordhash, legacy_password FROM user_accounts WHERE username = ?");
$stmt->execute([$username]);
$stored = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$stored) {
// No such user, throw an exception
throw new InvalidUserCredentialsException();
}
if ($stored['legacy_password']) {
// This is the legacy password upgrade code
if (password_verify(md5($password), $stored['passwordhash'])) {
$newhash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $this->db->prepare("UPDATE user_accounts SET passwordhash = ?, legacy_password = FALSE WHERE userid = ?");
$stmt->execute([$newhash, $stored['userid']]);
// Return the user ID (integer)
return $stored['userid'];
}
} elseif (password_verify($password, $stored['passwordhash'])) {
// This is the general purpose upgrade code e.g. if a future version of PHP upgrades to Argon2
if (password_needs_rehash($stored['passwordhash'], PASSWORD_DEFAULT)) {
$newhash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $this->db->prepare("UPDATE user_accounts SET passwordhash = ? WHERE userid = ?");
$stmt->execute([$newhash, $stored['userid']]);
}
// Return the user ID (integer)
return $stored['userid'];
}
// When all else fails, throw an exception
throw new InvalidUserCredentialsException();
}
用法:
try {
$userid = $this->authenticate($username, $password);
// Update the session state
// Redirect to the post-authentication landing page
} catch (InvalidUserCredentialsException $e) {
// Log the failure
// Redirect to the login form
}
主动升级旧版哈希是对机会主义策略的安全胜利(当用户登录时重新散列,但在数据库中为不活动的用户留下不安全的哈希):采用主动策略,如果您的服务器在每个人登录之前受到攻击再次,他们的密码已经使用了可接受的算法(bcrypt,在示例代码中)。
以上示例代码也可以Bcrypt-SHA-384风格。
此外,这与encryption无关。