I have simple reset password structure for users to update their existing passwords if lost. The user goes to a link where they enter their email, a token is created and stored in a designated table for the user with the forgotten password. A email is sent to the user with a link that has the token attached, when they hit that link it takes them to a page to reset their password. If the token stored in the db matches the one in the $_GET, I allow them to reset their password. simple.
The problem is I can't update their specific row in the db. I am trying to identify them by checking their email they entered against their email in the db. I am able to update the WHOLE tables password row, but when specify one user it fails.
if(isset($_POST['sub_settings'])){
$query = "SELECT * FROM `Password_Reset` WHERE `token` = '".$token."' AND `email` = '".$user_email."'";
$request = mysql_query($query,$connection) or die(mysql_error());
$result = mysql_fetch_array($request);
$token = $result['token'];
$alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcedfghijklmnopqrstuvwxyz1234567890";
$rand = str_shuffle($alpha);
$salt = substr($rand,0,40);
$hashed_password = sha1($salt . $_POST['password']);
$user_email = $result['email'];
if($_GET['token'] == $token) {
header("Location: index.php");
exit;
}else{
if(empty($_POST['Password'])) {
$valid = false;
$error_msgs[] = 'Whoops! You must enter a password.';
}
if($_POST['Password'] != $_POST['passwordConfirm'] || empty($_POST['Password'])) {
$valid = false;
$error_msgs[] = "Your password entries didn't match...was there a typo?";
}
if($valid) {
$query = "UPDATE `Users` SET `encrypted_password` = '$hashed_password' WHERE `Email` = '$user_email'";
mysql_query($query,$connection);
}
}
}
Thanks so much in advance
Why don't you store the user id in the Password_Reset table and then update the user based on there id rather than trying to match there email.
Note that if you are trying to match the users email the email casing must match exactly with an '=' in the query. You could lowercase the email address but this is technically incorrect.
$query = "
SELECT *
FROM `Password_Reset`
WHERE `token` = '".$token."' AND LOWER(`email`) = LOWER('".$user_email."')
";
It looks like you've not capitalized $_POST['Password']
$hashed_password = sha1($salt . $_POST['password']);
Based on your other code, it should be:
$hashed_password = sha1($salt . $_POST['Password']);
Also in your SELECT, you have email and in your UPDATE you use Email. MySQL is case-sensitive by default on non-windows platforms.
It looks like you have $user_email in your first query but it's not set yet because you're setting it with the result of the first query. Unless you mean $_POST['user_email']?
It would be MUCH easier and more secure to use a user_id and only send the user a token if they are actually in your system (it appears you're sending everyone a token!)
Your token should be unique. It looks like it's completely random. A good way to make a token is to create a random string + something that uniquely identifies the user (such as their username or email) and then use MD5 or a similar function to hash it. It's reasonably secure and it identifies the user themselves so you can look them up by the token only.
if($_GET['token'] == $token) {
header("Location: index.php");
exit;
Should be != I suppose.
You need to check if the token is not equal to the token into db. Isn't it?
Related
So I just learned about storing passwords with MD5 hash and salt in PHP/MySQL. The method I'm using is md5(md5($row["id"].$password)), so the salt is an MD5 hash of the user's ID in my SQL table (which is an auto-incremented INT), which is concatenated to the inputted password string and then re-hashed.
The problem I'm encountering is that when I trying making a test account, and then logging in with the test account, the hash I generate on logging in isn't matching the hash I created when the account was created.
Login Code:
<?php
$login = mysqli_connect("hiding this info for obvious reasons");
if ($_POST["login"])
{
$email = $_POST["email"];
$password = $_POST["passsword"];
$query = "SELECT * FROM useraccs WHERE email='$email'";
if ($result = mysqli_fetch_array(mysqli_query($login,$query)))
{
$hashpass = md5(md5($result["id"]).$password);
if ($hashpass == $result["password"])
{
$errors = "Logged in succesfully.";
}
}
else
{
$error.= "E-mail/Password do not match anything in our database.";
}
}
?>
Register Code:
<?php
$login = mysqli_connect("hiding this info for obvious reasons");
if ($_POST["submit"])
{
$username = $_POST["username"];
$email = $_POST["email"];
$query = "INSERT INTO useraccs (username,email) values('$username','$email')";
mysqli_query($login,$query);
$query = "SELECT id FROM useraccs WHERE username='$username'";
$userid = mysqli_fetch_array(mysqli_query($login,$query))["id"];
$password = md5(md5($userid).$_POST["password"]);
$query = "UPDATE useraccs SET password='$password' WHERE username='$username'";
mysqli_query($login,$query);
}
?>
As you can see, the way I hash the password in both scenarios is identical, and I have done testing to confirm that I am getting the same value for the ID in both scenarios. I am truly stumped as to why I am not getting a match.
I'd like to mention I am very new to using MySQL/creating login systems, so if I've done anything blatantly wrong or have left out essential information, please let me know.
First of all, please see the warnings in the comments, your code is highly unsure.
Regarding the md5: You are using
mysqli_fetch_array(mysqli_query($login,$query))["id"];
This will always return an array. Be sure to get only the field.
Hey guys ive put together a basic user log in for a secure admin area and it seems to work great, if you enter a correct user/pass you get access, if you enter the wrong user pass, you get no access. However if you enter nothing in both fields you get access.
This is how it works.
Creating a user, a basic form POSTS to this php file.
<?php
$con = mysqli_connect(credentials are all good) or die(mysqli_error($con)) ;
$escapedUser = mysqli_real_escape_string($con, $_POST['user']);
$escapedPass = mysqli_real_escape_string($con, $_POST['pass']);
$some_str = md5(uniqid(mt_rand(), true));
$base_64str = base64_encode($some_str);
$modified_base64 = str_replace('+', '.', $base_64str);
$gensalt = substr($modified_base64, 0, 22);
$format_str = "$2y$10$"; // 2y for Blowfish and 10 times.
$salt = $format_str . $gensalt . "$";
$hashed_pass = crypt($escapedPass, $salt);
$query = "INSERT INTO `userpass` (`username`, `password`, `salt`) VALUES ('$escapedUser', '$hashed_pass', '$salt'); ";
if(isset($escapedUser) && isset($hashed_pass))
{
mysqli_query($con, $query);
header("Location: ausers.php");
exit();
}
Echo "Something went wrong!";
?>
The database appears to be storing these fine
We then log in with this code
<?php
$con = mysqli_connect(again credentials are fine) or die(mysqli_error($con)) ;
$escapedUser = mysqli_real_escape_string($con, $_POST['user']);
$escapedPass = mysqli_real_escape_string($con, $_POST['pass']);
$saltQuery = "select salt from userpass where username = '$escapedUser';";
$result = mysqli_query($con, $saltQuery);
$row = mysqli_fetch_assoc($result);
$salt = $row['salt'];
$hashed_pass = crypt($escapedPass, $salt);
if(isset($escapedUser) && isset($hashed_pass))
{
$userQuery = "SELECT * FROM userpass WHERE username='$escapedUser' AND password='$hashed_pass'";
$userpass = mysqli_query($con, $userQuery);
$count = mysqli_num_rows($userpass);
if($count == 1)
{
$_SESSION['username'] = $escapedUser;
header("location: aindex.php");
exit();
}
header("Location: alogin.htm");
exit();
}
Echo "Something went wrong!";
?>
So as i said, this seems to work fine for when any user pass combination is given whether access granted or denied however using no user and pass and pressing log in allows entry. Any ideas? THeres no blank rows in the database table.
Side question, is this salt/hash method correct, its my first attempt.
For your login code, your condition relies on an isset() test. You perform this test on $escapedUser and $hashed_pass. Both of these variables were actually assigned values earlier in the code! Once you assign a value to the variable, it will pass the isset() test, even if the value is an empty string. You might want to use an empty() check, perhaps on the original $_POST variables.
Moving on to the inner condition, which tests if the mysql query returns exactly 1 row of results. If there were truly no rows with empty values, then this condition would never pass because the query would return 0 rows. But it is passing. Two things to consider:
Notice that your registering code uses the same isset() test. Therefore it is very possible that someone used your registration form, submitted empty fields, and successfully registered a row with empty user and password fields. Have you explicitly queried your database for empty fields and actually come up with 0 results?
Your query uses SELECT *. Perhaps this is causing the query to return some sort of aggregate value (like a COUNT() or something that always has a result no matter what). Perhaps try explicitly defining the columns to return?
I cannot comment on your salt/hash method as I have no experience in that part. Hope you find this helpful!
In my opinion you need more than one level of checks in any form, whether it be registration, comments, login, etc. The way I prefer to go about it is a tiered approach. It may work better for you, but it's just an example.
By doing it this way, you ensure that your input will never be empty. Another issue I see with your login script is that you never compare the input with the database so how can you know if they entered the correct information? The only thing allowing them to login is that the query returned a record. This is also why they can login with a blank form.
<?php
$con = mysqli_connect(again credentials are fine) or die(mysqli_error($con)) ;
/* Ensures that form was submitted before any processing is done */
if (isset($_POST)) {
$User = $_POST['user']);
$Pass = $_POST['pass']);
if (!empty($User)) {
if (!empty($Pass)) {
$escapedUser = mysqli_real_escape_string($con, $User);
$escapedPass = mysqli_real_escape_string($con, $Pass);
/* you need to verify the password here, before adding the salt */
$saltQuery = "select salt from userpass where username = '$escapedUser'";
$result = mysqli_query($con, $saltQuery);
$row = mysqli_fetch_assoc($result);
$salt = $row['salt'];
$hashed_pass = crypt($escapedPass, $salt);
$userQuery = "SELECT * FROM userpass WHERE username='$escapedUser' AND password='$hashed_pass'";
/* you need to verify the username somewhere here */
$userpass = mysqli_query($con, $userQuery);
$count = mysqli_num_rows($userpass);
if($count == 1)
{
$_SESSION['username'] = $escapedUser;
header("location: aindex.php");
exit();
} else {
header("Location: alogin.htm");
exit();
}
} else {
echo "Please enter a password.";
}
} else {
echo "Please enter a username.";
}
} else {
echo "You have not entered any information.";
}
?>
I wonder whether someone could help me please.
I've been doing quite a bit of research on the 'Password Reset' process and from one of the tutorials I found, I've been able to put the following code together which provides this functionality.
Forgot Password
<?php
// Connect to MySQL
$c = mysql_connect("host", "user", "password");
mysql_select_db("database", $c);
// Was the form submitted?
if ($_POST["ForgotPasswordForm"])
{
// Harvest submitted e-mail address
$emailaddress = mysql_real_escape_string($_POST["emailaddress"]);
// Check to see if a user exists with this e-mail
$userExists = mysql_fetch_assoc(mysql_query("SELECT `emailaddress` FROM `userdetails` WHERE `emailaddress` = '$emailaddress'"));
if ($userExists["emailaddress"])
{
// Create a unique salt. This will never leave PHP unencrypted.
$salt = "KEY";
// Create the unique user password reset key
$password = md5($salt . $userExists["emailaddress"]);
// Create a url which we will direct them to reset their password
$pwrurl = "phpfile.php?q=" . $password;
// Mail them their key
$mailbody = "Dear user,\n\nIf this e-mail does not apply to you please ignore it. It appears that you have requested a password reset at our website \n\nTo reset your password, please click the link below. If you cannot click it, please paste it into your web browser's address bar.\n\n" . $pwrurl . "\n\nThanks,\nThe Administration";
mail($userExists["emailaddress"], "", $mailbody);
echo "Your password recovery key has been sent to your e-mail address.";
}
else
echo "No user with that e-mail address exists.";
}
?>
Reset Password
<?php
// Connect to MySQL
$c = mysql_connect("host", "user", "password");
mysql_select_db("database", $c);
// Was the form submitted?
if ($_POST["ResetPasswordForm"])
{
// Gather the post data
$emailaddress = mysql_real_escape_string($_POST["emailaddress"]);
$password = md5(mysql_real_escape_string($_POST["password"]));
$confirmpassword = md5(mysql_real_escape_string($_POST["confirmpassword"]));
$q = $_POST["q"];
$passwordhint = $_POST["passwordhint"];
// Use the same salt from the forgot_password.php file
$salt = "KEY";
// Generate the reset key
$resetkey = md5($salt . $emailaddress);
// Does the new reset key match the old one?
if ($resetkey == $q)
{
if ($password == $confirmpassword)
{
// Update the user's password
mysql_query("UPDATE `userdetails` SET `password` = '$password', `passwordhint` = '$passwordhint' WHERE `emailaddress` = '$emailaddress'");
echo "Your password has been successfully reset.";
}
else
echo "Your password's do not match.";
}
else
echo "Your password reset key is invalid.";
}
?>
I would now like to add a timed expiry of the link that I send out to the user. I've been looking at the post on the Stackoverflow community and many others, but I've not been able to find what I've been looking for.
I just wondered whether someone could perhaps help me out please and give me a little guidance on how I may accomplish this.
Many thanks.
Add a field to the users table with a timestamp when a password reset is requested.
When you check if the key matches check the timestamp to see how old it is.
Is this what you mean?
The way I do this is to store both the hash that you send the user and the timestamp from when it was generated in the users table.
When they visit the reset page check the hash they give against the one in the database rather than generating it again (doing it this way you can use truly random hashes as you don't have to remember how it was created in the first place) and also check the timestamp.
I have this user login process page. at this point the user has entered the info and all of this works BUT I cannot figure out how to pull the encrypted password out of the DB. I need to extract with the PASSWORD() function and do not know how. I know this is not the best way to do it but its what the assignment calls for. I have the problem section commented out I think thats what needs fixing.
//sets $query to read usnername and passowd from table
$query = "SELECT username,password,first_name,last_name FROM jubreyLogin WHERE username
= '$userName' AND password=password('$userPassword')";
$result = mysql_query($query,$db);
if(mysql_error())
{
echo $query;
echo mysql_error();
}
//reads data from table sets as an array
//checks to see if user is already registered
while($row=mysql_fetch_array($result))
{
if($userName == $row['username'] /*&& $userPassword == ($row['password'])*/)
{
$login = 'Y';
$welcome = "Welcome" . " " .$row['first_name']. " " .$row['last_name'];
$userName = $row['username'];
}
}
if ($login='Y')
{
setcookie('name',$welcome,time()+60*60*24*30);
setcookie('login',"Y",time()+60*60*24*30);
$_SESSION['username_login'] = $userName;
header('Location: welcome.php');
}
Here is the modified code that I should of posted first I need it to check user entered password in this case $userPassword with the encrypted password if its a match it will send the user into the next page of the site.
You don't need to see the password in clear text ( you can't even if you wanted to). As you are checking the record both on password and username you don't need the check in your if() statement. If there is any row found, that means the username/password combination was succesfful and the user can be deemed as logged in.
Edit:
The updated code doesn't really make any difference to the actual logic. The logic stays the same, you query the database with username AND encrypted password, if there is a match that means the user has the right to login, so you proceed with setting the cookies/session data and redirect. Although I do not really see the need for the login cookie and the welcome cookie cause you could simply put in both username, fname and lname in the session. If the session on the following pages contains username that means the user has logged in.
The code can go something like this:
//sets $query to read usnername and passowd from table
$query = "SELECT username,first_name,last_name FROM jubreyLogin WHERE username = '$userName' AND password=password('$userPassword')";
$result = mysql_query($query,$db);
if(mysql_error())
{
echo $query;
echo mysql_error();
}
// were any rows returned?
if(mysql_num_rows($result)){
list($userName, $firstName , $lastName) = mysql_fetch_row($result);
$welcome = "Welcome" . " " .$firstName. " " .$lastName;
setcookie('name',$welcome,time()+60*60*24*30);
setcookie('login',"Y",time()+60*60*24*30);
$_SESSION['username_login'] = $userName;
header('Location: welcome.php');
}
You should not be encrypting your passwords, you should be hashing them. Try using a library such as phpass to be on the safe side. What you will need to do is hash the passwords and store the hashed value in the database. When a user logs in, you will hash the password they provide and compare that with the hashed value in the database. If the hashes match, the password provided is correct. If not, you send an error to the user. You never need to be able to obtain the password in plain text in order to validate a user.
Also, make sure that you are either escaping your variables using mysql_real_escape_string() or prepared statements or your script will be vulnerable to SQL injection.
So recently I learned how to properly add a username and password to a database.
My database is usersys, and the table storing user information is called userdb. The table has two columns - username (primary), password.
The registration form works great, enters the users input into the database correctly and also checks to see whether the user's username is already in the database or not.
With that said, I am asking if anyone could help me create a login script. So far, this is what I have:
$username = $_POST['username'];
$password = $_POST['password'];
$displayname = $_POST['username'];
$displayname = strtolower($displayname);
$displayname = ucfirst($displayname);
echo "Your username: " . $displayname . "<br />";
mysql_connect("localhost", "root", "******") or die(mysql_error());
echo "Connected to MySQL<br />";
mysql_select_db("usersys") or die(mysql_error());
echo "Connected to Database <br />";
$lcusername = strtolower($username);
$esclcusername = mysql_real_escape_string($lcusername);
$escpassword = mysql_real_escape_string($password);
$result = mysql_query("SELECT * FROM userdb WHERE username='$esclcusername' AND password='$escpassword'") or die(mysql_error());
$row = mysql_fetch_array( $result );
$validateUser = $row['username'];
$validatePass = $row['password'];
The POST data is from the previous log in page. I want this script to check the table (userdb) and find the row for the username that the user entered from the previous form and verify that the password entered matches the username's password set in that row, in userdb table.
I also want some type of way to check whether or not if the username entered exists, to tell the user that the username entered does not exists if it can not be found in the table.
This is not a direct answer to this question but a GOOD value-add.
You should use MYSQL SHA1 function to encrypt the password before storing into the database.
$user = $_POST['userid'];
$pwd = $_POST['password'];
$insert_sql = "INSERT into USER(userid, password) VALUES($user, SHA1($pwd))";
$select_sql = "SELECT * FROM USER WHERE userid=$user AND password=SHA1($pwd))";
You can use sessions. Sessions are global variables that when set, stay with the user while he is browsing through the site.
Since you are learning PHP, try out this tutorial on the official website.
But what you would do in theory is when the username and password match, you set a session variable
$_SESSION["auth"] = true;
$_SESSION["user_id"] = $row["user_id"];
And then do a check to see if the user is authenticated.
One way to do it (DISCLAIMER: not necessarily best-practice):
$result = mysql_query("SELECT id FROM userdb WHERE username='$esclcusername' AND password='$escpassword'") or die(mysql_error());
$row = mysql_fetch_array( $result );
$id = (int)$row['id'];
if($id > 0) {
//log in the user
session_start();
$_SESSION['userId'] = $id;
$_SESSION['username'] = $displayname;
}
... and on pages that require authentication:
session_start();
if(!isset($_SESSION['userId'])) {
die('You need to be logged in!!!');
} else {
echo 'Welcome ' . $_SESSION['username'];
}
Read more about PHP sessions.
I like to use both $_SESSION and MYSQL Checks with any login POST. This should help get a few things started.
$username = mysql_real_escape_string($_POST[username]);
$password = strip_tags($_POST[password]);
$password = sha1($password);
if(isset($username) && isset($password) && !empty($username) && !empty($password))
{
$sql = mysql_query("SELECT * FROM users_column WHERE username = '$username' AND password = '$password'");
//Check the number of users against database
//with the given criteria. We're looking for 1 so
//adding > 0 (greater than zero does the trick).
$num_rows = mysql_num_rows($sql);
if($num_rows > 0){
//Lets grab and create a variable from the DB to register
//the user's session with.
$gid = mysql_query("SELECT * FROM users_column WHERE username = '$username' AND password = '$password'");
$row = mysql_fetch_assoc($gid);
$uid = $row[userid];
// This is where we register the session.
$_SESSION[valid_user] = $uid;
//Send the user to the member page. The userid is what the
//session include runs against.
header('Location: memberpage.php?userid='.$userid);
}
//If it doesn't check out -- throw an error.
else
{
echo 'Invalid Login Information';
}
}
NOTE: You would need to start the page file with session_start() and create a separate Session Check include stating with session_start() and then your progressions e.g. if($_SESSION[valid_user] != $userid) do something.
You could use a select statement to retreive from MySQL the password for the specified username. If you have an empty result set, then you do not have the username in the table.
If you need the user to be authenticated in more than one php page, then one choice whould be using sessions (http://www.php.net/manual/en/function.session-start.php).
Also, I think you should think about security, i.e. preventing SQL injection:
$variable = mysql_real_escape_string($_POST['variable'])
and avoiding to "die" (treating errors and returning user-friendly messages from the script).
I would also think about not storing passwords in your database. One way hashes with MD5 or SHA1 are a way of adding a layer of security at the db level.
See http://php.net/md5 or http://php.net/sha1 for further information.
I agree with the idea if using SESSION variables while authenticating the user.
The easy way to authenticate the user is as follows
//connect the mysql_db
$mysql_connect()
$mysql_select_db()
//reading from mysql table
$res="SELECT * FROM table WHERE name=$username AND password=$password";
$val=mysql_query($res);
//authentication
$count=mysql_num_rows($val);
if($count==1)
//authenticate the user
else
through an error