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.
Related
I have encrypted and store password. Once user login I want to decrypt and validate .But following code is not able to do that. Can any body help with this?
<?php
include("config.php");
if($_SERVER["REQUEST_METHOD"] == "POST") {
$myusername = mysqli_real_escape_string($con,$_POST['username']);
$mypassword =md5(mysqli_real_escape_string($con,$_POST['password']));
$sql = "SELECT id FROM services WHERE user_name = '$myusername' and password = '$mypassword'";
$result = mysqli_query($con,$sql);
$row = mysqli_fetch_array($result,MYSQLI_ASSOC);
$count = mysqli_num_rows($result);
if($count == 1) {
echo "success";
}else {
echo "fail";
}
}
?>
It isn't necessary to escape value, that will be md5-hashed. You even could change the password (and md5 hash) if it contains some special char. For example, lets see at password's test' hashes:
echo md5(mysqli_real_escape_string($con,$_POST['password']));
echo md5($_POST['password']);
Output is:
e1e7975d4f1958297ede35ea4fc13a27
5c28a8c6d799d302f3ef53afefdfc81b
You shouldn't do:
$row = mysqli_fetch_array($result,MYSQLI_ASSOC);
because you don't use it later and you don't check if num_rows > 0 and it'll give an error if there are 0 records.
md5 should never ever be used for storing passwords.
First off it's been known to be broken for decades already, but that's not the worst of it in this case.
Secondly you're using it without a random salt, which makes it vulnerable to rainbow table attacks.
Finally, and most crucially, it's a fast algorithm, and hence completely unsuitable for password hashing. Any hacker worth their "salt" that gets a hold of your user's hashed passwords will make short work of finding >90% of the passwords in a matter of hours as your users will use predictable passwords instead of truly random ones.
You really need to use something like password_hash().
I found other method and this was success.Thank for your help
<?php
include('config.php');
session_start();
if($_SERVER['REQUEST_METHOD'] == "POST")
{
//Username and Password sent from Form
$username = mysqli_real_escape_string($con, $_POST['username']);
$password = mysqli_real_escape_string($con, $_POST['password']);
$password = md5($password);
$sql = "SELECT * FROM services WHERE user_name='$username' AND '$password'";
$query = mysqli_query($con, $sql);
$res=mysqli_num_rows($query);
//If result match $username and $password Table row must be 1 row
if($res == 1)
{
//header("Location: welcome.php");
echo "did";
}
else
{
echo "Invalid Username or Password";
}
}
?>
I set up a dev server and I installed nginx with php-fpm and 7.2 php (I installed all the necessary php packages).
The time has come to upgrade the security of all logins, using the argon2i algo.
So, I tried this (test code in dev enviroment. The security in the code, will come later):
require('connector.php');
$usr_u = $_POST['username'];
$psw_u = $_POST['password'];
$usr = mysqli_real_escape_string($conn, $usr_u);
$psw = mysqli_real_escape_string($conn, $psw_u);
$f_pass = password_hash($psw, PASSWORD_ARGON2I);
$result = "SELECT `username` FROM `users` WHERE username = '$usr'";
$tbl = mysqli_query($conn, $result);
$table = $tbl->fetch_assoc();
$m_user = $table['username'];
if ($m_user == $usr)
{
//correct username
echo 'Correct username!<br>';
$result = "SELECT `password` FROM `users` WHERE username = '$m_user'";
$tbl = mysqli_query($conn, $result);
$table = $tbl->fetch_assoc();
$m_pass = $table['password'];
if (password_verify($m_pass,$f_pass)) //always returns false
{
echo 'Password correct!<br>';
}
else
{
echo 'Wrong password!<br>';
}
}
else
{
echo 'Wrong username!<br>';
}
//close connection
mysqli_close($conn);
I always get "Correct username!" and "Wrong password!". I used echo on hashed password from the DB and from the input and I see that every time the hashed password is different. I assume that the hashing process, include using random salt and there is my issue.
As far as I understand, the random salt is necessary in order to retain the security of the hashing.
Can you please point me to the right direction, on how to solve this? I have the hashed password in my DB and I can't figure out a way to check the input password against the one in my DB (using password_verify and hash_equals).
Thank everyone in advance for the help.
Look at the documentation for password_verify:
bool password_verify ( string $password , string $hash )
The first argument is the password but you are passing it the hash you want to compare it to.
The second argument is the hash you want to compare it to but you are passing it a new hash created from user input.
password_verify($_POST['password'], $m_pass)
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 have created this php login script. I was wondering weather it was secure and if not how could I improve it.
PHP Script
<?php
include_once ("ConnectToMySql.php");
session_start();
$username = $_POST['username'];
$username = mysql_real_escape_string($username);
$password = $_POST['password'];
$password = sha1($password);
$query = "SELECT password FROM users WHERE username = '$username';";
$result = mysql_query($query);
if(mysql_num_rows($result) < 1)
{
echo "This Username Is Not Registered!";
exit;
}
if(mysql_num_rows($result) == 1)
{
if ($password == $result)
{
echo "Logged In!";
}
else echo "Wrong Password!";
}
?>
Thanks
A first tip could be to show a common error for both invalid login cases: invalid username or password. That way an eventual attacker wouldn't know if the username is valid or not.
You could also make a single query matching both username and password. You would probably need more user information (to store in session?), so it would be a good idea to select those fields instead of the password (e.g. id, name).
Regarding the hashed password stored in the database, you could add a SALT to improve security.
http://en.wikipedia.org/wiki/Salt_%28cryptography%29
What I would do is change the query to the following:
"SELECT COUNT(*) FROM users WHERE username = '$username' AND password='$password';"
That way, you don't have to check if the password is correct afterwards (and you don't have to pass the sensitive data as well), you only have to check if the numbers of rows returned equal 1 and you can produce a single error message for both username/password.
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