PHP secure Session Check? - php

I have a session that I gave to users that has matching password = stored password, like a simple login system :
// Checks Password and Username
if ($pSys->checkPassword($AccountData['password'], $StoredData['password'])) {
$_SESSION['login'] = true;
}
The question is: is this secure enough?
// put this on every header page that needs to be loggedin.
function loginCheck(){
if ( empty( $_SESSION['login'] )) {
header( 'location:index.php' );
die();
}
}
Is there a difference between die() and exit()? Second, some say that I should add session_regenerate_id()? (Is that an overkill?) Anyway the real question is said above.
addon*
I have read PHP Session Security but it seems it doesn't match my problem here (that link is just to general).
Here is the checkPassword() method
function checkPassword($password, $storedpassword) {
if($password == $storedpassword){
return true;
}
}

Answering the first part: empty and die are not comparable:
empty is to check if a variable does not exists or has a value equal to false (see also this type comparison table).
die is an alias of exit and is used to immediately abort the execution of the current script with an optional message.
Now to your authentication example: Yes, you should use session_regenerate_id to generate a new session ID and revoke the old session ID by setting the optional parameter for session_regenerate_id to true:
if (!sizeof($ErrorAccount)) { // Checks Password and Username
session_regenerate_id(true);
$_SESSION['login'] = true;
}
The purpose of session_regenerate_id is to avoid session fixation attacks. This will not be necessary if the server only allows session ids to be sent via cookies, but since PHP by default allows them in URL, you're strongly recommended to regenerate the id.

Since you are looking for answers about security, also don't keep the stored password in plain text. At the very least, salt and hash your passwords, then store the hash. Rehash and compare hashes, not plain text.

You could added a token (hash) to the form and then validate the token to make sure that the token which was submitted via the form is still valid. This helps to prevent CSRF attacks.
You could also store the IP address and browser together with the token in a database for additional validation, however you need to be aware that some ISP's change the clients IP address fairly often and could cause the validation to fail incorrectly.
More Info

Related

How can I check PHP Session in a more secure way?

I currently have a PHP Login System which logins by authenticating the Organisation Code the user enters, thus the database queried will be different.
includes.php
<?php
mysql_connect("mysql.example.com", $dbconn, "MySecurePassword");
mysql_select_db($dbconn);
?>
login.php
// $org is the Organisation Code, will be set when user clicks Login
$dbconn = $org;
include "includes.php";
// Omitted the $userid & $pw variables, assume there is no error, and that MySQL Injection is prevented already
$query = "SELECT * FROM `Login` WHERE `userid`=TRIM('$userid') AND `password`=TRIM('$pw' )";
$result = mysql_query($query);
if(mysql_num_rows($result)>0){
session_start();
$_SESSION['logged_in'] = $username;
header("Location: loggedinpage.php");
}
loggedinpage.php
<?php
session_start();
// As there is no fixed database, I've omitted the DB Connection
define('DS', TRUE); // used to protect includes
define('USERNAME', $_SESSION['logged_in']);
define('SELF', $_SERVER['PHP_SELF'] );
// Checks if user is logged in
if (!USERNAME) {
header("Location: login.php");
}
?>
Security Measure Taken
Passwords are hashed using SHA-512 and not stored in plaintext.
MySQL injection is prevented using mysql_real_escape_string()
I've omitted some code for ease to read, may I know if this way of checking if user is logged in is secure? If not, how can I improve it?
Thanks in advance!
Updated question to reflect the updates in comments
Assuming that your query works as intended and only returns a row when the match is exactly correct (e.g. no weird fuzzy matching through collate rules, but pure bin comparison), the authentication part is pretty much fine.
(You have been warned about SQL injection plenty, you're on your own there.)
Your security then boils down to this:
$_SESSION['logged_in'] = $username;
and the subsequent:
define('USERNAME', $_SESSION['logged_in']);
if (!USERNAME) {
header("Location: login.php");
}
And I suppose your question is about this part.
Then the answer is: the session part is fine, the blocking is not.
That's how sessions are used, yes, and they're reasonably safe by default; a user won't be able to somehow set the $_SESSION['logged_in'] value themselves, the value can only be set by your server, and presumably you're doing so only on successful authentication. Do read up about session hijacking, this is the only real vulnerability to the whole scheme.
The real problem is:
if (!USERNAME) {
header("Location: login.php");
}
Setting a header does not terminate the current page. If you're outputting sensitive information after this line, it will be sent to the client! You need to explicitly exit after setting the header.
Having said all this, we cannot tell you whether your system is "secure" because there may be any number of facepalm backdoors you have created which we're not seeing. In general I'd start with the following:
stop using mysql, use PDO or mysqli
bind your parameters, don't mysql_real_escape_string them; there are security pitfalls there
use password_hash password hashing, not SHA; especially if you're only doing a single SHA pass
becareful SQL Injection :
If you type in password field :
''=''
The password's rule will be true, because Password = TRIM(''='') is true. You have to control the password's string :
Minimum length
No white space (thanks to Trim function)
And you don't have to store a password like this, you must make a password's hash

Three tiered security check; session still vulnerable?

I have a basic site I'm using to test my programming method and I want to get a semi-decent secure way of keeping people logged in. Here is the code for register.php.
$username = $_POST["username"]; //username stored plaintext
$passhashed = crypt($_POST["password"], $username); //hashed password salted with username
$rnum = rand(1000,9999); //assign random 4-digit number
$authkey = crypt($rnum, $passhashed); //unique authentication key per user, hashed and salted with hashed password
//insert into SQL
When they log-in, $username, $passhashed, and $authkey is stored in $_SESSION data.
At the top of every single page I have the following snippet of code:
if(isset($_SESSION["username"])
&& isset($_SESSION["password"])
&& isset($_SESSION["authkey"])) {
$verifyuser = $db->prepare("
SELECT *
FROM users
WHERE username = :user
AND password = :password
AND authkey = :authkey
");
$verifyuser->execute(array(
':user' => $_SESSION["username"],
':password' => $_SESSION["password"],
':authkey' => $_SESSION["authkey"]));
if($verifyuser->rowCount() != 1) {
unset($_SESSION["username"]);
unset($_SESSION["password"]);
unset($_SESSION["authkey"]);
}
}
Basically on any given page, it performs a check that each piece store in $_SESSION clears with SQL, and if not (if any of the checks fail, will give a rowCount of not 1), it drops the session.
I'll be the first to admit I'm not too familiar with contemporary security measures to evade session hijacking (in fact, I only have a loose command of how it is even done). That being said, how is this for a beginner programmer? What can I do different to make it more secure? Assign a second authentication key at login, temporarily store it in SQL and make the same checks (new key per login)?
The crypt function is somewhat out-of-date. You'd be better off using bcrypt, which is provided in PHP using password_hash and password_verify. Additionally, using those functions, the salt (what you call $authkey) is integrated into the string, so you don't need to store it separately.
I notice you're storing the username and password in $_SESSION. $_SESSION cannot be directly modified by the client, so you might be better off just storing the user's ID there.
As you mentioned, I too have a basic understanding of session hijacking.
However I think if these 3 were hijacked, this still may not prevent account hijacking, although does make it harder.
When reading preventing session hijacking, I saw an example as simple as - If the current IP doesn't match the session, log the user out.
<?php
if($_SESSION['ip'] != $_SERVER['REMOTE_ADDR'])
{
session_destroy();
}
?>
Typical: I can no longer find said website...
Some links that may help you:
Preventing session hijacking
Proper session hijacking prevention in PHP

best and secure way to authenticate user in php application

I need to know how secure is my user authentication code that I am using in my php applications.
This is my login check function
// Is Login
//*********************************************************************************
public function isLogin()
{
$validation = new Validation();
if(!$validation->isEmpty($_SESSION["AdminId"]) && !$validation->isEmpty($_SESSION["AdminUsername"]) && !$validation->isEmpty($_SESSION["AdminName"]))
{
return true;
}
else
{
return false;
}
}
I have a authenticate file which i call from top of every user account's page which is as under
if (!$admin->isLogin())
{
header("Location: index.php?type=warning&msg=" .urlencode(ADMIN_INVALID_LOGIN));
exit();
}
The session values for example Adminusername is the actual username of the admin, adminname is the alphabetical name of the admin and adminid is the record id from mysql table such as $_SESSION["Adminusername"] = administrator though i am storing this value after encypting it.
I need to know is this a secure method to just store the values and check for them or I need to have some kind of advance functionality to make it more secure such as salt or time check etc.
I would appreciate your suggestions and feedbacks. If possible, your authenticate code / class.
Thanks in advance.
Amardeep Singh
use session regenerate id to get a new ID in every request, so u can prevent session hijacking .. read this manual : http://php.net/manual/en/function.session-regenerate-id.php
I am storing this value after encypting it
I don't understand... Why do you crypt your AdministratorName?
As you surely know, the user cannot manipulate his session as he wants, because the session is on the serverSide and your code decide what to write into session-data.
I think, salting or timechecking do not raise your security-level.
Because HTTP is stateless, each session is identified by a id, which ist mostly saved in a cookie on the client side. Each of your request to this server contains this SID, because it's the only way your server could identify a visitor.
If you use HTTP-Transport, your data (end also your SID) is sent through the internet without encryption. So a hacker could read your SessionID and take over your Session (which contains logged in User-Data). To prevent this, you can force HTTPS connection for logged in users.
If you have the possibility to switch all your pages to https-only, do it. If you must switch between http and https (for example https only if user is loggedin) it becomes really difficult to guarante security!

New to PHP logins and sessions; Is this safe enough?

I have a classifieds website which I am creating a login system for...
In the code below, a form with "username" and "password" has been submitted to. Also a "remember_me" feature is available (Code is not tested yet):
else if($row['password']===$pass){
session_start();
$_SESSION['logged_in'] = '1';
$remember_me = isset($_POST['remember']) ? $_POST['remember'] : '0';
if($remember_me=='1'){
$text = "SECRET_TEXT_AND_NUMBERS_HERE";
$username= $row['username'];
$salt1 = sha1($row['alt_username']);
$salt2 = sha1($text);
$cookie_value = $salt1.':'.$username.':'.sha1($row['alt_username'].$salt2.$salt1);
setcookie("s_b", $cookie_value, time()+60*60*24*100, "/");
}
}
Now, is this code a good start for a login page?
Also, an important follow-up question to all this, if users want to stay logged in, do I then set a $_SESSION variable like the one in the code, and just check if that is set in the beginning of all pages on the site?
if(isset($_SESSION['logged_in'])) // Then user is logged in already
or do I check to see if the cookie created in the login page is set instead of checking the session?
logging in is about security; security is always more difficult then it seems.
There are a couple of things that you could improve in your code. first:
the security for your password is in the strength of the hasing algorithm. You choose to use sha1 (better than md5, but could be improved by using sha256 or bCrypt if you use PHP version >= 5.3)
First
The salt you use is supposed to be a random value, stored alongside the hashed result.
in other words, the value to store in your database is:
$salt = [some random string of predifend lenght]; // Let's say 16 characters in length
$storedValue = $salt . sha256($salt . $password);
you check the password:
if ($row['username'] == $_POST['username'] && substr($row['$storedValue'], 16) == sha256(substr($row['$storedValue'], 0, 16) . $_POST['password'])) {
// login ok
} else {
// login fail
}
(better yet)
Use a proven library for the password hashing stuff, take a look at: Portable PHP password hashing framework and try to use the CRYPT_BLOWFISH algorithm if at all popssible.
Second
You should only store the session key in the session cookie. all other information is stored on the server.
The session cookie is already send out by PHP's session_start() function call, so you do not have to worry about this anymore.
if you want to check the sessions lifetime, you should store this information in the session array:
$_SESSION['lastActivity'] = time()+60*60*24*100;
Third
The remember me token is a 'password equivalent' so you should only store a hash of the token in your database, just treat it as a password, only this 'password' is not typed by the user, but read from the cookie.
The whole point of a hash is that its non-reversible, so it's not really adding any value the way you've used for the remember me function. Stop pretending it does anything useful, and use a random token for the remember me (and log this in the database against the username) then, if you get a client presenting a remember me cookie without an authenticated session, you know where to look to find out who it is.
(this also allows a sensible approach to be applied where the user keeps moving to different machines - you might say keep the last 2 values - and flag when they try to remember me from a 3rd machine).
A 100 day timeout is rather long - maybe 30 days (with an automatic refresh might be more appropriate depending on the level of risk.

PHP session var enough for user auth?

Scenario:
After a user has logged in, a session variable is set confirming their login.
At the top of every page, login session variable is confirmed valid
If it's not, they're booted out.
No persistent cookies are used, only session
Question:
Is this a strong enough security measure by itself, or should I
Set two session variables to validate eachother and/or
Implement database/hash validation
...?
========
(Incidentally, while I was researching this question, this wiki is a fantastic read.)
It is enough to store just user login (or user id) in the session.
To prevent session fixation/hijacking everything you need is just to implement simple algorythm (pseudocode):
if (!isset($_SESSION['hash']) {
$_SESSION['hash'] = md5(!empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'no ua');
} else if ($_SESSION['hash'] != md5(!empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'no ua')) {
session_regenerate_id();
$_SESSION = array();
$_SESSION['hash'] = md5(!empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'no ua');
}
You could move the hash calculation into some function to prevent of duplication, i've just shown a sketch of possible protection.
This is how I implemented this kind of protection in my kohana session class:
abstract class Session extends Kohana_Session
{
public function read($id = null)
{
parent::read($id);
$hash = $this->calculateHash();
$sessionHash = $this->get('session_fixation');
if (!$sessionHash) {
$this->set('session_fixation', $hash);
} elseif ($sessionHash != $hash) {
$this->regenerate();
$_SESSION = array();
$this->set('session_fixation', $hash);
}
}
private function calculateHash()
{
$ip = !empty($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1';
$ua = !empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'no ua';
$charset = !empty($_SERVER['HTTP_ACCEPT_CHARSET']) ? $_SERVER['HTTP_ACCEPT_CHARSET'] : 'no charset';
$ip = substr($ip, 0, strrpos($ip, '.') - 1);
return md5($ua . $ip . $charset);
}
}
Don't try to write your own session scheme, PHP will do it better.
yes you can add more information to your $_SESSION to help prevent session hijacking
for example I generate a fingerprint by combining a secret phrase or random data with the user agent and the session_id() and hash it all. To hijack a session the user would need to figure out a valid session_id, and the hash of the fingerprint. it will look like this. This is a good read
$_SESSION['fingerprint'] = md5('somethingSecret' . $_SERVER['HTTP_USER_AGENT']. session_id());
then you would validate the session like
$check_print = md5('somethingSecret' . $_SERVER['HTTP_USER_AGENT']. session_id());
if($check_print != $_SESSION['fingerprint'] || $_SESSION['authenticated']){
//invalid session
}
As of 15 November, the two answers I have received do not address my question, which was
"Is this [a single session variable] a strong enough security measure by itself?"
This question says yes, but there seems to be some dissension. Here is a summary of the various results:
1) A single session variable is not enough security since a session can be hijacked fairly easily.
2) Since this can occur, no session is truly safe, but it can be made safer with the addition of a fingerprint. This ensures a unique, repeat-able check each time a session needs validation. #zerkms recommends a hash of User-Agent and a few others (refer to his code).
3) Salting the fingerprint is mostly useless since it obscures the data but is replicated on every client machine, therefore losing its unique-ness.
4) A database solution is useless since it is a client-side problem.
Not the definitive answer I was looking for, but I suppose it will have to do, for lack of anything better.
Reading that has helped/confused me further:
Session hijacking and PHP
Is HTTPS the only defense against Session Hijacking in an open network?
There is nothing you can do, except use HTTPS.
It doesn't matter how many cookies you add or what data you hash; it can all be sniffed and sent back to the server.
If you're going to force a user to use a single UA throughout the life of their request, that can help: you don't need any special hashing business, because you're hashing it into $_SESSION which neither the user nor the hijacker can access directly, so why bother hashing it? Might as well just store $_SESSION["reportedUA"] = $_SERVER["HTTP_USER_AGENT"] on log-in and then check reportedUA on each request.
That, too, is trivial to hijack, once you realise it's happening, as you need only sniff the reported UA when you sniff the session cookie, and start using that.
What next? IP address? Session hijacking might be happening from behind a NAT, in which case you're screwed. Your users might be using dial-up, in which case they're screwed.
This problem has no solution: there is no way. There couldn't be a way. If a hacker can see your session cookies, then they can mess you up, because there's no additional information or challenge related to something only the user knows (i.e. password) that's sent with each request.
The only way to make the session secure is to secure the entire session.
Is this a strong enough security measure by itself,
Set two session variables to validate eachother and/or
Implement database/hash validation
No, and the reason is this: Anything that your valid user can send to your server for authentication (Session ID, cookies, some hashed string, anything!) can be sniffed by others if it's not encrypted. Even if the server processes the data with md5 hashing, salt, double-session-variable checks, id or whatever, and stores that information, it is easily reproduced by the server when it receives the spoofed data again from some other source.
As many people have suggested, SSL is the only way to prevent this type of evesdropping.
It has occurred to me that, were the server to generate a new session id for each request, and allow the browser to reply with it only once, there could theoretically be only one hijacker request or post before the server and the authorized browser knew about it. Still unacceptable, though, 'cause one is enough to do serious damage.
Hey what about this:
Create a single-use GUID and random salt and encrypt it with a shared password using PHP - this is sent as the session id or a cookie.
The client receives the cookie, decrypts it with the shared password using javascript (there are many enc/dec utilities available)
Set the current cookie or session id to the GUID.
That would ensure that nobody could hijack the session unless they knew the password, which is never sent over the network.
SSL seems much easier, and is more secure still.
EDIT: Ok, it's been done - nevermind ;-)

Categories