I'm trying to login a user, but I always get no result from the query below. If I just query the username, it works. Everything looks good in the database.
Any help is very appreciated!
Thanks
$login = 1;
$username = 'james';
$password = 'myPassword';
if ($login == 1)
{
$pwdPassword = md5($password);
$insertUser = mysql_query("INSERT INTO users (username, password) VALUES ('$username', '$pwdPassword')");
$queryUser = "SELECT * FROM users WHERE username='$username' AND password='".md5($password)."'";
$result = mysql_query($queryUser);
if (mysql_num_rows($result) != 0)
{
echo 'success';
return;
}
else
{
echo mysql_error();
echo 'error';
return;
}
}
UPDATE
If I try the above script, without using md5(), it works fine. So I guess the problem is with the md5(). Is md5() the best way to handle the password or is there any better way?
Edited Solution
You say the code works fine without md5 but it doesn't work with md5. When you change the code to encrypt the password, do you also change the database entry (manually I suppose) to the md5 hash?
Remember that all md5 does is turn your password into a garbled bunch of characters. So you need to store that garbled bunch in the database, and use that to compare to the md5 hash you create of the user's input.
make sure your password field in your DB is CHAR(32).
md5() creates a 32 bit hash
(always 32 characters), set the size of your field to 32 to avoid it being truncated when it's inserted.
Other than that I don't see anything wrong with the script. Try echo-ing what you're pulling out of the database as password and $pwdPassword - that could give you an idea of what's going wrong.
"SELECT * FROM users WHERE username='$username' AND password='".md5($password)."'";
I donn't believe you need to call the md5() function again, since you allready declared $pwdPassword
This might work:
"SELECT * FROM users WHERE username='$username' AND password='" . $pwdPassword . "'";
Password might be a reserved name, try escaping it
`password`
Related
I think i have hashed password using function PASSWORD directly from mysql database(am i doing wrong here?). And i am trying to verify that password with this code:
if($submit)
{
$first=$_POST['first'];
$password=$_POST['password'];
$hash="*85955899FF0A8CDC2CC36745267ABA38EAD1D28"; //this is the hashed password i got by using function PASSWORD in database
$password=password_verify($password,$hash);
$db = new mysqli("localhost", "root","","learndb");
$sql = "select * from admin where username = '" . $first . "' and password = '". $password . "'";
$result = $db->query($sql);
$result=mysqli_num_rows($result);
if($result>0)
{
session_start();
$_SESSION['logged_in'] = true;
session_regenerate_id(true);
header("Location:loginhome.php");
}
}
But the password is not matching. What am i missing here?
UPDATE:
After all the suggestions i have used password_hash from php code to store into database.
$db = new mysqli("localhost", "root","","learndb");
$password=password_hash('ChRisJoRdAn123',PASSWORD_DEFAULT);
$sql="INSERT INTO admin (username,password)values('ChrisJordan','$password')";
$db->query($sql);
still the password is not matching.
One cannot search for a salted password hash in a database. To calculate the hash you need the password_hash() function as you already did correctly in your insert statement.
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_DEFAULT);
To check a password, you first need to search by username only (used a prepared query to avoid sql injection):
$sql = 'select * from admin where username = ?';
$db->prepare($sql);
$db->bind_param('s', $first);
When you finally got the stored hash from the database, it can be checked like this:
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
password_verify is a boolean function which return either true or false. In your code, after getting value of password from Post param, you doing this operation
$password=password_verify($password,$hash);
which changes the $password value to true or false and that boolean value stored in $password you are using in mysql select statement
$sql = "select * from admin where username = '" . $first . "' and password = '". $password . "'";
Another thing is it might be possible that the hashed/salted password you are using is not the correct hashed value of the password you are using.
Update: Try this
$cost = [
'cost' => 15,
];
$hash_password = password_hash('ChRisJoRdAn123', PASSWORD_BCRYPT, $cost);
before any db operation, change your password field varchar length to >=64
$sql = "INSERT INTO admin (username,password)values('ChrisJordan','".$hash_password."')";
After insert operation, execute the select statement with the user
$sql = "select * from admin where username = 'ChrisJordan'";
after this fetching hased password and password from the post parameter, you will need to verify both passwords using password_verify
if (password_verify(validate($_POST['password']), $hash_password_from_db)) {
echo "Valid Password";
}else{
echo "Invalid Password";
}
You must use password_hash to encode passwords verified with password_verify.
The MySQL function PASSWORD is something entirely different. It is used for encoding passwords specific to MySQL authentication. (MySQL specifically recommends against using PASSWORD for anything other than MySQL authentication.)
The two use different hashing algorithms, present their output in different formats, and are generally not compatible with each other.
The typical way to use password_hash and password_verify is:
$hash = password_hash($password, PASSWORD_DEFAULT);
//Store $hash in your database as the user's password
//To verify:
//Retrieve $hash from the database, given a username
$valid = password_validate($password, $hash);
The problem in your code is that you're doing this:
$password=password_verify($password,$hash);
$sql = "select * from admin where username = '" . $first . "' and password = '". $password . "'";
password_verify returns a boolean (whether the password and hash matched). Instead, you need to retrieve the hash from the database and match the entered password with that hash.
This is too long for a comment.
Seeing that this question has yet to contain a green tick next to any of the answers, am submitting the following in order to point out probable issues.
I noticed that you are trying to move over from MD5 to password_hash() - password_verify().
Your other question Switching from md5 to password_hash
What you need to know is that MD5 produces a 32 character length string, as opposed to password_hash() being a 60 length.
Use varchar(255).
If you kept your password column's length to 32, then you will need to clear out your existing hashes from that column, then ALTER your column to be 60, or 255 as the manual suggests you do.
You will need to clear out all your existing passwords, ALTER your column, create a new hash, then try your login code again.
I see this in your code:
"*85955899FF0A8CDC2CC36745267ABA38EAD1D28"; //this is the hashed password i got by using function PASSWORD in database
This string *85955899FF0A8CDC2CC36745267ABA38EAD1D28 is 40 long, which is too short and has been cut off.
This tells me that your column's length is 40, instead of 60, or again as the manual suggests, 255.
MD5 reference:
http://php.net/manual/en/function.md5.php
Returns the hash as a 32-character hexadecimal number.
Reference for password_hash():
http://php.net/manual/en/function.password-hash.php
The result will always be a 60 character string, or FALSE on failure.
To ALTER your column, here is a reference link:
http://dev.mysql.com/doc/refman/5.7/en/alter-table.html
Also make sure that your form contains a POST method and that the inputs bear the matching name attributes and that no whitespace gets introduced.
You can use trim() to get rid of those.
Add error reporting to the top of your file(s) which will help find errors.
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
// Then the rest of your code
Sidenote: Displaying errors should only be done in staging, and never production.
as well as or die(mysqli_error($db)) to mysqli_query().
Edit:
What you need to do is fetch an array and get the match on that.
$sql = "select * from admin where username = '".$first."' and password = '".$password."' ";
$result = $db->query($sql);
if ($result->num_rows === 1) {
$row = $result->fetch_array(MYSQLI_ASSOC);
if (password_verify($password, $row['password'])) {
//Password matches, so create the session
// $_SESSION['user']['user_id'] = $row['user_id'];
// header("Location:/members");
echo "Match";
}else{
echo "The username or password do not match";
}
}
Another possible solution:
$query = "SELECT * from admin WHERE username='$first'";
$result = $db->query($query);
if($result->num_rows ===1){
$row = $result->fetch_array(MYSQLI_ASSOC);
if (password_verify($password, $row['password'])){
echo "match";
} else {
$error = "email or Password is invalid";
echo $error;
}
}
mysqli_close($db); // Closing Connection
I am creating a login system for my website using a mysql database.
When the user registers, it saves the password to the database using:
$password = hash("sha512","somesalt".$password."moresalt");
Then when I login, I compare the password entered to the password in the database using the same hash function.
To compare the database I use this:
$query = mysql_query("select * from users where password='$password' AND email='$email'", $connection);
$rows = mysql_num_rows($query);
if ($rows == 1) {//do login stuff}
But rows always returns 0. When I remove the hash function from both the register and login, it logs in fine. What's wrong?
As a side note in case anyone's wondering, I would be using mysqli but my webhosting's database version is old. They are using 5.2 I believe.
I forgot to mention that I did check to make sure the database did match what it was getting as seen in these pics (can't embed pics so links):
https://drive.google.com/file/d/0B_u6weYp5wTCQng5eVhTSkZFRDg/view?usp=sharing
https://drive.google.com/file/d/0B_u6weYp5wTCQVRXTkNqdzhWUFE/view?usp=sharing
what is the length of your password field in database???
The reason seems to me is the hashed password length is too long and while saving to database part or it is dropped...
Then when you compare you get 0 rows...
Okay, I would like to suggest that you use prepared statements other than the mysql library. It is much more secure and reliable.
$query = "SELECT * FROM `users` WHERE AND `email`=:email_token";
Then you prepare and execute your query
$data = $connection->prepare($query);
try {
$data->bindParam(":email_token",$_POST["email"],PDO::PARAM_STR);
$data->execute();
}
$result = $data->fetch(PDO::FETCH_ASSOC);
while($row = $result) {
$out = $row["password"];
}
if($out == $_POST["password"]) {
//loggin
} else {
//get lost
}
This is a very basic structure but essentially you want to pull the password out of the database first then compare the strings instead of doing it all with your query.
I have an idea for a system to log in users and validate their login on pages.
I realize that there are lots of systems out there, but I mainly was curious if the idea I had was any good. I've done some digging, but most results seem to leave out what I've always thought to be important practices (like password encryption, etc). I'll probably look harder for a pre-made solution, as it is probably more secure, but I haven't really worked with application security, and was hoping to get some feedback.
When a user logs in, their name and password are verified against a database, the password is encrypted using SHA256 and a randomly generated salt, the overall string (both the salt and the encrypted password is 128 chars. long).
Here's the password validation code:
function ValidatePassword($password, $correctHash)
{
$salt = substr($correctHash, 0, 64); //get the salt from the front of the hash
$validHash = substr($correctHash, 64, 64); //the SHA256
$testHash = hash("sha256", $salt . $password); //hash the password being tested
//if the hashes are exactly the same, the password is valid
return $testHash === $validHash;
}
If the login is valid, they are assigned a token. This token is similar to the password encryption, but stores the encrypted epoch as well as another random salt. The token, the login time, an expiration time, and the username are stored in a DB and the username and the token are transmitted as session information.
Here's the code that creates the token:
function loginUser($email)
{
$thetime = time();
$ip = $_SERVER['REMOTE_ADDR'];
$dbuser="///";
$dbpass="///";
$dbtable="tokens";
mysql_connect(localhost,$dbuser,$dbpass);
mysql_select_db("///") or die( "Unable to select database");
//Generate a salt
$salt = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
//Hash the salt and the current time to get a random token
$hash = hash("sha256", $salt . $password);
//Prepend the salt to the hash
$final = $salt . $hash;
$exptime = $thetime + 3600;
//Store this value into the db
$query = "INSERT INTO `spanel`.`tokens` VALUES ('$final', $thetime, $exptime, $thetime, '$ip', MD5('$email') )";
mysql_query($query) or die ("Could not create token.");
//Store the data into session vars
$_SESSION['spanel_email'] = $email;
$_SESSION['spanel_token'] = $final;
return true;
}
When they reach a page, the token they have and the username are checked against the DB. If the check is good, the expiration time is updated and the page loads.
Here's that code:
function validateUser($page)
{
//Grab some vars
$thetime = time();
$ip = $_SERVER['REMOTE_ADDR'];
$token = $_SESSION['spanel_token'];
$email = $_SESSION['spanel_email'];
$dbuser="///";
$dbpass="///";
$dbtable="tokens";
mysql_connect(localhost,$dbuser,$dbpass);
mysql_select_db("///") or die( "Unable to select database");
//Global var
//Get the var for token expire
$token_expire = 3600;
//Validate the token
$query = "SELECT * FROM `tokens` WHERE `token` LIKE '$token' AND `user_id` LIKE MD5('$email') AND `exp` > $thetime";
$result = mysql_query($query) or die(mysql_error());
//Check if we have a valid result
if ( mysql_num_rows($result) != 1 ) {
//Logout the user
//Destroy the session
session_destroy();
//Redirect
header("location: /spanel/login.php?denied=1");
exit();
//(Since the token is already invalid, there's no reason to reset it as invalid)
}
$row = mysql_fetch_assoc($result);
//Update the token with our lastseen
$newexp = $thetime + $token_expire;
$query = "UPDATE `spanel`.`tokens` SET `exp` = $newexp, `lastseen_ip` = $thetime, `lastseen_ip` = '$ip' WHERE `token` LIKE '$token'";
mysql_query($query);
}
Feedback (good and bad) is appreciated. Like I said, I haven't done much security and was hoping to get pointers.
EDIT: I fear I overestimated my ability to effectively create a login system. Saying this, I understand if you decide to stop trying to figure out the jumbled mess that was this probably flawed idea.
Nevertheless, here's the php code from the login page. (After what's been said here, I realize just POST'ing the password is a big no-no).
$email = $_POST['email'];
$password = $_POST['password'];
$dbuser="///";
$dbpass="///";
$dbtable="///";
mysql_connect(localhost,$dbuser,$dbpass);
mysql_select_db("spanel") or die( "Unable to select database");
$query = "SELECT * FROM users WHERE `email` LIKE '$email'";
$result=mysql_query($query) or die(mysql_error());
$num=mysql_num_rows($result);
$row = mysql_fetch_array($result);
if ( ValidatePassword($password, $row['hash']) == true ) {
loginUser($email);
header("location: /spanel/index.php");
} else {
echo "<p>Login Failed.</p>";
}
Here's the bit that generates the password salt and hash when the account is created.
function HashPassword($password)
{
$salt = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)); //get 256 random bits in hex
$hash = hash("sha256", $salt . $password); //prepend the salt, then hash
//store the salt and hash in the same string, so only 1 DB column is needed
$final = $salt . $hash;
return $final;
}
Thanks for the feedback, I'm glad the problems with my lack of knowledge were found here and not after an attack.
For one, hashing like that is insecure. sha256 can be broken easily, at least for short passwords. You must use some hash stretching. See if you can find some PBKDF2 implementations or use the wikipedia's suggestion for a "for loop" with sha256.
Moreover I don't get what you achieve with having more session variables. I don't understand what validateuser() does, it still relies on session id, or am I missing something.
Similar to sivann, I can’t see the reason for the additional spanel_token either. All it seems to effectively do is to ensure that the session is no longer valid after the token’s expiration time. Since both values for token and user_id for the WHERE condition are stored in the session and are only set during the login, they won’t change. But session expiration can be implemented much easier.
But apart from that and much more important: your code is vulnerable to SQL injection. It would be easy with the knowledge you’ve posted here. All you need is to do the following steps:
Find out the number of columns of users with a UNION SELECT injection in email:
' UNION SELECT null, …, null WHERE ''='
If the wrong number of columns is entered, your script will throw a MySQL error, otherwise the “Login Failed.” will appear. Thanks for that.
By using the following query:
SELECT t1.* FROM users t1 RIGHT JOIN (SELECT email, '000000000000000000000000000000000000000000000000000000000000000060e05bd1b195af2f94112fa7197a5c88289058840ce7c6df9693756bc6250f55' hash FROM users LIMIT 1) t2 USING (email);
the value 000000000000000000000000000000000000000000000000000000000000000060e05bd1b195af2f94112fa7197a5c88289058840ce7c6df9693756bc6250f55 is injected into each record instead of the original hash column value. The leading 0s are the salt and the remaining string is the salted SHA-256 hash value for an empty password string, which will result in a valid password.
So we end up with entering an empty string for the password field and the following for the email field:
' UNION SELECT t2.* FROM users t1 RIGHT JOIN (SELECT email, '000000000000000000000000000000000000000000000000000000000000000060e05bd1b195af2f94112fa7197a5c88289058840ce7c6df9693756bc6250f55' hash FROM users LIMIT 1) t2 USING (email) WHERE ''='
This should suffice to get ‘authenticated’ as any user.
Just commenting on the salt/hash system: Storing the salt alongside the password in the database sort of defeats the purpose of salting--if you database is compromised the salt becomes useless from a security perspective, because its right there to aid in guessing / breaking the security. The purpose of a salt is to increase the time taken to guess a hashed word by adding a secret string of appropriate length to the value you are hashing.
I have a form for updating user data. It posts to this page:
<?php
//Update user table
session_start();
include 'sql_connect_R.inc.php';
$id = mysql_real_escape_string($_POST['userID']);
$password = mysql_real_escape_string($_POST['user_passwrd']);
$salt = time();
$hash = sha1($password . $salt);
mysql_query("UPDATE users SET user_passwrd = '$hash', stamp = '$salt', pending = 'yes'
WHERE userID = '$id'");
mysql_close($con);
?>
(I have edited out the things not pertinent to this question)
I believe what is happening is when the 'stamp' field is being populated with the $salt it is getting a different value than when the $hash is being calculated. Therefore, when a user signs in and is checked here:
$qry="SELECT * FROM users WHERE userlogin = '$login' AND user_passwrd = sha1(CONCAT('$password', stamp))";
$result=mysql_query($qry);
$row = mysql_fetch_assoc($result);
$num = mysql_num_rows($result);
When I echo $num it returns a value of 0.
I'm wondering if there is a way to ensure that the value of $salt remains the same when it is being used in $hash and then when it is updating the field 'stamp'.
Can anyone help me with this or point me in the right direction? Thanks in advance.
Cheers
More ideas so I've changed my comment into an answer...
It's worth noting that you're using PHP's SHA1 function when storing but mysql's when retrieving. They should be the same but that's the first place I'd look to debug this. try using mysql's sha function to store the hash or retrieve the record based on login, read the salt and hash it in PHP to compare
How are you storing the timestamp? Is it possible that it's being transformed/rounded/clipped/treated as a date string in some way? Just for a sanity check, take the string you're feeding into the sha1 function in both steps and check they're identical.
Further to your comment, can you post the schema for the relevant fields in the table?
Thank you for all comments. I want to report that I've 'solved' the problem. I had made a change in the name of the password input field late one night and neglected to change the $_POST value. What this did, of course, was not supply the $password value to the $hash. Though I'm embarrassed about this, I think it is important for me to share my oversight to exemplify how important it is to check ALL places where errors can occur. I failed to double-check everything and made incorrect assumptions about the nature of the problem. The code worked fine, it was the loose screw in front of the keyboard that caused the problems. Cheers
You're doing your queries incorrectly. You need to concatenate the variables in the string and NOT use single quotes. Use the quote to the left of your 1 key ``. This is the way that most MySQL read queries. example:
<?php
//Update user table
session_start();
include 'sql_connect_R.inc.php';
$id = mysql_real_escape_string($_POST['userID']);
$password = mysql_real_escape_string($_POST['user_passwrd']);
$salt = time();
$hash = sha1($password . $salt);
mysql_query("UPDATE `users` SET `user_passwrd` = '".$hash."', `stamp` = '".$salt."', `pending` = 'yes' WHERE `userID` = '".$id."'");
mysql_close($con);
?>
$qry="SELECT * FROM `users` WHERE `userlogin` = '".$login."' AND `user_passwrd` = '".sha1(CONCAT($password, stamp))".'";
$result=mysql_query($qry);
$row = mysql_fetch_assoc($result);
$num = mysql_num_rows($result);
This little change should help. Sometimes the db can be a little touchy. I hope this helps.
Alright, I'm trying to make a login page. It seems that all of the pages worked pretty good- until I added salts. I don't really understand them, but doing something as basic as I am shouldn't be to hard to figure out. Here's "loginusr.php":
<html>
<body>
<?php
//form action = index.php
session_start();
include("mainmenu.php");
$usrname = mysql_real_escape_string($_POST['usrname']);
$pass = $_POST['password'];
$salt = $pass;
$password = sha1($salt.$pass);
$con = mysql_connect("localhost", "root", "g00dfor#boy");
if(!$con)
{
die("Unable to establish connection with host. We apologize for any inconvienience.");
}
mysql_select_db("users", $con) or die("Can't connect to database.");
$select = "SELECT * FROM data WHERE usrname='$usrname' and password='$password'";
$query = mysql_query($select);
$verify = mysql_num_rows($query);
if($verify==1)
{
$_SESSION["valid_user"] = $usrname;
header("location:index.php");
}
else
{
echo "Wrong username or password. Please check that CAPS LOCK is off.";
echo "<br/>";
echo "Back to login";
}
mysql_close($con);
?>
</body>
</html>
I used the command echo $password; to show me if the password in the database matched with the script. They did. What am I doing wrong?
It seems like you've misunderstood salts, since you're setting $salt to be the password.
A salt should be a completely random string that's stored in a user record along with the password hash. A new unique salt should be generated for every user. So you need to add a new column to your database, called "password_salt" or similar.
Rather than trying to use the password in the SELECT query and see if you get any records, you actually need to just SELECT using the username/user_id in order to get the password hash and salt so that you can then use those to determine if the user entered the correct password.
When you sign up new users you should add the fields with values like this,
<?php
// This is registeruser.php
$salt = substr(sha1(uniqid(rand(), true)), 0, 20);
$pass = $_POST['password'];
$pass_to_store = hash("sha256", $salt.$pass);
// Then issue a DB query to store the $salt and $pass_to_store in the user record.
// Do not store $pass, you don't need it.
// e.g. INSERT INTO users ('username', 'password_salt', 'password_hash') VALUES (:username, :salt, :pass_to_store);
?>
Then to check the password is the same when logging in, you do something like this,
<?php
// This is loginuser.php
$user = // result from SQL query to retrieve user record
// e.g. SELECT password_hash, password_salt FROM users WHERE username='from_user'
$salt_from_db = $user['password_salt'];
$pass_from_db = $user['password_hash'];
if ($pass_from_db == hash("sha256", $salt_from_db.$_POST['password'])
{
// Password matches!
}
?>
Don't forget to sanitize user inputs and anything you're putting into your database. You might want to look into using prepared statements instead of having to remember to use mysql_real_escape_string all the time.
It looks like you're salting with the same password? Normally a salt would be a random key that is specific to your site that you prepend to the password input, which it looks like you're doing fine. Just make sure you're using that same salt for checking that you use when the password is created.
Also, to use sessions properly you need to have session_start before anything is output to the page:
<?php
session_start();
?>
<html>
<body>
...
A salt is a random value to prevent an attacker from just looking up the source of a hash in table generated based on common passwords. (Using the username as salt is obviously not a good idea as it only adds very little entropy).
So you need to store the salt in the database and read it from the database in order to calculate the salted password hash for comparison with the stored value.
You misspelled username a couple of times, is it misspelled in the database, too?