Log in

View Full Version : Am I right about PHP sessions?



auriaks
06-21-2010, 08:34 PM
Hi all, again :)

I am working with new SMALL project and I want to make some thing clear:
Login page:


$password = md5($_POST['password']);
$nick = $_POST['nick'];

$password = mysql_real_escape_string($password);
$nick = mysql_real_escape_string($nick);
$nick = strtolower($nick);

if(info is INcorrect) {ERROR} else {
session_start();
$_SESSION['nick'] = $nick;
$_SESSION['password'] = $password;
$_SESSION['authID'] = 'your_special_ID';
(Redirect to safe_page.php)
}


What I want? Protection level :)

1. I think variables are safe... IS IT?
password is md5;
nick, pass = mysql_real_escape_string
nick = strtolower.

2. I used session_start(); Do I need something more to start session?
3. $_SESSION variables which I will use. Are thay correct?
4. IS all of the login page script secured?

OK, now - other pages, which I will keep in safe:
safe_page.php


if(isset($_SESSION['authID'])) {
include $_SERVER['DOCUMENT_ROOT'] . '../db_conn.php';
$dates = date("Y-m-d");
$times = date("H:i:s");
$upnick = $_SESSION['nick'];
(access granted)
} else {
header("Location: ../login.php"); // Not allowed
}


1. Is this session right?
2.How much is it safe?

What can you offer to increase my security level?

I want to THANK YOU ALREADY, because there Are a lot of questions :D

Also, all suggestions are welcome :)

djr33
06-22-2010, 12:18 AM
Your questions are somewhat confusing, and parts of your script are not real PHP.
if(info is INcorrect) {ERROR} else {
Assuming that those parts are correct, then yes, it looks like your script will work.

However, one problem is that you should do session_start() at the beginning of any page that will operate independently, and NOT within an if statement. It's not a problem to start a session if they don't log in-- just don't store their login info yet. Then you can check isset($_SESSION[...]) on other pages.

traq
06-22-2010, 01:29 AM
Here's a good, easy to follow (as easy as possible, anyway) article about sessions and session security (http://shiflett.org/articles/the-truth-about-sessions).

How "safe" a session is depends largely on how secure you actually need your session to be. Are you dealing with records of people's favorite colors? Their name and address? Their bank information? Obviously, some things need more security than others.

The main thing that needs to be address in your (vague) code example is how you verify your user throughout the session. It's great that you save the user's nickname, password, and authID in the session, but if you later use that info without double-checking it, there's no point.

Specifically: The first thing you need to do on every "secure" page is verify and re-validate the user's info (cookies are a common and fairly secure way to do this).

Beyond that, you'd have to finish writing your script before we could tell you how effective it was.

auriaks
06-22-2010, 09:15 AM
Here's a good, easy to follow (as easy as possible, anyway) article about sessions and session security (http://shiflett.org/articles/the-truth-about-sessions).

How "safe" a session is depends largely on how secure you actually need your session to be. Are you dealing with records of people's favorite colors? Their name and address? Their bank information? Obviously, some things need more security than others.

The main thing that needs to be address in your (vague) code example is how you verify your user throughout the session. It's great that you save the user's nickname, password, and authID in the session, but if you later use that info without double-checking it, there's no point.

Specifically: The first thing you need to do on every "secure" page is verify and re-validate the user's info (cookies are a common and fairly secure way to do this).

Beyond that, you'd have to finish writing your script before we could tell you how effective it was.

You say that I need to check that user info is right in all pages?
what's the point?

djr33, You mentioned that I should always create a session, but check the isset($_SESSION[...])... IS there a difference between making session, checking $_SESSION variable and Not creating the session?

djr33
06-22-2010, 10:12 AM
In all pages that have user authentication. If it's another unrelated page without any secure items, you do not need sessions or to verify anything.


session_start() begins a session. That means that PHP is operating sessions and they work. Then after that, you can USE $_SESSION to do whatever you'd like. Adding session_start() to the top of any page is fine. It doesn't "do" anything except start the setup for using sessions...

auriaks
06-22-2010, 10:27 AM
OK :)

Btw, I have just finished reading "sessions and session security"...

How to Correctly use Fingerprint and HTTP_USER_AGENT? Could you link me to a tutor of these?

Also, I always was skeptical about cookies, because they are saved in the CPU and can be revealed, and they need browsers cookie enabling.

Do I really need use them to provide higher sessions secure?

Thanks for your time, djr33 :)

djr33
06-22-2010, 10:33 AM
1. User agent: store $_SERVER['HTTP_USER_AGENT'] in the session to check that the user is still the same person and the session has not been hijacked. (If someone finds/steals the session id, they could use someone else's session.)

2. The important part is that you check the session every time you use it. Cookies are how the session is stored on the user's computer: usually just an id. The session data (in $_SESSION) is hidden on the server and the user cannot see it. So use the cookies just as an extra thing to verify the user. It's not that you use both sessions and cookies for all the data.

auriaks
06-22-2010, 10:39 AM
So, on every page top must be?:


<?php
start_session();
$_SESSION['authID'] = 'your_special_ID';

$_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);

$fingerprint = 'SHIFLETT' . $_SERVER['HTTP_USER_AGENT'];
$_SESSION['fingerprint'] = md5($fingerprint . session_id()
?>


What I can change in this script to make it more authentic?

traq
06-22-2010, 02:29 PM
The idea behind checking the user-agent is that it's a string that is usually consistent on a single browser, but often different between different browsers. Say an attacker stole your user's session ID - they're probably not using the exact same browser and version, meaning they'd have to fake that too.

I wouldn't be too worried about advanced stuff like that unless you've got some info that is seriously worth protecting - and if you did, you might want to hire someone who has experience doing it instead of trying to figure it out yourself.

To answer your question, the reason you check the user's credentials on every secure page is to make sure you're still dealing with the right person. Otherwise, someone might have stolen the session, and you wouldn't have any clue. Likewise, by not checking on subsequent pages, you're just "assuming" that the user got to that page by loging in. What if they typed the URL directly and bypassed the login page? Having the user's session info doesn't do any good at all unless you check against it.

The number one internet security lesson is this:

never trust user input.

They might be lying. They might be mistaken. Always assume that something is wrong.

auriaks
06-22-2010, 07:48 PM
One more thing then, because that means that I don't know what session really is...
When I am starting session it automatically creates session_id ???

How to check that this id is the same on other "safe" page?

traq
06-23-2010, 01:03 AM
you don't need to check that the session id is the same. that is worked out between the browser and the server automatically.

You can make it more secure by forcing php to use cookies and not accepting session ids in URLs (cookies are more secure than query strings passed in URLs), by changing the default directory on your server that stores session info (a custom session path is more secure than the default path, especially on shared servers), and more... Read here (http://us2.php.net/manual/en/session.security.php).

What we've been talking about is above and beyond all that. Again, what it comes down to is how secure you actually need things to be. Are you using HTTPS / SSL? If not, then don't worry too much. Just force cookies, always re-validate that the user is logged in, ask the user to log in again before any serious changes can be made, and you should be fine.

auriaks
06-23-2010, 12:09 PM
Are you using HTTPS / SSL?

No, just .php...

Well, I don't know much about cookies :) Maybe you know a tutorial or working example of secure sessions? Because what I am looking for now, is script or parts to add into one.

traq
06-23-2010, 01:45 PM
in your php.ini file, put:

session.use_only_cookies = 1
session.cookie_httponly = 1
use_only_cookies prevents php from using session info passed in the URL
cookie_httponly makes the cookie usable only via http (not javascript, etc. - not supported by all browsers yet)

More (http://www.php.net/manual/en/session.configuration.php)

auriaks
06-24-2010, 08:54 PM
where do I have to create php.ini file?
Do I have to include it?

auriaks
06-24-2010, 09:00 PM
Take a look into my LOGIN script:

<?php
if(isset($_POST['enter'])) {
include $_SERVER['DOCUMENT_ROOT'] . '/connect/db_conn.php';
$password = md5($_POST['password']);
$nick = $_POST['nick'];

$password = mysql_real_escape_string($password);
$nick = mysql_real_escape_string($nick);
$nick = strtolower($nick);

if($password == '') {
$error .= "<li>Enter your password!</li>";
}
if($nick == '') {
$error .= "<li>Enter your Nick!</li>";
}
if(preg_match('/\W/', $password)) {
$error .= "<li>!!! No symbols !!!</li>";
} else {
if(preg_match('/\W/', $nick)) {
$error .= "<li>!!! No symbols !!!</li>";}}

$check = mysql_query("SELECT * FROM `test_sessions` WHERE nick='$nick' AND pass='$password'") or die(mysql_error());
if(mysql_num_rows($check) == 0) {
$error .= "<li>Wrong password or Nick!</li>";
}

if(isset($error)) {
$eroras = '<center><font color="grey">Mistakes:<br/><br/><font color="blue">'.$error.'</font></center>';
} else {

$r = mysql_fetch_array( $check ) or die(mysql_error());

session_start();

$code = md5($nick.$password);
$sess_time=date('ymdHis');
$sess_browser=$_SERVER['HTTP_USER_AGENT'];

$_SESSION['code'] = $code;
$_SESSION['time'] = $sess_time;
$_SESSION['browser'] = $sess_browser;

header("Location: index.php");
}

if($_GET['act'] == 'logout') {
session_start(); // begin session
session_unset();
session_destroy(); // remove the entire session
}
}
?>
<?php echo "$eroras";?>

<html xmlns="http://www.w3.org/1999/xhtml" lang="lt">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="lt"/>
</head>
<body>
<form method='post' action='login[test].php'>
<table align='center'><tr><td> User:</td>
<br />
<td><input type='text' name='nick' size='15'></td>
</tr><tr><td>Password:</td>
<br />
<td><input type='password' name='password' size='15'><input type='submit' name='enter' value=' Enter '></td></tr></table>
<br />
</form>
</body>
</html>

I want to change this part:


session_start();

$code = md5($nick.$password);
$sess_time=date('ymdHis');
$sess_browser=$_SERVER['HTTP_USER_AGENT'];

$_SESSION['code'] = $code;
$_SESSION['time'] = $sess_time;
$_SESSION['browser'] = $sess_browser;

To Create more powerful session...

I wonder if I could use cookie like:

<?php
$hash = md5($nick.$password.$sess_time);
setcookie("hash", "$hash");
?>
and use it as variable $_SESSION['hash']...
As you can see all of that are just a scratch... But Maybe I can make something from all of this?

TIP: For now, I am not looking into other pages such as regenerating session_id or checking hash for user authentication... Just trying to create powerful session. Only Then i could look forward.

traq
06-25-2010, 12:32 AM
A php.ini file goes in the directory you want it to affect, much the way a .htaccess file does. You don't include it.

Don't use the $sess_time in your cookie. Because the time constantly changes, it will be impossible to successfully check against this value. Otherwise, fine cookie.

HOWEVER, the main thing here is that you check against it. For example,
<?
session_start();

// I will assume you are also setting $nick and $password somewhere in here
$sess_browser=$_SERVER['HTTP_USER_AGENT'];

$hash = md5($nick.$password.$sess_browser); // create hash
$_SESSION['hash'] = $hash; // save hash to SESSION
setcookie("hash", "$hash"); // save hash in cookie for user

?>Will be completely useless unless you always validate it whenever the user opens a new page (or AJAX request, etc. - anything!). If you don't use the info, it does no good - that's the really important part. So, every "secure" page needs to also include something like:
<?php

if($_COOKIE['hash'] != $_SESSION['hash']){
header("Location: http://www/mysite.com/login-again");
}

?>

auriaks
06-25-2010, 08:01 AM
This reply was most informational (if this is even a word) :D

But still I have some questions... I have a lot of "secure" directions. Is it possible to use one php.ini file in all? Or I will need to create it in each..?

How I can improve security level? IP checking can be a big trouble, so I won't use it. Maybe I should use my encrypted code as a part of hash like:

<?
session_start();

// I have $nick and $password in the previous script.
$sess_browser=$_SERVER['HTTP_USER_AGENT'];
$code='jaskdjhasjdh455452sdasd';
$my_code=md5($code);

$hash = md5($my_code.$nick.$password.$sess_browser); // create hash
$_SESSION['hash'] = $hash; // save hash to SESSION
setcookie("hash", "$hash"); // save hash in cookie for user

?>

And Also I could regenerate session_id

BTW, is this session and cookie destroy is correct?


if($_GET['act'] == 'logout') {
session_start(); // begin session
session_unset($_SESSION['hash']);
session_unset($_COOKIE['hash']);
session_destroy(); // remove the entire session
}

auriaks
06-25-2010, 08:09 AM
Can you explain more about these:

[Session]
session.save_handler = files
session.save_path = /tmp
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.bug_compat_42 = 0
session.bug_compat_warn = 1
session.referer_check =
session.entropy_length = 0
session.entropy_file =
;session.entropy_length = 16
;session.entropy_file = /dev/urandom
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 1
url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry"

auriaks
06-25-2010, 10:08 PM
Why this script is not working?? I am not getting redirected by header when session is destroyed. What I can see is empty window...

<?php
session_start();
$cookie=$_COOKIE['hash'];
$session=$_SESSION['hash'];

//echo "$cookie and $session";

$host = $_SERVER['HTTP_HOST'];
$link = "http://$host/login.php";

if($_COOKIE['hash'] != $_SESSION['hash']){
header("Location: $link");
}

?>

djr33
06-25-2010, 10:55 PM
Two possibilities:
1. $_SERVER['HTTP_HOST'] is an unexpected value or includes http:// already. Try typing the address directly.
2. You were echoing $cookie and $session. A header() redirect only works BEFORE any text is output. I know this is commented out in your post, but if you had this executing while testing, that would cause a problem.


Also, that is NOT secure: a header redirect is very reliable, but not 100% reliable. Some browser could decide to ignore it, or, more importantly, a hacker would be able to avoid it: then they would have access to your page. It is generally a good way to move the user to another page, but you also need to be sure that you do not show any secure information. Add exit(); to the end and the script will stop execution there.


Try this:

<?php
session_start();
$cookie=$_COOKIE['hash'];
$session=$_SESSION['hash'];

$link = "http://www.example.com/login.php";

if($_COOKIE['hash'] != $_SESSION['hash']){
header("Location: $link");
exit();
}

?>


And make sure this is the first thing in your source code: any text (even whitespace-- spaces, returns, etc.) will make the header functions (session, header()) not work.

auriaks
06-25-2010, 11:46 PM
Two possibilities:
1. $_SERVER['HTTP_HOST'] is an unexpected value or includes http:// already. Try typing the address directly.
2. You were echoing $cookie and $session. A header() redirect only works BEFORE any text is output. I know this is commented out in your post, but if you had this executing while testing, that would cause a problem.

Add exit(); to the end and the script will stop execution there.



where I must use Exit() ??

The problem can be that when I destroy session - both variables became empty, and they are still equal...

djr33
06-25-2010, 11:51 PM
After the redirect. I added it to my previous post-- I forgot when I first posted it.

auriaks
06-26-2010, 12:35 AM
OK, now works... Maybe you know how I can solve the session and cookie question?

When I broke the session my $_COOKIE and $_SESSION values becomes empty... And that means equal:

if($_COOKIE['hash'] != $_SESSION['hash'])

traq
06-26-2010, 01:34 AM
my bad.

<?php

if(empty($_SESSION['hash'] || $_COOKIE['hash'] != $_SESSION['hash'])){
// end session, redirect to login, stop script
}

?>Also my bad:

If you're using $_SERVER['HTTP_USER_AGENT'], you should check the session hash directly against that value each time, instead of relying solely on the cookie's hash value. It's an extra step the malicious user would have to go through, beyond simply stealing the cookie:

<?php

// things we use to create hash
$user = "username";
$pass = "password";
$agent = $_SERVER['HTTP_USER_AGENT'];

// don't hash HTTP_USER_AGENT yet
$hash = md5($user.$pass);
// cookie won't include it
setcookie("hash", $hash);
// but session will
$_SESSION['hash'] = md5($hash.$agent);

// when you check later on:

if(empty($_SESSION['hash']) ||
md5($_COOKIE['hash'].$_SERVER['HTTP_USER_AGENT']) != $_SESSION['hash']){
// user/pass/agent combination doesn't match.
// destroy session, redirect to re-login, end script
}

?>

auriaks
06-26-2010, 01:49 AM
// when you check later on:

if(empty($_SESSION['hash']) ||
md5($_COOKIE['hash'].$_SERVER['HTTP_USER_AGENT']) != $_SESSION['hash']){
// user/pass/agent combination doesn't match.
// destroy session, redirect to re-login, end script
}

This part: where I have to check it?

I already use:

<?php
session_start();

if(empty($_SESSION['hash'] || $_COOKIE['hash'] != $_SESSION['hash'])){
header("Location: http://www.share2gether.xz.lt/login.php");
exit();
}
?>

..In every page TOP.

There is a mistake in first script in your comment...

traq
06-26-2010, 02:35 AM
the second bit of code (where the hash is checked separately) is an alternative method which could be used in place of what you're using now. It requires the cookie and session values to be set differently, however.

about the mistake - which comment/ which script are you referring to?

auriaks
06-26-2010, 09:37 PM
Everything is good, thanks :DD

traq
06-26-2010, 11:44 PM
no prob.

You fixed my mistake, or it was okay to start with? If something was broke I'd like to know

auriaks
06-27-2010, 01:05 PM
No it was on mine script :)

traq
06-27-2010, 02:45 PM
okay.

hey, thanks for asking this question. You prodded me to figure out a few things that'll be going into my current project. ::thumbs-up::

auriaks
06-27-2010, 08:31 PM
woohoo :D :D :D