Can you experts give me some thougths on this code? Some security hole i have missed?
Can you see any potential threats? Something i can do better?
I'm still learning :) Thanks
<?php
if (isset($_POST['username'])) {
$username = mysql_real_escape_string($_POST['username']);
$password = mysql_real_escape_string($_POST['password']);
$password2 = mysql_real_escape_string($_POST['password2']);
$encrypted_password = md5($password);
// remove eventuakl space
foreach($_POST as $key => $val) $_POST[$key] = trim($val);
// check if username is taken
$query = mysql_query("SELECT COUNT(*) FROM users WHERE username = '$username'");
if (mysql_result($query, 0) > 0) {
$reg_error[] = 0;
}
// make sure username only cosist of at least 3 letters, numbers or _ -
if (!preg_match('/^[a-zA-Z0-9_-]{3,}$/', $username)) {
$reg_error[] = 4;
}
// check for empty fields
if (empty($username) || empty($password) || empty($password2)) {
$reg_error[] = 2;
}
// check if the passwords match
if ($password != $password2) {
$reg_error[] = 3;
}
// save if error is unset
if (!isset($reg_error)) {
mysql_query("INSERT INTO users (username, password, registered, registration_ip)
VALUES('$username', '$encrypted_password', '".time()."', '".$_SERVER['SERVER_ADDR']."')");
$_SESSION['id'] = mysql_insert_id();
header('refresh: 3; url=/home');
}
}
?>
Login.php
if (isset($_POST['username'])) {
$username = mysql_real_escape_string($_POST['username']);
$password = mysql_real_escape_string($_POST['password']);
$md5_password = md5($password);
$query = mysql_query("SELECT id FROM users WHERE username = '$username' and password = '$md5_password'");
if (mysql_num_rows($query) == 0) {
header("Location: ".$_SERVER['REQUEST_URI']."");
exit;
}
// set session
$_SESSION['id'] = mysql_result($query, 0, 'id');
header("Location: /");
exit;
You didn't salt the password.
Also, md5() is considered not strong enough for hashing passwords.
Use hash('sha256', $password) instead.
I assume you're serving this on https, though you don't mention whether you do -- if you're not, username and password travel on the open net in the clear, and that's definitely not very safe.
There's a race condition -- you check whether the username is taken, first, and only later do you insert it. You should use a transaction, a least, and ideally just try to insert (with the uniqueness constraint imposed by the database) and catch the error in case of duplicates. And, you should do this only after all other sanity checks, i.e. when you've convinced yourself that, apart from possible duplicates, the registration attempt is OK.
Little bobby tables will give you a lot of headaches since you do not check for username validity.
You need to salt the password.
This is placed in the wrong place. Move it up a few lines before the $_POST vars are used.
// remove eventuakl space
foreach($_POST as $key => $val) $_POST[$key] = trim($val);
You are escaping the password fields for no reason. They are not being sent to the database. md5($password) is going to the database and it is not escaped.
EDIT: On the login side, you should be trimming anything you are trim on the registrations side.
Your error checking is out of order. I'd do the error checking in this order:
Check for empty fields
Check that the fields have valid values (filtering input)
Escape the fields with mysql_real_escape_string before using the fields in SQL
Check for the user in the SQL table
If you find an error don't continue with further checks. Guard each error check similar to your guard on the final INSERT statement.
You have no edits on the password fields besides using mysql_real_escape_string?
You should do mysql_connect before using mysql_real_escape_string. mysql_real_escape_string will use the connection to determine the character set of the connection. The character set will identify which characters to escape.
You should use parameters instead of building your sql dynamically. It will help prevent sql injection attacks. Little bobby tables will get you.
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 am using PHP and MySQL to create a login system. The page only requires the user to login and their is no option for them to register.
I have the passwords stored in my database already as plain text and i am aware this is not safe at all.
What steps would i take to make this more secure and hash the password that is already stored in the database?
Would i need to go back and alter my database?
Here is some code i am using at the moment:
if($_SERVER['REQUEST_METHOD'] == 'POST') {
if (empty($_POST['username']) || empty($_POST['password'])) {
$error = "Enter Username and Password";
} else {
$username = $_POST['username'];
$password = $_POST['password'];
include('dbconx.php');
$sql = "SELECT * from admin where password='$password' AND username='$username'";
$result = mysqli_query($con,$sql) or die(mysqli_error());
$count = mysqli_num_rows($result);
if ($count == 1) {
$_SESSION['login_user'] = $username; // Initializing Session
header("location: confirm.php"); // Redirecting To Other Page
} else {
$error = "Username or Password is incorrect";
}
mysqli_close($con); // Closing Connection
}
}
The important points were already written in the comments.
To sum it up:
password_hash and password_verify are the functions to use in PHP
You'd have to write a script which goes through all your already stored passwords (in plaintext) and hash them with password_hash and resave them to the database.
You should read about SQL-injections. Use (at least) mysqli_escape_string. Much, much better ist to use prepared statments. (http://php.net/manual/en/pdo.prepared-statements.php)
I don't know your database-structure, but normally you don't need to alter anything there, but you will have to check your password field is large enough to hold the hash VARCHAR(255) is recommended as password_verify() may get changed in future versions of PHP and this should be big enough to hold any future hashing output.
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.";
}
?>
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.
I'm wondering how I can make this code safer, I'm using it as login.php:
if(isset($_POST["username"]) and isset($_POST["password"])) {
if($_POST["username"] == $adminusr && $_POST["password"] == $adminpass){
I want to make it a little more safe to prevent sql-injections and such. Do you have any ideas ? I'd like to learn more about making safer sites.
Thank you dudes and dudettes
Edit:
Sorry I didn't post all the code needed, but here is the complete code:
<?php
session_start();
include_once("../include/config.php");
if(isset($_POST["username"]) and isset($_POST["password"])) {
if($_POST["username"] == $adminusr && $_POST["password"] == $adminpass){
$_SESSION['admin_user'] = $adminusr;
$_SESSION['admin_password'] = $adminpass;
}
else {
echo "Wrong Username or Password";
}
}else if(isset($_GET['act']) && $_GET['act']=='out') {
unset($_SESSION['admin_user']);
unset($_SESSION['admin_password']);
session_destroy ();
}
if($_SESSION['admin_user'] == $adminusr && $_SESSION['admin_password'] == $adminpass){
$_SESSION['testdd'] = 'test';
header("location:index.php");
exit;
}
?>
Thank you once again :)
If you are using $_POST['username'] in a query the following code will keep you save from SQL-injection.
$username = mysql_real_escape_string($_POST["username"]);
$password = mysql_real_escape_string($_POST["password"]);
$query = "SELECT * FROM users
WHERE users.username = '$username'
AND users.Passhash = SHA2(CONCAT(users.id,'$password'),512) ";
$result = mysql_query($query);
....
Note that you need to use mysql_real_escape_string() with mysql_query
and mysqli_real_escape_string() with mysqli_query.
Even better is to use PDO with php5, see: http://www.php.net/manual/en/book.pdo.php
Handling passwords in MySQL
Note that is strongly recommended not to store passwords in the clear in your database.
Always store a hash (preferably using SHA2) in your database and use a salt.
See: https://stackoverflow.com/search?q=hash+salt+mysql
For more info on this.
I think you code should be like this:
if(isset($_POST["username"]) and isset($_POST["password"])) {
$handle = mysql_connect($host, $user, $pass);
mtsql_select_db($db, $handle);
$query = "SELECT user FROM table_users WHERE user='{$_POST["username"]}' AND password=MD5('{$_POST["password"]}')";
$result = mysql_query($query, $handle);
if(mysql_num_rows($result) == 1)
{
What you need here is to escape special charcarter using mysql_real_escape_string() or PDO prepared statement, so we change this:
$input["user"] = mysql_real_escape_string($_POST["username"]);
$input["password"] = mysql_real_escape_string($_POST["password"]);
$query = "SELECT user FROM table_users WHERE user='{$input["user"]}' AND password=MD5('{$input["password"]}')";
.
.
.
You may also use addslashes() function, but it may be sufficient enough, I am quoting from this:
addslashes adds slashes to characters
that are commonly disturbing.
mysql_real_escape_string escapes
whatever MySQL needs to be escaped.
This may be more or less characters
than what addslashes takes care of.
You should use mysqli_real_escape_string to escape special characters (assuming you are querying database). E.g. $password = mysqli_real_escape_string($link, $_POST['password']);. Otherwise, it seems fine.
Your code doesn't show what you are actually doing with the database.
If you use a regular mysql_query, you need to encode unwanted characters, quotes (",') for example.
You also need to keep in mind, that people might want these characters in their passwords, so you need to store them in the DB encoded in some way.
Probably an MD5 hash, or just regular entity encoding (see below).
htmlentities($pass,ENT_QUOTES,'UTF-8')
(!get_magic_quotes_gpc()) ? mysql_real_escape_string($item):$item;
You should still use variable binding, that helps avoiding any SQL injections.
Check out this introduction to PDO, its really useful.