LeonLatex Posted September 18, 2023 Share Posted September 18, 2023 I was setting up a login system that was working till I want it to hash the password. I paste both my user table in the database and login.php. I can't find what's wrong, can you? <?php // Inkluder databasekobling og nødvendige funksjoner include_once $_SERVER['DOCUMENT_ROOT'] . '/includes/db.php'; if ($_SERVER['REQUEST_METHOD'] === 'POST') { // Håndter innloggingsskjemaet som er sendt inn. $email = $_POST['email']; $password = $_POST['password']; // Hent brukerens hashed passord fra databasen basert på e-postadressen $sql = "SELECT * FROM users WHERE email = :email"; $stmt = $pdo->prepare($sql); $stmt->bindParam(':email', $email); $stmt->execute(); $user = $stmt->fetch(); if ($user && password_verify($password, $user['password_hash'])) { // Passordet er gyldig, opprett en brukersesjon session_start(); $_SESSION['user_id'] = $user['user_id']; $_SESSION['user_role'] = $user['role']; // Gi tilbakemelding til brukeren om vellykket innlogging header('Location: dashboard.php'); // Omdiriger til en beskyttet side exit(); } else { // Feil passord, gi tilbakemelding om innloggingsfeil $error_message = "Feil e-postadresse eller passord."; } } ?> <!DOCTYPE html> <html lang="en"> <head> <!-- ... Legg til nødvendige meta-informasjon og stiler ... --> </head> <body> <h2>Logg inn</h2> <?php if (isset($error_message)): ?> <p><?php echo $error_message; ?></p> <?php endif; ?> <form method="post" action="login.php"> <label for="email">E-postadresse:</label> <input type="email" id="email" name="email" required> <label for="password">Passord:</label> <input type="password" id="password" name="password" required> <input type="submit" value="Logg inn"> </form> </body> </html> /* Navicat MySQL Data Transfer SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for users -- ---------------------------- DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `user_id` int(11) NOT NULL AUTO_INCREMENT, `first_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `middle_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `last_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `city` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `postal_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `birthday` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `country` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `county` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `municipality` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `sex` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `display_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `password_hash` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `confirm_password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `confirm_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `role` enum('user','moderator','administrator') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'user', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`user_id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of users -- ---------------------------- SET FOREIGN_KEY_CHECKS = 1; Quote Link to comment Share on other sites More sharing options...
requinix Posted September 18, 2023 Share Posted September 18, 2023 And what about the code that inserts the user records - specifically, that deals with setting the password? Because that part and this part need to work together. Quote Link to comment Share on other sites More sharing options...
LeonLatex Posted September 18, 2023 Author Share Posted September 18, 2023 Of course Requinix. Here is that part: <?php // Inkluder skriptet for databasekobling. include_once $_SERVER['DOCUMENT_ROOT'] . '/includes/db.php'; if ($_SERVER['REQUEST_METHOD'] === 'POST') { // Hent brukerregistreringsdata fra skjemaet. $first_name = $_POST['first_name']; $last_name = $_POST['last_name']; $email = $_POST['email']; $password = $_POST['password']; // Dette skal være passordet i klartekst som brukeren oppgir. // Hash brukerens passord før det lagres i databasen. $hashed_password = password_hash($password, PASSWORD_DEFAULT); // SQL-spørring for å sette inn brukeren i databasen. $sql = "INSERT INTO users (first_name, last_name, email, password_hash) VALUES (:first_name, :last_name, :email, :password_hash)"; // Forbered og utfør SQL-setningen. $stmt = $pdo->prepare($sql); $stmt->bindParam(':first_name', $first_name); $stmt->bindParam(':last_name', $last_name); $stmt->bindParam(':email', $email); $stmt->bindParam(':password_hash', $hashed_password); if ($stmt->execute()) { // Brukerregistrering vellykket. echo "Bruker registrert vellykket!"; // Du kan omdirigere brukeren til en påloggingsside eller vise en suksessmelding. } else { // Brukerregistrering mislyktes. echo "Brukerregistrering mislyktes. Prøv igjen senere."; } } ?> Quote Link to comment Share on other sites More sharing options...
requinix Posted September 18, 2023 Share Posted September 18, 2023 Seems fine. What's the problem you're trying to solve? You didn't mention that. Can I assume it's not that you're unable to log in with a user that was created before you added the hashing? Quote Link to comment Share on other sites More sharing options...
LeonLatex Posted September 18, 2023 Author Share Posted September 18, 2023 Sorry again. There's a little busy here today (every day). The problem is that i get the $error_message = "Feil e-postadresse eller passord."; ...and I dont know why. It has been running fine on another site, but not on this site I am dealing with now. The only difference is the database. I cant find any there. Can you ? Quote Link to comment Share on other sites More sharing options...
requinix Posted September 18, 2023 Share Posted September 18, 2023 Have you taken the email address you're trying to sign in with, queried the database manually to make sure there is a corresponding record, and checked that the password_hash stored in there looks like a hash? Quote Link to comment Share on other sites More sharing options...
LeonLatex Posted September 18, 2023 Author Share Posted September 18, 2023 (edited) One of the first things I did was go through the password and username. I checked the db-connection with this one too: <?php $servername = "***.****.********.no"; $username = "*****_*****"; $password = "************"; $database = "*****_*****"; try { $pdo = new PDO("mysql:host=$servername;dbname=$database", $username, $password); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); echo "Connection successful!"; } catch(PDOException $e) { echo "Error connecting: " . $e->getMessage(); } ?> Then I checked if the hashed password was corect and matched. As a precaution, I set up a new hashed password string using this code, and paste it into the database table users: <?php $password = '******'; // Replace this with the actual password $hashed_password = password_hash($password, PASSWORD_DEFAULT); echo $hashed_password; // This will output the hashed version of the password ?> Edited September 18, 2023 by LeonLatex Quote Link to comment Share on other sites More sharing options...
Phi11W Posted September 18, 2023 Share Posted September 18, 2023 I don't think you need password_verify() at all here. When saving the password, hash the entered, plaintext, password and store the hashed value. When logging in, hash the entered, plaintext, password and compare that to what's in the database table. Saving password (as you currently have): $hashed_password = password_hash($password, PASSWORD_DEFAULT); . . . $sql = "INSERT INTO users (first_name, last_name, email, password_hash) VALUES (:first_name, :last_name, :email, :password_hash)"; . . . $stmt->bindParam(':password_hash', $hashed_password); Logging in: $email = $_POST['email']; $password = $_POST['password']; $hashed_password = password_hash( $password, PASSWORD_DEFAULT ); $sql = "SELECT a, b, c FROM users WHERE email = :email and password_hash = :hashed_password"; . . . $stmt = $pdo->prepare($sql); $stmt->bindParam(':email', $email); $stmt->bindParam(':hashed_password', $hashed_password ); $stmt->execute(); $user = $stmt->fetch(); If you get no rows back, either the username or entered password is wrong. Regards, Phill W. Quote Link to comment Share on other sites More sharing options...
mac_gyver Posted September 18, 2023 Share Posted September 18, 2023 @Phi11W, password_hash() produces a different hash for the same input, every time it is called, because it generates a random salt each time it is called. this is precisely why password_verify() must be used. it takes the algorithm, cost and salt from the existing hashed value, hashes the submitted password using these values, then compares the resulting hash of the submitted value with the existing hashed value. Quote Link to comment Share on other sites More sharing options...
mac_gyver Posted September 18, 2023 Share Posted September 18, 2023 (edited) @LeonLatex, because you haven't posted the registration and login forms (you could have a typo between the field names and the php code), aren't trimming and validating the inputs before using them (any of the inputs could be empty or contain additional characters due to typo mistakes or something javascript is adding) , and have lumped together the test for the user row and password_verfy() (you currently have no single place to test if a user row was not found, then if the password_hash() didn't match), no one here can determine why this isn't working. you could also be overwriting the $password variable if your actual code is requiring the database connection code right before executing the query. edit: here's another couple of problems with the form processing code you have posted. you should only store the user_id in a session variable, then query on each page request to get any other user data, such as permissions/roles, so that any change in these other values will take effect on the very next page request after they have been changed. the redirect should be to the exact same URL of the current page to cause a get request to be registered in the browser for that URL. by redirecting to a different URL, anyone can walk up to a computer that was used to register/login using this code and browse back to the form page, which will cause the browser to resubmit the form data, where you can use the browser's developer console network tab to see what the submitted form data is. Edited September 18, 2023 by mac_gyver Quote Link to comment Share on other sites More sharing options...
mac_gyver Posted September 18, 2023 Share Posted September 18, 2023 here's even more issues - the email column should be defined as a unique index. this will prevent duplicate email addresses, which could be the cause of the current symptom. then, in the registration code, the exception error handling for the INSERT query would test for a duplicate index error number, and setup a message that the email address is already in use. when you make the database connection, you need to set the character set to match your database table's character set, so that no character conversion occurs over the connection. this is doubly important when using emulated prepared queries, which you are using but which should be avoided whenever possible, so that sql special characters in a value won't be able to break the sql query syntax. when you make the database connection, you should set the emulated prepared query setting to false, i.e. you want to use true prepared queries whenever possible. when you make the database connection, you should set the default fetch mode to assoc, so that you only get the type of fetched data that you want and so that you don't need to specify the fetch mode in each fetch statement. Quote Link to comment Share on other sites More sharing options...
LeonLatex Posted September 18, 2023 Author Share Posted September 18, 2023 @mac_gyver, If you look in bottom of my first posting you find my login form. I dont have a registration form yet because so early in the development process i manually put the testing user accounts in mysql manually. I dont have time to use more time on this now, so i will start develop another system, and this time with email confirmation and a confirmation code. Is less use of time to put a new one together than looking for errors in this login system. I dont think there is only one error. The system has going through many changes through the last year, so it's time to let the old one rest. Any way, thanks for using time for trying to help 😃 Quote Link to comment Share on other sites More sharing options...
Strider64 Posted September 18, 2023 Share Posted September 18, 2023 3 minutes ago, LeonLatex said: @mac_gyver, If you look in bottom of my first posting you find my login form. I dont have a registration form yet because so early in the development process i manually put the testing user accounts in mysql manually. I dont have time to use more time on this now, so i will start develop another system, and this time with email confirmation and a confirmation code. Is less use of time to put a new one together than looking for errors in this login system. I dont think there is only one error. The system has going through many changes through the last year, so it's time to let the old one rest. Any way, thanks for using time for trying to help 😃 You don't need a registration form/page as all you have to do is hash your password that you want to use. That's what I do when I develop my website(s). Quote Link to comment Share on other sites More sharing options...
maxxd Posted September 19, 2023 Share Posted September 19, 2023 You are hashing the passwords using the password_hash function before you manually enter your test user accounts, right? Quote Link to comment Share on other sites More sharing options...
LeonLatex Posted September 19, 2023 Author Share Posted September 19, 2023 @maxxd@Strider64 Of course, I do. I don't save a plain-text password in the database Have you read through the thread, you would see that your question is so unnecessary, or am I wrong? The password is saved to the "password_hash" column in db, and id hashed with this: <?php $password = '******'; // Replace the stars with the actual password $hashed_password = password_hash($password, PASSWORD_DEFAULT); echo $hashed_password; // This will output the hashed version of the password for you. Just copy and paste ?> Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.