I am writing a deliberately vulnerable web application. I'd like to figure out how to check username and password, matching against the database and each other as well.
So: if the username exists in the database and the password exists in the database and the username and password belongs together. I'm fully aware how to send a query which checks for both at the same time and returns either true or false, so please don't start on that. My goal is to individually check for both so I can inform the user which one is not working.
Here's my code but as I'm not really a PHP person this is obviously not working:
<?php
if(isset($_POST["submit"])){
$username = mysqli_real_escape_string($conn, $_POST['username']);
$password = mysqli_real_escape_string($conn, $_POST['password']);
$sql_username = "SELECT id FROM users WHERE username = '$username'";
$sql_password = "SELECT id FROM users WHERE password = '$password'";
$result_username = mysqli_query($conn, $sql_username);
$result_password = mysqli_query($conn, $sql_password);
$row_username = mysqli_fetch_array($result_username);
$row_password = mysqli_fetch_array($result_password);
$count_username = mysqli_num_rows($result_username);
$count_password = mysqli_num_rows($result_password);
if($count_username > 0 && $count_password < 0) {
echo "Invalied password";
} else if ($count_username < 0 && $count_password > 0) {
echo "Invalied username";
} else {
"Welcome";
}
}
?>
Any hints?
Edit
$conn can be used as I'm getting it from another php file.
<?php
//set up a connection and all that prerequisite stuff
$sqlConnectionNameHere = new mysqli($sql_host, $sql_username, $sql_password, $sql_dbname);
$username = 'bob'; //the username that will be checked
$password = 'securepassword1'; //the password that will be checked
$query = $sqlConnectionNameHere->query("SELECT username, password FROM users WHERE username='$username' LIMIT 1"); //make your query
if ($query->num_rows != 1){ //if the datbase didn't return any rows, the user with $username must not exist
die('User not found!');
}
while ($user = $query->fetch_assoc()){
if ($user['password'] != $password){
die('Invalid Password');
}
}
//if they've made it here, the user exists and the password matches!
echo 'Welcome!';
?>
This is a really barebones way of doing it. You may want to add more security to this.
Hope this helps. Best of luck to you!
I know its way cooler to let the user know wether the username or password is wrong. But this actually helps get unwanted indivuduals to pass this test. Since they can test if a specific user is present or not. From there this individual would bruteforce the password. So its a good practice to just check for username AND password.
Furthermore you can store the password as a hash. This way not even the hoster of your db has a direct access to the passwords. Use MD5 or SHA. As example the credentials in your db would look like:
User Password
Admin 098f6bcd4621d373cade4e832627b4f6
This is a MD5 hash. You'll get this hash if you process md5('test'). A hash is a one way "encryption" function. You check it by hashing the user-input and comparing this result with the stored hash.
If you check for this password you'd bind it like this:
$stmt->bind_param("ss", $_POST['username'], md5($_POST['password']));
$mysqli = new mysqli("localhost", "my_user", "my_password", "my_db");
Plaintext password(not recommended!) - prepared select
$stmt = $mysqli->prepare("SELECT id FROM users WHERE username=? AND password=?");
// type string, string ("ss")
$stmt->bind_param("ss", $_POST['username'], $_POST['password']);
// hashed (recommended)
// $stmt->bind_param("ss", $_POST['username'], md5($_POST['password']));
$stmt->execute();
// set target for the id-column
$stmt->bind_result($id);
// Will be TRUE if a row has been found
if( $stmt->fetch() ) {
echo "Welcome! user:{$id}";
} else {
echo "Invalid username or password";
}
For details have a look at mysqli prepare
And a little more security related: Password hashing
Related
So in my function I have the connection, the query which will result in 1 row and 1 column displayed. I then want to run the password_verify() This is where I am struggling. As the first parameter I have placed $pass which is user entered but then I need to get the result from the database to place in the 2nd parameter.
How would I do this?
function login($user, $pass){
$conn = connect();
$query = "SELECT password FROM account WHERE username = '$user' AND password = '$pass'";
$result = mysqli_query($conn, $query);
if (mysqli_num_rows($result)=== 1){
password_verify($pass, "$row[password]");
session_start();
If you do everything right your password field in a account table stores hashed password.
And argument $pass of a function is a plain password, I suppose.
So, your query
SELECT password FROM account WHERE username = '$user' AND password = '$pass'
will NEVER find any user, as you try to find user by plain password.
In addition - your $row variable is not defined.
What's the solution:
function login($user, $pass){
$conn = connect();
// do not add password to query
$query = "SELECT password FROM account WHERE username = '$user'";
$result = mysqli_query($conn, $query);
if (mysqli_num_rows($result) === 1){
// define $row
$row = mysqli_fetch_assoc($result);
// set proper quotes and compare password
// from db with password input by user
if (password_verify($pass, $row["password"])) {
// do something if password is correct
session_start();
And of course, instead of passing values directly to query, start using prepared statements.
When someone registers on your website, you have to use de built-in PHP function password_hash(). Also, I suggest naming it "password_hash" in your database and not "password" as to avoid confusion.
When someone tries to log in on your website, you have to use the built-in PHP password_verify() to compare the hashed password with the password.
// Login function
function login($user, $pass)
{
// Search the user by username
$conn = connect();
$query = "SELECT password_hashed FROM account WHERE username = '$user'";
$result = mysqli_query($conn, $query);
if (mysqli_fetch_row($result))
{
// We found the user, check if password is correct
if(password_verify($pass, $result["password_hashed"]))
{
return true;
}
else
{
return false;
}
}
else
{
// We didn't find the user
return false;
}
}
-Why should you hash the password when you store it into the database? Because when you store the password without hashing, the password in the database is exactly the same like what the user types in when registering. So when a hacker gets into the database, he sees the passwords of every user. If you hash the password, PHP makes the password into something completely else, that way when a hacker gets into the database he doesn't see the password but something completely else.
-The password_verify function is definitely the way to go when a user logs in. Just don't forget to add extra security when you enter data you receive from a user (through $_POST, $_GET, $_SESSION, ...) because when a user types in the follow name: my name" DROP TABLES account; they will delete all account informations.
I have a issue regarding logging in with password being hashed in database.
My current script just tells me 'bad password' message even when its correct.
$s = $mysqli->query("SELECT * FROM `users` WHERE email`='".$_POST['email']."'") or die();
$i = $s->fetch_assoc();
if($_POST['password'] == sha1($i['password'])) {
echo "works";
} else {
echo "bad password";
}
You are doing it the wrong way round. The database password is already hashed I hope but the user enters a plain text password, so you need to hash what the user enters and see if that matches the hash you have on the database
$s = $mysqli->query("SELECT * FROM `users` WHERE `email`='{$_POST['email']}'") or die();
$i = $s->fetch_assoc();
if(sha1($_POST['password']) == $i['password']) {
echo "works";
} else {
echo "bad password";
}
However
Please dont roll your own password hashing. PHP provides password_hash()
and password_verify() please use them, I might want to use your site one day
And here are some good ideas about passwords
If you are using a PHP version prior to 5.5 there is a compatibility pack available here
Also
Your script is at risk of SQL Injection Attack
Have a look at what happened to Little Bobby Tables Even
if you are escaping inputs, its not safe!
Use prepared statement and parameterized statements
Here is an example of how you can verify sha with mysql safely.
<?php
// Basic php MYSQL authentication with crypted password
$username = $_POST['username'];
$password = $_POST['password'];
$salt = "CrazyassLongSALTThatMakesYourUsersPasswordVeryLong123!!312567__asdSdas";
$password = hash('sha256', $salt.$password);
//echo $password;
// Mysql connection
$mysqli = new mysqli("localhost","mysqluser","mysqlpassword","mysqldatabase");
$stmt = $mysqli->prepare('SELECT userid FROM Users WHERE password = ? AND username = ?');
// (ss -> string, string) Always bind parameters and use prepared statement to improve security
$stmt->bind_param("ss", $password, $username);
$stmt->execute();
$stmt->bind_result($userid );
if (!empty($stmt->fetch())) {
// if fetch is not empty we have results and password hash was correct
echo "User was found";
} else
echo "User was not found";
$mysqli->close();
?>
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