Password Reset Link Expiry - php

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.

Related

php md5 for login won't let me login, and keeps saying password incorrect

The md5 is posting to the database from the signup page so I know that's working, but everything I try here won't let me sign in and just keeps telling me I have the wrong password.
<?php
// Parse the log in form if the user has filled it out and pressed "Log In"
if (isset($_POST["user_name"]) ) {
$user = mysql_real_escape_string($_POST["user_name"]);
$pass_word = mysql_real_escape_string(md5($_POST["pass_word"]));
$pass_word=md5($pass_word);
// Connect to the MySQL database
include "../connect_to_mysql.php";
$sql = mysql_query("SELECT m_id FROM member WHERE user_name='$user' AND pass_word='$pass_word' LIMIT 1"); // query the person
// ------- MAKE SURE PERSON EXISTS IN DATABASE ---------
$existCount = mysql_num_rows($sql); // count the row nums
if ($existCount == 1) { // evaluate the count
while($row = mysql_fetch_array($sql)){
$id = $row["m_id"];
}
$_SESSION["m_id"] = $id;
$_SESSION["user"] = $user;
$_SESSION["pass_word"] = $pass_word;
header("location: ../../index.php");
exit();
} else {
echo 'That information is incorrect, try again Click Here';
exit();
}
}
?>
You're running MD5 twice on your password.
$pass_word = mysql_real_escape_string(md5($_POST["pass_word"]));
$pass_word = md5($pass_word);
Also, don't use MD5, it is completely unsafe, look into using bcrypt, it is secure, and very easy to implement in PHP. Replacing MD5 with this line of code will make your password hashes safe. Preferably add some salt, the salt being some random string. It will make breaking your passwords nigh impossible.
$hash = password_hash($password . $salt, PASSWORD_BCRYPT);
Change these lines from
$pass_word = mysql_real_escape_string(md5($_POST["pass_word"]));
$pass_word=md5($pass_word);
to
$pass_word=md5($_POST["pass_word"]);

How to connect user with a login cookie in PHP?

First of all, I am testing on localhost. I have this index.php file which contains the following "remember me" checkbox:
<input type="checkbox" id="login_remember" name="login_remember">
The login form posts to loginvalidate.php, which includes the following php script. I have included a lot of comments to ease the process of reading my code. Note that I'm pretty sure that everything below works fine.
if (isset($_POST['login_submit'])) { //SETS VARIABLES FROM FORM
$email = $_POST[trim('login_email')];
$password = $_POST['login_password'];
$remember = isset($_POST['login_remember']) ? '1' : '0';
$db_found = mysqli_select_db($db_handle,$sql_database); //OPENING TABLE
$query = "SELECT password FROM registeredusers WHERE email = '$email'";
$result = mysqli_query($db_handle, $query) or die (mysqli_error($db_handle));
$row = mysqli_fetch_assoc($result);
$numrows = mysqli_num_rows($result);
if ($numrows!=0) //IF EMAIL IS REGISTERED
{
if ($row['password'] == $password) { //IF PASSWORD IN DATABASE == PASSWORD INPUT FROM FORM
if ($remember == '1'){ //IF USER WANTS TO BE REMEMBERED
$randomNumber = rand(99,999999); //RANDOM NUMBER TO SERVE AS A KEY
$token = dechex(($randomNumber*$randomNumber)); //CONVERT NUMBER TO HEXADECIMAL FORM
$key = sha1($token . $randomNumber);
$timeNow = time()*60*60*24*365*30; //STOCKS 30 YEARS IN THE VAR
$sql_database = "registeredusers";
$sql_table = "rememberme";
$db_found = mysqli_select_db($db_handle,$sql_database); //OPENING TABLE
$query_remember = "SELECT email FROM rememberme WHERE email = '$email'"; //IS THE USER IN TABLE ALREADY
$result = mysqli_query($db_handle, $query_remember) or die (mysqli_error($db_handle));
if (mysqli_num_rows($result) > 0) { //IF USER IS ALREADY IN THE REMEMBERME TABLE
$query_update = "UPDATE rememberme SET
email = '$email'
user_token = '$token'
token_salt = '$randomNumber'
time = '$timeNow'";
}
else { //OTHERWISE, INSERT USER IN REMEMBERME TABLE
$query_insert = "INSERT INTO rememberme
VALUES( '$email', '$token', '$randomNumber', '$timeNow' )";
}
setcookie("rememberme", $email . "," . $key, $timenow);
}
header('Location: homepage.php'); //REDIRECTS: SUCCESSFUL LOGIN
exit();
}
Then, when I close the internet browser and come back to index.php, I want the cookie to automatically connect the user. This is in my index.php:
include 'db_connect.php';
$sql_database = "registeredusers";
$db_found = mysqli_select_db($db_handle,$sql_database); //OPENING TABLE
session_start();
if (isset($_COOKIE['rememberme'])) {
$rememberme = explode(",", $_COOKIE["rememberme"]);
$cookie_email = $rememberme[0];
$cookie_key = $rememberme[1];
$query_remember = "SELECT * FROM rememberme WHERE email = '$cookie_email'"; //IS THE USER IN TABLE ALREADY
$result_remember = mysqli_query($db_handle, $query_remember) or die (mysqli_error($db_handle));
$row = mysqli_fetch_assoc($result_remember);
$token = $row['user_token'];
$randomNumber = $row['token_salt'];
$key = sha1($token . $randomNumber); //ENCRYPT TOKEN USING SHA1 AND THE RANDOMNUMBER AS SALT
if ($key == $cookie_key){
echo "lol";
}
}
The problem is, it never echoes "lol". Also, does anyone have any insight on how I could connect the users? AKA, what should go inside these lines:
if ($key == $cookie_key){
echo "lol";
}
Thank you! I'm still new to PHP and SQL so please bear with me if I have made some beginner errors.
EDIT!: After looking again and again at my code, I think that my error might lie in these lines. I'm not sure about the syntax, and the method I am using to store values into $token and $randomNumber:
$query_remember = "SELECT * FROM rememberme WHERE email = '$cookie_email'"; //IS THE USER IN TABLE ALREADY
$result_remember = mysqli_query($db_handle, $query_remember) or die (mysqli_error($db_handle));
$row = mysqli_fetch_assoc($result_remember);
$token = $row['user_token'];
$randomNumber = $row['token_salt'];
A login script in PHP can be implemented using sessions.
Using Sessions
Making it simple, sessions are unique and lives as long as the page is open (or until it timeouts). If your browser is closed, the same happens to the session.
How to use it?
They are pretty simple to implement. First, make sure you start sessions at the beginning of each page:
<?php session_start(); ?>
Note: It's important that this call comes before of any page output, or it will result in an "headers already sent" error.
Alright, now your session is up and running. What to do next? It's quite simple: user sends it's login/password through login form, and you validate it. If the login is valid, store it to the session:
if($validLoginCredentials){
$_SESSION['user_id'] = $id;
$_SESSION['user_login'] = $login;
$_SESSION['user_name'] = $name;
}
or as an array (which I prefer):
if($validLoginCredentials){
$_SESSION['user'] = array(
'name' => $name,
'login' => 'login',
'whichever_more' => $informationYouNeedToStore
);
}
Ok, now your user is logged in. So how can you know/check that? Just check if the session of an user exists.
if(isset($_SESSION['user_id'])){ // OR isset($_SESSION['user']), if array
// Logged In
}else{
// Not logged in :(
}
Of course you could go further, and besides of checking if the session exists, search for the session-stored user ID in the database to validate the user. It all depends on the how much security you need.
In the simplest application, there will never exist a $_SESSION['user'] unless you set it manually in the login action. So, simply checking for it's existence tells you whether the user is logged in or not.
Loggin out: just destroy it. You could use
session_destroy();
But keep in mind that this will destroy all sessions you have set up for that user. If you also used $_SESSION['foo'] and $_SESSION['bar'], those will be gone as well. In this case, just unset the specific session:
unset($_SESSION['user']);
And done! User is not logged in anymore! :)
Well, that's it. To remind you again, these are very simple login methods examples. You'll need to study a bit more and improve your code with some more layers of security checks depending on the security requirements of your application.
reason behind your code is not working is
setcookie("rememberme", $email . "," . $key, $timenow); // this is getting expire exactly at same time when it is set
replace it with
setcookie("rememberme", $email . "," . $key, time() * 3600);//expire after 1hour
time()*60*60*24*365*30
this time is greater than 9999 year also you didn't need to set this horror cookie time.
that cookie time you were set is greater than 9999 years and php not allow for this configure.
in my opinion the best solution is setup new expire cookie time lower than 9999 :))

can't pull info form database that uses PASSWORD() function

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.

validating user/updating table

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?

How to improve login script?

How can I ensure my login script is secure and make it better, This is my first code:
Help is most appreciated.
<?php
include ('../includes/db_connect.php');
$firstname = $_POST['firstname'];
$lastname = $_POST['lastname'];
$email = $_POST['email'];
$mobile = $_POST['mobile'];
$username = $_POST['username'];
$password = md5($_POST['password']);
// lets check to see if the username already exists
$checkuser = mysql_query("SELECT username FROM users WHERE username='$username'");
$username_exist = mysql_num_rows($checkuser);
if($username_exist > 0){
echo "I'm sorry but the username you specified has already been taken. Please pick another one.";
unset($username);
header("Location: /registration?registration=false");
exit();
}
// lf no errors present with the username
// use a query to insert the data into the database.
$query = "INSERT INTO users (firstname, lastname, email, mobile, username, password)
VALUES('$firstname', '$lastname','$email', '$mobile','$username', '$password')";
mysql_query($query) or die(mysql_error());
mysql_close();
echo "You have successfully Registered";
header("Location: /registration?registration=true");
// mail user their information
//$yoursite = ‘www.blahblah.com’;
//$webmaster = ‘yourname’;
//$youremail = ‘youremail’;
//
//$subject = "You have successfully registered at $yoursite...";
//$message = "Dear $firstname, you are now registered at our web site.
// To login, simply go to our web page and enter in the following details in the login form:
// Username: $username
// Password: $password
//
// Please print this information out and store it for future reference.
//
// Thanks,
// $webmaster";
//
//mail($email, $subject, $message, "From: $yoursite <$youremail>\nX-Mailer:PHP/" . phpversion());
//
//echo "Your information has been mailed to your email address.";
?>
Follow Artefacto's advice about SQL injection and Hashing passwords in the database. Other things ...
echo "I'm sorry but the username you specified has already been taken. Please pick another one.";
unset($username);
header("Location: /registration?registration=false");
Wont work because you can't echo then send a header. Headers must be sent before any output.
Also, there is no point doing this:
header("Location: /registration?registration=false");
echo "I'm sorry but the username you specified has already been taken. Please pick another one.";
unset($username);
The webbrowser will redirect straight away and the user won't see the handy message you've printed.
Also, it's usual to ask for 2 password fields on registration forms incase the user made a typo and didn't notice because all the text was *'s. You compare the 2 and if they are different you assume a typo was made and ask again.
That's not a login script. It's a registration script.
See SQL injection in the PHP manual. Your program is vulnerable to this kind of attacks.
Also, don't just or die(mysql_error()). This will expose information about your database that you may not want to expose (table names, etc.). Use proper error handling. For instance, you can throw an exception and define a uncaught exception handler that shows a "oops" page and logs the error.
Finally, use hashes strong than MD5, such as sha1.
As said by #Artefacto, that's not a login script.
But if you intend to do a login script I would like to give you a suggestion. I've done this a while ago.
Instead of doing something like this:
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
I would do this:
$sql = "SELECT * FROM users WHERE username = '$username'";
$user = //use the php-sql (query, fetch_row) commands to fetch the user row.
if (strcmp($user['password'], $password) == 0) {
//log in success
}
By doing this, you avoid SQL Injection in a simple and elegant way. What you guys think about it?
To reiterate what everyone else mentioned. It's important to protect yourself (and sever) from SQL injection. For example:
$checkuser = mysql_query("SELECT username FROM users WHERE username='$username'");
You're just simple taking the value from $_POST['username'] and placing it in the variable $username.
Some people aren't very nice and will try to break your program :( So it's always recommended to escape any data that was taken from a user, before placing it into an SQL query.
For instance...
This:
$checkuser = mysql_query("SELECT username FROM users WHERE username='$username'");
Becomes:
$checkuser = mysql_query("SELECT username FROM users WHERE username='" .mysql_real_escape_string($username). "'");

Categories