во-первых, я старался изо всех сил, чтобы найти окончательный ответ на этот вопрос. Во-вторых, мой код работает, но я хочу подтвердить, что я делаю это эффективно и не оставляю себя открытым для нарушений безопасности.
Во-первых, я использую PHP password_hash при добавлении пользователя в таблицу администратора;
$stmt = $dbh->prepare("INSERT INTO admin (username, password) VALUES (:username, :password)");
$stmt->bindParam(':username', $username);
$stmt->bindParam(':password', $password);
$password = password_hash('password', PASSWORD_DEFAULT);
Во-вторых, когда пользователь пытается войти в систему, я извлекаю пользователей из таблицы admin, сопоставляя ТОЛЬКО имя пользователя, так как я не мог найти способ проверить хэш во время запроса (это часть, в которой я не уверен, если есть лучший way), а также определить переменную $ password из входных данных POST;
$stmt = $dbh->prepare("SELECT * FROM admin WHERE username = :username");
$stmt->bindParam(':username', $username);
$username = $_POST['username'];
// define $password for use in password verify
$password = $_POST['password'];
В-третьих, если в результате запроса есть результат, я запускаю password_verify на вводе пользователя, чтобы проверить совпадение, а затем выполняю ответвление в зависимости от true или false.
if ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
if (password_verify($password, $row['password'])) {
session_start();
foreach ($row as $user) {
$_SESSION['user'] = $row['id'];
}
} else {
$errors = true;
}
header('location: leads.php');
}
else {
$errors = true;
}
Я знаю, что есть много разных способов хешировать / защищать пароли, но я решил пойти с помощью встроенных функций password_hash, мой вопрос: правильно ли я это сделал / есть ли лучший способ?
Заранее спасибо.
По сути, ваш код выглядит вполне нормально, кроме уже упомянутых вещей. Когда вы просите об улучшениях, особенно связанных с производительностью, мы начинаем:
username
Если в вашей таблице много записей, удалите индекс из username
добавьте новый столбец с именем hash
с индексом и переписать вставку и выберите как это:
INSERT INTO admin (username, password, hash) VALUES (:username, :password, crc32(username))
SELECT * FROM admin WHERE username = :username AND hash=crc32(:username)
Я предполагаю, что вы используете MySQL, поэтому добавление LIMIT 1
на ваш запрос помогает оптимизатор и прекращает поиск после того, как строка найдена.
Избегать foreach
-loop также возможно, если вы работаете только с одной строкой.
КСТАТИ: header('location: leads.php');
должен прочесть header('Location: leads.php');
и использование абсолютных путей делает вещи более устойчивыми.
Других решений пока нет …