Jump to content

[SOLVED] Watertight method for password protected login areas?


Edward

Recommended Posts

 

Hi,

 

I'm creating a basic website which can only be viewed by users with a password. I need to make sure there is NO chance of unauthorised access. I'm using 4 php pages at the moment and I was wondering if someone can see if my code is fool proof, or if there is a better way?

 

index.php

<?php
if (isset($_POST['submit'])) {
if (strtolower($_POST['password']) == 'my_password') {
	session_start();
	$_SESSION['active'] = 'TRUE';
	header('Location: welcome.php');
} else {
	echo '<p>Error!</p>';
	// HTML page with form goes here
}
} else {
// HTML page with form goes here
}
?>

 

welcome.php

<?php
ob_start();
session_start();
if ($_SESSION['active'] != 'TRUE') {
unset ($_SESSION);
session_destroy();
header('Location: index.php');
}
// HTML Welcome message goes here
?>

 

log_out.php

<?php

session_start();
unset ($_SESSION);
session_destroy();
header('Location: end.php');

?>

 

end.php:

<?php
// HTML exit message goes here
?>

 

Thank you very much.

Link to comment
Share on other sites

There's a few things you could do.

 

Firstly, you need to run $_POST['password'], and username if you have one, through

 

$password = mysql_real_escape_string($_POST['password'])

 

Since someone can spoof the session $_SESSION['active'], I would also add the password session upon login:

$_SESSION['password'] = $password;

 

and on each page put in the if statement add:

 

if ($_SESSION['active'] != 'TRUE' && !isset($password)) {

 

Also, instead of isset($_POST['submit']), you could add a unique token.

 

On the form you could start a session like $token = mt_rand()

 

and on the processor page, make sure that session is there and the value is the same and it was on the previous page.

 

That's a few ideas

Link to comment
Share on other sites

 

Hey majocmatt, thanks for your comments, I'm going to work through them and see if I can add them in, however I've just noticed that you can click 'back' in the browser after logging out and you're still logged in! The only way around this I know is if I put a flash swf in the page, then for some reason it refreshes the page after 'back' is pressed and it logs you out, do you know if I can avoid this??

Link to comment
Share on other sites

 

Hmm, I've noticed that if I put a Flash swf on my 'private' page, clicking 'back' in the browser doesn't keep you logged in, this is true for Safari, Firefox and IE. However without the Flash swf, clicking 'back' keeps you logged in in Safari and IE. Does anyone know a fix to keep the user logged out when they click 'back'? It's really urgent! Thank you.

Link to comment
Share on other sites

Try placing -

 

session_cache_limiter('nocache');

 

before your session_start() calls.  This SHOULD send the proper headers so that neither proxy or browser caching will occur.  If you need caching enabled then hopefully someone else can give you a more creative solution.

 

Edit: 

 

You may want to try

 

session_cache_limiter('must-revalidate');

 

too, as I remember having issues with IE and the nocache directive.

Link to comment
Share on other sites

Did you put the session_cache_limiter('nocache'); between ob_start(); and session_start(); on your welcome.php file?  (It must be before session_start() calls and I believe AFTER ob_start() calls.) 

 

If that doesn't work try removing your ob_start() calls and see what happens.  If that still doesn't work try searching for different cache limiter directives, nocache should work in Safari if no other cache related headers are being sent first, but there may be other options you could use that I am not familiar with.

 

 

Link to comment
Share on other sites

 

  :) Going back to the first post where $password = mysql_real_escape_string($_POST['password']) was recommended, can I simply do this:

 

$username = mysql_real_escape_string($_POST['username']);
$password = mysql_real_escape_string($_POST['password']);
$sql = 'SELECT * FROM users WHERE username = "'.$username.'" AND password = "'.$password.'" ORDER BY username ASC;';

 

As I've seen people do the following, but I don't know what the advantage is as I don't understand what it's doing differently:

 

$link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password');
query = sprintf("SELECT * FROM users ('username', password') VALUES ('%s', '%s'')",
mysql_real_escape_string($product_name, $link),
mysql_real_escape_string($product_description, $link);
mysql_query($query, $link);

 

Any help on differences/advantages would be great!

Link to comment
Share on other sites

Use your first example and add 'LIMIT 1' to the end of the query. (After all, there can't be more than one username with that password in your setup, right?)  That along with the escaping and single quote usage in your first example is fine for SELECT statements.

 

Your second example appears to be partly from the php manual (as $product_name and $product_description don't fit your username/password variables.)  The reason they do it that way in the manual for that example is to prevent SQL Injection on an INSERT statement.

 

http://phpsec.org/projects/guide/3.html#3.2

Link to comment
Share on other sites

 

Yes that was taken from the PHP maual. Thanks for your help, I will use that for INSERT queries. I have noticed however that I have already validated by $_POST['username'] and $_POST['password'] variables and upon successful validation, I have converted them to $username and $password. Can I do the same thing with them (like below), or do they need to be $_POST?

 

$username = mysql_real_escape_string($username);
$password = mysql_real_escape_string($password);
$sql = 'SELECT * FROM users WHERE username = "'.$username.'" AND password = "'.$password.'" ORDER BY username ASC LIMIT 1;';

 

The guide you linked to says to always use single quotes, does it mean like this:

 

$username = mysql_real_escape_string($username);
$password = mysql_real_escape_string($password);
$sql = 'SELECT * FROM users WHERE username = \''.$username.'\' AND password = '\'.$password.'\' ORDER BY username ASC LIMIT 1;';

 

Or should I put the statement inside double quotes, and use single quotes around the values, like this:

 

$username = mysql_real_escape_string($username);
$password = mysql_real_escape_string($password);
$sql = "SELECT * FROM users WHERE username = '".$username."' AND password = '".$password.'" ORDER BY username ASC LIMIT 1;";

 

Lastly (sorry!...), if I'm going to do an INSITE query, should I always use this:

 

$link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password');
query = sprintf("SELECT * FROM users ('username', 'password') VALUES ('%s', '%s') LIMIT 1",
mysql_real_escape_string($username, $link),
mysql_real_escape_string($password, $link);
mysql_query($query, $link);

 

Is it as straight forward as %s for a varchar, %d for an integer?

 

THANK YOU very much!

Link to comment
Share on other sites

Personally I would use -

 

$sql = "SELECT * FROM users WHERE username = '".$username."' AND password = '".$password.'" ORDER BY username ASC LIMIT 1;";

 

simply for readability.  But your example with all single quotes -

 

$sql = 'SELECT * FROM users WHERE username = \''.$username.'\' AND password = '\'.$password.'\' ORDER BY username ASC LIMIT 1;';

 

may have a tiny performance benefit. (As php doesn't have to evaluate single quoted strings for variables.) 

 

And again, for readability I would use the $username and $password variables as you have them at the sacrifice of the tiny bit of overhead required to assign a new variable.  (It also makes it easier to add further checks (i.e. regex, etc.) on them in the future.)

 

And yes, you would use %d for integers and %s for strings.  (and %f for float, etc.)  There should be a list in the php manual under sprintf that shows the different place holders.  The reasoning behind using that being (AFAIK) that sprintf will throw an error if something  other than that type is injected in that field.  (Though for all strings it seems useless IMHO.)

Link to comment
Share on other sites

 

Regarding the following code for the INSERT query:

 

$link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password');
query = sprintf("INSERT INTO users ('username', 'password') VALUES ('%s', '%s') LIMIT 1",
mysql_real_escape_string($username, $link),
mysql_real_escape_string($password, $link);
mysql_query($query, $link);

 

Can I do it without the 'link' section as follows:

 

query = sprintf("SELECT * FROM users ('username', 'password') VALUES ('%s', '%s') LIMIT 1",
     mysql_real_escape_string($username),
     mysql_real_escape_string($password);
mysql_query($query);

 

This is because I already have a function set up for my connection which I want to call.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.