So I'm very new to PHP and I'm still learning. I just learned about superglobals and using POST, GET, SESSION, COOKIES etc.
To test my current knowledge, I made a simple log in code. Where there are two pages, one for logging in, the other is the destination that can only be reached by logged in users. It's very simple, there is only one password "test pass" and it's checked through an if-statement. The username can be anything the user wants. I will obviously add more functionality to this project, like a sign up page, account info changing settings etc. But I can't do that without having my main code being solid. So my question is, security-wise, is this code okay? What would you do differently, and if there are non-security issues, I would also like to know.
Login Page:
<form method="post">
Username: <br>
<input type="text" name="user"> <br>
Password: <br>
<input type="password" name="pass"> <br>
<button type="submit" name="signin">Sign In</button>
</form>
<?php
session_start();
if (isset($_GET['logged']) && $_GET['logged'] == 'false'){
session_destroy();
header("Location: login.php");
}
if (isset($_POST['signin'])){ //form was submitted
//username check
if (!empty($_POST['user'])){ //username entered
$_SESSION['user'] = htmlspecialchars($_POST['user']);
} else { //no username entered
echo "You must enter your username!";
}
//password check
if (!empty($_POST['pass'])){ // a password was entered
if ($_POST['pass'] == 'testpass' && !empty($_POST['user'])){ // the password was correct and a username was entered
$_SESSION['logged'] = true; //user is logged in
header("Location: loggedin.php");
} else { // incorrect pass
echo "Incorrect Password!";
}
} else { //no pass entered
echo "You must enter a password!";
}
}
?>
Logged in page:
<html>
<head>
<?php session_start();
if (!$_SESSION['logged']){
header("Location: login.php");
} ?>
<title>Welcome <?php echo $_SESSION['user'] . "!";?></title>
</head>
<body>
Sign Out
</body>
</html>
It is okay for single user. You can improve security by adding md5() function.
eg: $_POST['pass']=md5('testpass'); and $_SESSION['user']=md5($_POST['user']);
If you want code for multiple user. Add mysql (database).
Are you going to be using a database to store users and other data? It'd be hard to evaluate the security of this if you're later going to be using a database.
In that case, you'd need to use prepared statements when querying the database and hashing when storing the passwords like Fred said. Prepared statements add protection against SQL injections which are very important to keep under control.
Another form of injection you need to worry about is script injection, or cross-site scripting (XSS). This is when you print user input back. You have added some protection for this using htmlspecialchars() on $_SESSION['user'] but you can do more, look more into it.
Related
I've created a login page and I'm using Cookies. Down below is the code for Login Page:
Register
<?php
session_start();
if(isset($_POST['submitted'])){
$errors = array();
$mysqli = new mysqli('localhost', 'db123', 'db123', 'db123');
$username = $_POST['username'];
$result = $mysqli->query("SELECT * FROM registered_users WHERE phone_number = '$username'");
$data = mysqli_fetch_assoc($result);
if($result->num_rows == 0) {
echo 'Username Not Found!';
} elseif($data['otp_verified'] === 'false'){
echo 'OTP Not Verified, Click Here To Verify Your Number';
}
else{
$encryptpass=md5($_POST['password']);
$cookie_username = $_POST['username'];
if($encryptpass == $data['password']){
echo 'Login Is Verified';
$Month = 86400 + time();
setcookie('user', $cookie_username, $Month);
header("location:dashboard.php");
}
else{
echo 'Login/Password Incorrect :(';
}
}
$mysqli->close();
}
?>
And Finally, Here's the code for dashboard.php and all other pages which are restricted:
<?php
session_start();
if(!isset($_COOKIE['user']))
{
header("location:index.php");
die();
}
?>
My Questions:
1. How Secure Is This Login System?
2. How I can improve it?
Thanks in advance :)
Here's a non-exhaustive list of problems/solutions:
Your code is difficult to read because it is not properly indented.
You should use prepared statemens to guard against SQL-injection.
You give hints to hackers by having different error messages. When the username is correct and the password wrong you say: "Login/Password Incorrect :(", but if the username is wrong you say: "Username Not Found!". That way a hacker can know if an username is correct, and half the job is done.
Better not use md5() for password encryption.
Use password_hash() for handling passwords.
Do not store the username in a cookie. Again, you're leaking information.
Don't use cookies, there's just no need to do that, use sessions and store information on the server, not on the user's machine.
You seem to have stored usernames as phone_number. So which one is it? It is either an username or a phone number, it cannot be both. Even if you use phone numbers as user names, call them what they are.
Sloppy coding: $errors = array(); is not used anywhere. You don't check the result of new mysqli(), the connection might fail. Same is true for $mysqli->query().
You take care to close the database, but then why don't you release the query result with $result->close();? Either do both, or none.
Security is a difficult topic, it's really hard to get it right, and what might be good today, might be bad tomorrow.
Its very unsecure
there can be sql injections (because the username goes directly to the databasa)
md5 is obsolete since years
you save the username unencrypted
Can anyone help me?
Im still newbie in using most of the php stuff here. I kinda having a problem with creating multi users using session.
What I want to do is this. An account exclusive only of admin and an account only for normal users.
Admin privileges will be able to access pages for admins only while normal users who logs in, will be able to access pages meant for users only.
So far Ive created a single user login credentials. Which is for admins only. Im really confused how do I add non-admin in order to access pages only for them.
Can anyone help me with this code?
This is the home page
<?php
//Initialize Session
session_start();
error_reporting(E_ALL ^ E_NOTICE);
//$name = $_SESSION['username'];
if(isset($_SESSION['username']))
{
header('Location: index_admin.php');
}
?>
This is the admin page
<?php
// Inialize session
session_start();
// Check, if username session is NOT set then this page will jump to login page
if (!isset($_SESSION['username']))
{
header('Location: index.php');
}
?>
This is the login form
<form action="login.php" method="post">
<input type="text" name="uname" placeholder="USERNAME . . . " autofocus/>
<br/>
<input type="password" name="pword" placeholder="PASSWORD . . . " />
<br/>
<center><input type="submit" name="submit" value="LOGIN" /><button type="reset" value="Reset" />RESET</button></center>
</form>
This is the login.php
<?php
session_start();
include("config.php");
$login = mysql_query("SELECT * FROM users WHERE (username = '" . mysql_real_escape_string($_POST['uname']) . "') and (password = '" . mysql_real_escape_string($_POST['pword']) . "')");
// Check username and password match
if (mysql_num_rows($login) == 1)
{
// Set username session variable
$_SESSION['username'] = $_POST['uname'];
// Jump to secured page
header('Location: index_admin.php');
}
else
{
// Jump to login page
header('Location: index.php');
}
?>
This is the database
user_tbl
id = 1
username = admin
password = 12345
Thanks in advance for the assitance.
It seems from your question that you'll use the same login page for both administrative users and non-administrative users. That's the case for which I'll offer an answer.
In the process of validating a particular user's name and password, you need to determine what privilege level that user has been granted. You might have a column called "privilege" in your user table.
usr_tbl needs to look something like this:
id username password privilege
1 admin W$^%^$%^%^% admin
2 reggel DJDT&646364 user
3 ollie DTHDHFGEERT user
Upon login, you'l read the usr_table and pull that user's value out of the column and store it as a session variable something like this:
$_SESSION['privilege'] = $privilege; /* from user table */
Then you can do logic like this to decide what your user should see, and what she should be able to do.
if ( 'admin' == $_SESSION['privilege'] ) {
// Jump to secured page
header('Location: index_admin.php');
}
else {
// Jump to login page
header('Location: index.php');
}
In later page views, if your session logic is functioning correctly, the $_SESSION['privilege'] variable should continue to be available.
p.s. mysql_ APIs for security code? Really?
You need to add a new field in your database for user type (admin/normal_user).
In your login script save the user type in session (admin/normal_user).
Now on every top of page check the session value of user type if it is admin let the page open and if it is normal_user redirect page to login.
ideally you need to expand on the data structure serving this code: Set up a table of users and a table of groups; the groups will imply access rights. When you submit the login page, check the database for the username, then:-
1) If no match, return to "access denied" screen
2) if match, xref with groups table to determine privilege level of this user. Then:-
2a) if admin, return to admin screen, setting appropriate session vars to store that decision.
2b) Else, return to normal user screen, ditto setting appropriate session vars.
Your core problem is that upon entering "the" homepage, you are simply checking if the username is set, and then taking the user to the admin screen. This is wrong. Try to split out your logic into smaller simpler steps, and consider the "if-else" logic in human terms. "What do I want to happen?" then "What do I need to know to ascertain how to do that?".
Good luck!
I use the same but I got one error
This page does not work local host has redirected you too often.
Try clearing your cookies.
ERR_TOO_MANY_REDIRECTS
<?php
// Include config file
require_once "config.php";
// Initialize the session
session_start();
// Check if the user is logged in, if not then redirect him to login page
if(!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true){
header("location: login.php");
exit;
}
$_SESSION['privilege'] = $privilege; /* from user table */
if ( 'admin' == $_SESSION['privilege'] ) {
// Jump to secured page
header('Location: index_admin.php');
}
else {
// Jump to login page
header('Location: index.php');
}
?>
<?php include "theme/header.tpl"; ?>
<div class="page-header">
<h1>Hi, <b><?php echo htmlspecialchars($_SESSION["username"]); ?></b>. Welcome to our site.</h1>
</div>
<p>
Reset Your Password
Sign Out of Your Account
Users
</p>
<?php include "theme/footer.tpl"; ?>
***the question has been answered. Here is the solution:
Ok, so I need to address a few things before answering the problem. First, the database is meant to have the numerous security flaws. This is a security class, and I am trying to hack into it on purpose. Then after I hack in, i'm supposed to prevent my own attacks.
Second thing I wish to clear up, is that this is a local database only, and never used by anyone but myself, classmates and instructor.
now for the answer: The first thing I was doing wrong was that the code was supposed to be logged into from the localhost webpage. I was trying to log in from the login.php file.
Second thing, was that I was mixing my mysql * and mysqli * methods. You cannot have multiple versions of the same method in the code.
Thanks to all who posted and for the fast responses.
A brief explanation of the problem:
I have been coding a database for a school project. I have the school database set up correctly, as per the instructor's review. The code I have is supposed to take a user input, check it with a "enrolled" list of students and compare the student ID and passsword to a pre-existing list.
After the check, the code is to start a session based on the student being enrolled. If the student is not enrolled it redirects them to the login page again.
The trouble I am having is that the code simply doesn't work. I get a error that says I have an issue on line 35 of my login.php file. Here is my code:
<?php
//Connect to DB
$con=mysql_connect("localhost","root","cravenreach","univ");
if (mysqli_connect_errno($con))
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
else
{
echo "Succeed to connect to MySQL. ";
}
//Session setup
session_start();
if( isset($_POST['sid']) && isset($_POST['password']))
{
$checklogin = mysql_query($con, "SELECT * FROM students WHERE sid=".$_POST['sid']." AND password=".$_POST['password']);
echo $count1 = mysql_num_rows($checklogin);
if($count1==1)
{
// auth okay, setup session
$_SESSION['sid'] = $_POST['sid'];
// redirect to required page
header( "Location: main.php" );
}
else {
// didn't auth go back to login
header( "Location: login.php" );
}
}
else {
// username and password not given so go back to login
//header( "Location: login.php" );
//This code is broken, causes a redirect loop.
echo "failure to start";
//header( "location: .php");
}
?>
here is the index.php code:
<html>
<body>
<form action="login.php" method="post">
<p><label>Student ID: <input type="text" name="sid"></label></p>
<p><label> Password: <input type="password" name="password"></label></p>
<input type="submit">
<input type="reset" value="Clear">
</form>
</body>
</html>
The error I receive is this: "Succeed to connect to MySQL. failure to start."
I understand that the code is not evaluating the login as true, and is skipping down to the last else statement. I just dont understand why.
To recap: My code will not actually accept the correct student input (or incorrect for that matter) and will not allow the user to login. It simply throws an error. My question is: what is wrong with my code? Is my query wrong, or implementation of the session?
You need to replace mysql_* functions into mysqli_* and also, You need add " end of the query before )
$checklogin = mysqli_query($con, "SELECT * FROM students WHERE sid='".mysqli_real_escape_string($_POST['sid'])."' AND password='".mysqli_real_escape_string($_POST['password'])."' ");
Your query should be like
//Prevnt from SQL injection
$sid = mysql_real_escape_string($_POST['sid']);
$password = mysql_real_escape_string($_POST['password']);
checklogin = mysql_query("SELECT * FROM students WHERE sid='$sid' AND password='$password'",$con);
Note MySQL is deprecated use MySQLi or PDO
I'm trying to create a webpage with users and information that can only be accessed by registered users. Is it possible to limit the files an unregistered user can see? If so, how? I already have a MySQL database with a connection in index.php. Here's what I have so far:
<head></head>
<body>
<h3>Signup Here:</h3>
<form method="post" action="userindex.php">
Please enter user name: <input type="text" name="username" value="" /><br />
Please enter password: <input type="password" name="password" value="" />
<br />
<input type="submit" value="Submit"/>
</form>
</body>
<?php
include ("dbroutines.php");
if (isset($_POST['username'])) {
if ($_POST['username']>'' && $_POST['password']>'' ) {
$q="insert into users (Name, Password ) values ('".$_POST['username']."', '".$_POST['password']."')";
echo 'query='.$q;
$conn=db_connect();
$result=$conn->query($q);
echo '<br />xxx'.$conn->error."xxx";
unset($_POST['username']);
unset($_POST['password']);
} else {
echo 'Please enter both username AND password!';
}
}
$q="select Name, Password from users";
$conn=db_connect();
$result=$conn->query($q);
echo 'xxx'.$conn->error."xxx";
if ($result){
echo '<hr />';
for ($count=0; $row=$result->fetch_row(); ++$count ) {
echo $count." Name=".$row[0]." password=".$row[1].'<br />';
}
echo '<b style="color:red;">there are '.$count.' users in your database!'.'</b><hr />';
}
From this, can you specify what kind of user gets access to certain files like the userindex.php?
I think verifying user is not the fool proof solution . You have to keep a token in the Session to remember that this user is registered user. You have to create a common php page , called Security.php where you will put the following code , because a smart user can directly type the URL and reach to your confidential pages. You need to include this page at the top of each php page you want to secure.
if (!isset($_SESSION['AuthId'])) {
header('Location:Login.php');
exit;
}
Yes. Query your database for someone with the given username and password using a query that would look something like this:
select * from users where Name = 'john.doe' and Password = 'hunter2' limit 1
If it yields any rows, the user exists, and you should let them in. If there are no rows, then that combination of username and password is invalid and you should not let them in.
That's the basics, but if you're actually going to put this into production, you'll want to make a few more changes:
Escape the data you're putting in the query appropriately or use prepared queries. As is, your code is vulnerable to an SQL injection attack. Say, for example, I tried to create an account with an apostrophe in the username or password. Your code would break. This could be leveraged for malicious means, too, so you really should patch that up.
The simplest way to patch it up would be to escape everything before you put it into the query, using, say, mysql_real_escape_string. That'll probably work, but even better (since the whole mysql_ family of functions is deprecated) would be to use prepared queries and PDO, as I've shown below.
Hash and salt your passwords so a database compromise (which could happen rather easily if the above vulnerability is left unpatched) will not reveal all the passwords.
Your code might then look like this:
// You'd probably want to put these in a separate configuration file.
$db = new PDO('mysql:dbname=test', 'my_mysql_user', 'hunter2');
// Make any errors throw an exception.
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$query = $db->prepare('select * from users where Name = :name limit 1');
$query->bindValue(":name", $_POST['username'], PDO::PARAM_STR);
$row = $query->fetch(PDO::FETCH_ASSOC);
if($row === FALSE) {
// User not in the database; don't let them in.
}
$calculatedHash = hash("sha512", $row['PasswordSalt'] . $_POST['password']);
if($calculatedHash === $row['PasswordHash']) {
// Password's right. Let them in.
}else{
// Password's wrong. Keep them out.
}
Further improvements would be to use, say, bcrypt rather than salted SHA-512.
You can put the one extra field in the loggin table name 'Role'.
Each login time. Check if it is Master user,then It can access the more access.
If it is extra user then limited access.
You got my point? Or any Query?
I've created a code to change a password. Now it seem contain an error.
When I fill in the form to change password, and click save the error message:
You forgot enter your userid!
Please try again.
I really don’t know what the error message means. Please guys. Help me fix it.
Here's is the code:
<?php # change password.php
//set the page title and include the html header.
$page_title = 'Change Your Password';
//include('templates/header.inc');
if(isset($_POST['submit'])){//handle the form
require_once('connectioncomplaint.php');//connect to the db.
//include "connectioncomplaint.php";
//create a function for escaping the data.
function escape_data($data){
global $dbc;//need the connection.
if(ini_get('magic_quotes_gpc')){
$data=stripslashes($data);
}
return mysql_real_escape_string($data);
}//end function
$message=NULL;//create the empty new variable.
//check for a username
if(empty($_POST['userid'])){
$u=FALSE;
$message .='<p> You forgot enter your userid!</p>';
}else{
$u=escape_data($_POST['userid']);
}
//check for existing password
if(empty($_POST['password'])){
$p=FALSE;
$message .='<p>You forgot to enter your existing password!</p>';
}else{
$p=escape_data($_POST['password']);
}
//check for a password and match againts the comfirmed password.
if(empty($_POST['password1'])) {
$np=FALSE;
$message .='<p> you forgot to enter your new password!</p>';
}else{
if($_POST['password1'] == $_POST['password2']){
$np=escape_data($_POST['password1']);
}else{
$np=FALSE;
$message .='<p> your new password did not match the confirmed new password!</p>';
}
}
if($u && $p && $np){//if everything's ok.
$query="SELECT userid FROM access WHERE (userid='$u' AND password=PASSWORD('$p'))";
$result=#mysql_query($query);
$num=mysql_num_rows($result);
if($num == 1){
$row=mysql_fetch_array($result, MYSQL_NUM);
//make the query
$query="UPDATE access SET password=PASSWORD('$np') WHERE userid=$row[0]";
$result=#mysql_query($query);//run the query.
if(mysql_affected_rows() == 1) {//if it run ok.
//send an email,if desired.
echo '<p><b>your password has been changed.</b></p>';
//include('templates/footer.inc');//include the HTML footer.
exit();//quit the script.
}else{//if it did not run OK.
$message= '<p>Your password could not be change due to a system error.We apolpgize for any inconvenience.</p><p>' .mysql_error() .'</p>';
}
}else{
$message= '<p> Your username and password do not match our records.</p>';
}
mysql_close();//close the database connection.
}else{
$message .='<p>Please try again.</p>';
}
}//end of the submit conditional.
//print the error message if there is one.
if(isset($message)){
echo'<font color="red">' , $message, '</font>';
}
?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
Please don't store the actual password in the database. Create a hash of the password and store it. When a user logs in, hash the incoming password and check if it matches the hashed password for the user. See http://phpsec.org/articles/2005/password-hashing.html for more info.
Also, it would be more secure to store the userid in the session and retrieve it from there rather than getting it from the form. Even if the input is hidden on the page there are any number of ways that it could be substituted. It leaves you with a small hole in the application where, if one user knows another user's id and password, they can change it in an undetectable fashion. That is, the password could be changed despite the fact that you have no record of that user having logged in. Even when getting the user id from the form (or the url), always check that the data they are operating on is their own, not someone else's unless, of course, they are a user with sufficient privileges.
It means that you didn't send along userid with your POST parameters. Presumably, your form didn't include an element with name userid. The error comes from this line:
if(empty($_POST['userid'])){
That error is displayed because of this test :
if(empty($_POST['userid'])){
$u=FALSE;
$message .='<p> You forgot enter your userid!</p>';
}
Which means the server doesn't receive a userid field from the form.
I'm guessing you should make sure there is such a field in your form -- and it'll have to contain the userid of the user for which you want to change the password.
Considering you probably don't want that field to be displayed, though, you'll use a hidden input :
<input type="hidden" name="userid"
value="<?php echo htmlspecialchars(HERE THE USERID); ?>" />
According to your code it means that the userid POST variable was empty. Verify the name of the field you use for it.