I am creating a login form. I am learning how to use SHA-1 to encrypt passwords. I used SHA-1 to encrypt the password that the user created during registration. In the database I inputted pretend username and password data, to have something to work with. I'm having problems getting my login form to work.
// Database Connection
$con = getConnection();
$sqlQuery = mysql_query("SELECT count(*) from Customers
WHERE Email = '$email' and Password = sha1('$passLogin')")
// Executing query
$result = $con->mysql_result($sqlQuery, "0");
if ($result == 0) {
echo "Can not login, try again.";
} else {
echo "Login Good!";
}
I am learning how to use sha1 to
encrypt passwords.
... use sha1 to hash passwords. Hashing is different from encryption. Encryption is reversible, hashing isn't. (or shouldn't be). Now, ...
You have to make sure the passwords in the database are hashed.
Usually you do the hashing on the PHP side.
You should use salting to make rainbow table attacks unfeasible. Read Just Hashing is Far from Enough for Storing Password
That said, I would do the authentication part like this:
$hashedAndSalted = sha1($passLogin . $yourSalt);
$sqlQuery = mysql_query("SELECT Email FROM Customers WHERE Email = '$email' AND Password = '$hashedAndSalted'");
if (mysql_num_rows($sqlQuery) == 1) {
echo 'Login successful';
} else {
echo 'Could not login';
}
Replace your query with this:
$sqlQuery = mysql_query("SELECT count(*) from Customers
WHERE Email = '".$email."' and Password = '".sha1($passLogin)."'");
Remember to always concatenate strings and variables manually, don't rely on PHP to do it for you. Also, you forgot the semicolon ; after that line. Every line must be appended with a semicolon in PHP.
On a separate note if you have not sanitized your form inputs you are wide open for SQL injection.
If user enters the following for Email field:
' or '1'='1
They will be logged in :)
You should be using mysql_real_escape_string to escape $email and $passLogin or even better use prepared statements.
Related
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Secure hash and salt for PHP passwords
I am working on a PHP script for my site, the site it's self is up and running. The problem I have is that the registration on the website is for plain text passwords. Obviously this is very weak security. I am hoping someone can help me convert it so I can use a hash password.
I have included part of the registration code that I think counts. I did not include all code on the page as I did not think it relevant but will supply if someone thinks it will help.
require 'include.inc';
if ($signup) {
if ($signup[repassword] != $signup[password]) {
$err_msg = "Your passwords do not match.";
error($err_msg);
}
if(!preg_match("^[_\.0-9a-z-]+$/i^", $str)) {
$msg = 'Invalid Username! Usernames can consist of letters and numbers only';
}
if(!preg_match("^[_\.0-9a-z-]+$^",$signup[password])) {
$err_msg = "Invalid Password! Passwords can consist of letters and numbers only.";
}
if(!$signup[password] || !$signup[username] || !$signup[email] || !$signup[username])
$err_msg = "Oops! You forgot some important fields!";
if (!$err_msg) {
$usercheck = #mysql_query("INSERT INTO user values(
'NULL','$signup[fname]','$signup[lname]',
'$signup[username]','$signup[password]','$signup[email]', 1, ".$pointInc.", '$signup[referral]', NOW(), 'n', 'y')");
// done, you are entered correctly, Now Enter the points and URL info
$sql = "Select id from user where username='$signup[username]'";
$result = mysql_query( $sql );
if ( $result != false )
{
while ( $data = mysql_fetch_assoc( $result ) )
{
$point_set = $data['id'];
}
} else {
echo mysql_error();
}
// add rerral points
if ($signup[referral]) {
$referralSql="UPDATE points SET points=points+ ".$refPoints . " WHERE userid=".$signup[referral];
$result = mysql_query( $referralSql );
if ( $result != false )
{
} else {
echo mysql_error();
}
}
// add URL
$sql="INSERT INTO url_table ( userid, website, active, datechanged) VALUES ($point_set,'".$signup[site_url]."','n', '".date("Ymd")."')";
$result = mysql_query( $sql );
if ( $result != false )
{
} else {
echo mysql_error();
}
// add points
$sql="INSERT INTO points (userid, username, points) VALUES ($point_set,' ',$signPoints)";
$result = mysql_query( $sql );
if ( $result != false )
{
} else {
echo mysql_error();
}
}
echo mysql_errno().": ".mysql_error()."<br>";
if (!$usercheck) {
$err_msg = "Database error:<br>There was an error entering your account.<br>It is possible that username or Email already exists, please try another one.<br>";
} else {
include ("reg.php");
exit;
}
}
if (!$err_msg) {
// done, you are entered correctly
}
pageHeader($title, $bgColor, $styleSheet);
?>
The basic principle is quite easy:
1 . When a user registers, don't store the plaintext password, but hash(password).
$query = $pdoObject->prepare('INSERT INTO users (UserName, Password) VALUES (:u, :p)');
$query->bindParam(':u', $_POST['username']);
$query->bindParam(':p', hash($_POST['password']));
// Note that we don't store the password, we store the hash of the password. Once this script is done executing, no one involved in the website (except for the original user) will know that the password is
$query->execute();
2 . When a user attempts to log in, calculate the hash of the entered password with the hash stored in your user database. If both hashes match, the password is correct.
$query = $pdoObject->prepare('SELECT * FROM users WHERE UserName = :u AND Password = :p');
$query->bindParam(':u', $_POST['username']);
$query->bindParam(':p', hash($_POST['password']));
// We locate the original user by searching for the hash of the password that they typed in
So much for theory. Some practical issues you should consider:
Many tutorials suggest using MD5 of SHA1 as hash functions. However, these are not secure. Check the PHP hash library (especially the hash() function) for available hashing algorithms.
You should also consider using salted passwords. For each registered user, create a random string (the salt), concatenate this string with the user's password and then hash both password and salt (the salt needs to be saved too, because you need it again when authenticating the user).
You can use PDO to make your SQL more secure. This will protect you against something called SQL Injection. If you don't do this, then users will be able to mess up your website by entering characters such as apostrophes (').
You can use md5 function to create a hash for your passwords, example:
$password = '12345';
$password = md5($password);
You save this hash at the database and when you will check user and password for login you do this
$post['password'] = md5($post['password']);
and check if is equal of the hash saved in the database.
I know that md5 is not the best hash but is simple and has a good level of security
Use crypt for hashing passwords.
Use md5 for that http://php.net/manual/en/function.md5.php
Also look up uniqid http://php.net/manual/en/function.uniqid.php
It's always a bad practice to store the password in plain text in your database. Check this other question:
What are the best practices to encrypt passwords stored in MySql using PhP?
some opinions don't think md5 or SHA-1 breakable, try to salt them.. search that.
What am I doing wrong here:
<?php
if (isset($_POST['submitted'])) {
$errors = array();
require_once ('mysql_connect.php');
session_start();
$username = $_POST["username"]; // This is the inputted username from the form in Login.html
$password = $_POST["password"]; // This is the inputted password from the form in Login.html
if (empty($errors)) {
$query="SELECT username FROM users WHERE username='$username' AND password='SHA($password)'";
$result = mysql_query($query);
// Mysql_num_row is counting table row
if (mysql_num_rows($result) == 1) {
$_SESSION["username"] = $username; // Creates a cookie saving the username
$_SESSION["loggedIn"] = true; // Creates a cookie saying the user is logged in
// Show thank you message
echo '<h3 style="color:green;">Thank You!</h3>
<span style="color:green;">You have been logged in.</span>';
} else {
echo '<font color="red">You could not be logged in, please make sure your username and password is correct.</font>';
foreach ($errors as $msg) {
echo " - <font color=\"red\">$msg</font><br />\n";
}
}
} else {
echo '<font color="red"><h3>Error!</h3>
The following error(s) occured:<br /></font>';
foreach ($errors as $msg) {
echo " - <font color=\"red\">$msg</font><br />\n";
}
}
}
?>
I get a:
Warning: mysql_num_rows(): supplied argument is not a valid MySQL result resource in /login.php on line 19
Also is the way I SHA the password correct?
The problem is that your MySQL query is causing an error, which means that your $result doesn't actually contain a result resource.
You need to remove the '' from around SHA($password) in your query, and instead put them around the password value, like so:
$query="SELECT username FROM users WHERE username='$username' AND password=SHA('$password')";
Also is the way I SHA the password correct?
That depends on how the passwords were hashed when they were inserted into the database. MySQL's SHA() is the same as its SHA-1():
Calculates an SHA-1 160-bit checksum for the string, as described in RFC 3174
Which is also the same as PHP's sha1(); so, for example, if the passwords in the database are SHA-1 hashes that were created using PHP's sha1(), it should be fine.
Side Notes
You should use PHP's crypt() or hash() for hashing passwords, rather than SHA-1. For example usage, refer to the PHP documentation.
You should be cleaning/escaping all user-provided data before using any of it in a database query. This is to stop SQL injection attacks. Better yet, use prepared statements and parameterized queries. Refer to this answer for more information.
Don't use '' by SHA function
$query="SELECT username FROM users WHERE username='$username' AND password='SHA($password)'";
And offcourse don't remember escape your data.
Why did you put a # in #mysql_query($query); ? If you have a MYSQL error you should handle it correctly and not ignore it (I assume you have an error there). It would help you understand where your bug is coming from.
Also, you can do the SHA in PHP (which depends on your architecture could be better or worse for your project).
http://php.net/manual/en/function.sha1.php
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 ;)
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.
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?