Need a bit of help with a form. I have created a form which require log in. Once a person has logged in they complete the form and then someone else checks the form and enters there password before the form is submitted.
I have set up some rules which checks the fields are completed correctly and I want to write some code that will check the password field is completed and then check it against the stored passwords in the database.
So far I have got this.
if (!empty($_POST['password']))
{
/*connect to database to check password is valid*/
$user_name = "contains username for database";
$pass_word = "contains password";
$database = "name of database";
$server = "localhost";
$db_handle = mysql_connect($server, $user_name, $pass_word);
$db_found = mysql_select_db($database, $db_handle);
if ($db_found) {
$uname = quote_smart($uname, $db_handle);
$pword = quote_smart($pword, $db_handle);
$SQL = "SELECT * FROM masterpass WHERE password = $password";
$result = mysql_query($SQL);
$num_rows = mysql_num_rows($result);
if ($result) {
if ($num_rows > 0) {
continue;
}
else {
$error = true;
}
Not sure if I am going about this the right way so any help would be great.
Thanks in advance
Matt
for starters, first you create $pword:
$pword = quote_smart($pword, $db_handle);
and in your query you use $password.
$SQL = "SELECT * FROM masterpass WHERE password = $password";
This can't work.
Secondly, you should ask for username AND password in your query.
Last but not least: never save a password in clear text in your database. Generate a MD5 hash!
I have set up some rules which checks the fields are completed correctly and I want to write some code that will check the password field is completed and then check it against the stored passwords in the database.
No, you don't. Checking to see if the password is already in the database is not a very smart thing to do, as that opens your application to brute-forcing attacks. I could use your form to determine which passwords are used, and if I can get a list of your users, I can try each of those passwords to each of those users and get access.
Secondly, quote_smart is probably not smarter than mysql_real_escape_string. Use that instead.
Thirdly, as Sascha already mentions, please generate a hash. I wouldn't use MD5, but sha1 instead, but even using MD5 without salt already increases the security in your form dramatically.
My mantra on validating passwords is: make sure it's longer than 7 characters, that's it. Don't make assumptions on what password people should use. I hate it if I type in a password and some validation routine tells me I can't use {^ in my password.
Related
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
I'm switching over to PDO and trying to make my passwords in the MySQL database a little bit more secure, but unfortunately I've run into a little bit of a problem.
When a user registers, their password is treated as follows:
$pass = sha1($_POST['pass']);
And when a user logs in, the password they provide is treated exactly the same ($pass = sha1($_POST['pass'];)
The idea is then that I compare the two, and if they match, the user is logged in. The difficulty is, even if I enter the same password - "password", for instance - the encrypted password put into the database on registration does not match the encryption of the password when the user attempts to log in.
Does anyone know what the issue might be?
Full code:
$user = $_POST['user'];
$pass = sha1($_POST['pass']);
echo $pass; // This was just to check the two passwords
$db = new PDO('this is all correct');
$query = $db->prepare('SELECT pass, id FROM users WHERE user=:user');
$query->bindParam(':user',$user);
$query->execute();
$result = $query->fetch();
$storedpass = $result['pass'];
$storedid = $result['id'];
if($storedpass === $pass) {
header("Location: index.php");
}
else {
echo "Something went wrong";
}
sha1 should not be used to hash passwords. See the notice in the docs. You should use the new password_hash function instead, and the matching will be handled for you by password_verify.
Switching to the new hashing functions would likely solve your password validation issue while at the same time making your app much, much more secure.
If your version of PHP is less than 5.5, the new functions aren't available. A version for PHP 5.3.7+ is available on Github https://github.com/ircmaxell/password_compat.
You'd actually be much better off doing something like this:
$user = $_POST['user'];
$pass = sha1($_POST['pass']);
echo $pass; // This was just to check the two passwords
$db = new PDO('this is all correct');
$query= $db->prepare("SELECT id FROM users where user=:user AND pass=:pass");
$query->execute(array(':user' => $user, ':pass' => $pass));
if ($query->rowcount() == 1){
// authenticated
}else{
// not authenticated
}
Don't know if this will solve your problem though.
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.
What I want to be able to do is: When a user enters their username and password in the form on the index.html page, if they match what is in the DB, then they get sent to the next page; userlogin.php.
If their username or password is incorrect then they are asked to re-enter their details on the index.html page, and displaying an error like, "Your username is Incorrect" or "Your password is Incorrect" above the form text box. I can paste this code if required.
Can I change this text font color as well, to red for example?
This is the code I currently have for the userlogin.php page
<?php
mysql_connect("Server", "root", "Gen") or die("Couldn't select database.");
mysql_select_db("generator") or die("Couldn't select database.");
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * FROM users WHERE Username = '$username' AND Password = '$password' ";
$result = mysql_query($sql) or die(mysql_error());
$numrows = mysql_num_rows($result);
if($numrows > 0)
{
echo 'Your in';
}
else
{
echo 'Your not in';
}
?>
There as sooo many things wrong with this code:
1- you have an SQL injection hole.
If I enter ' or 1=1 LIMIT 1 -- as a username, I will always get access, no matter what.
Change your code into.
$username = mysql_real_escape_string($_POST['username']);
$password = mysql_real_escape_string($_POST['password']);
See: How does the SQL injection from the "Bobby Tables" XKCD comic work?
2- you are storing the password in the clear
This is a huge no no. Combined with the SQL-injection hole, it will take a hacker 5 minutes to get a list of all usernames and passwords on your site.
Store the password as a salted hash.
I like to use the username as the salt.
You store the password hash using:
INSERT INTO users (username, passhash)
VALUES ('$username', SHA2(CONCAT('$password','$username'),512))
And you test the user credentials using:
SELECT * FROM users
WHERE username = '$username' AND
passhash = SHA2(CONCAT('$password','$username'),512)
See: Secure hash and salt for PHP passwords
And: What is "salt" when relating to MYSQL sha1?
BTW, use SHA2 with a 512 keylength, SHA1 is no longer secure, and MD5 is even more broken.
3- A login can only ever match against 1 user
This code:
if($numrows > 0)
Makes no sense, if you get 2 rows out of the database, that's a clear sign someone has hacked your system. The test should be:
if($numrows > 1) { //send email to sysadmin that my site has been hacked }
else if ($numrows = 0) { echo "wrong username or password" }
else { echo "welcome dr. Falken" }
4- Don't die if there's an error, call a routine to restart the connection or something
This code:
$result = mysql_query($sql) or die(mysql_error());
Is fine in testing, but in production you should do something like
$result = mysql_query($sql);
if ($result) {
//do the deed
} else {
//call error recovery routine
}
The error recovery routine should reconnect to the server, log a error in the logbook. Is the error cannot be fixed, it should send an email to the sysadmin and only then die the server.
First of all, your code is vulnerable to SQL injection. Use PDO and prepared statements to fix this. Second of all, you're appearantly storing usernames unencrypted. This is very unsafe. Use a hashing function to encrypt the passwords, and encrypt the submitted password before running the query to get a match. Coloring the output is simple:
echo '<span style="color:red">Your not in</span>';
And use sessions to actually log the user in. After successfully querying the user table for the username/password combination, store the returned user_id in the $_SESSION variable. On each page that needs to be secured, just check for the existence of $_SESSION['user_id']; if it isn't there, your user needs to login so redirect him to the login form.
That should about do the trick for ya ;)
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?