I am attempting to set a cookie and then check to see if the cookie has been set.
So in one function, I have it make the cookies:
public function makeCookies(){
Cookie::queue('logged_in', $value, 15);
Cookie::queue('user_id', 2);
//return Response::make()->withCookie(Cookie::make('logged_in', $value, 15))->withCookie(Cookie::forever('user_id', 2));
}
And in the other function, I try to check to see if the cookie has been set:
public function checkCookies(){
$this->makeCookies();
if(Cookie::get('logged_in') && Cookie::get('user_id')){
return 'Logged In!';
}
}
However the only way this works is if I add 'return' before $this->makeCookies(); However, I want to be able to get to the conditional below it. Is there any way I can go about doing this? Any help is greatly appreciated.
To understand the Cookie Creation/Read process:
The user's browser sends a request for a page, along with any cookies that it currently has for the site
The site serves up the page, and any cookies you create become a header in your response.
Subsequent requests to your site will send the cookies created in #2.
What you are asking...to be able to read cookies that you create in step #2 in step #1...not possible.
Now, depending on how the Cookie class is created, you could make it so that when the Cookie::queue() is called, that it creates in-memory data that reflects what the cookie "should be" on the next request, but it doesn't truly know whether or not the user's browser will accept cookies, etc.
This is why many sites, after creating a cookie give the user a redirect to a page with something like ?checkCookie=1. This way, on the subsequent request, they can verify that your browser supports cookies...and if the cookie doesn't exist on the ?checkCookie page, they give you an error saying that their site requires cookie support. However, it does require a second round to the server to read cookies from the browser that were created.
UPDATE 2015-04-24 Per #Scopey, Laravel does support in-memory retrieval of cookies via queued(). So, you should be able to do:
public function checkCookies(){
$this->makeCookies();
$loggedIn = Cookie::get('logged_in') ?: Cookie::queued('logged_in');
$userId = Cookie::get('user_id') ?: Cookie::queued('user_id');
if( $loggedIn && $userId ){
return 'Logged In!';
}
}
SECURITY CONCERNS (NOT DIRECTLY ANSWERING THE QUESTION)
Your question was only about the cookies, so that's all I answered. However, now that I'm looking at your code, I feel I would be remiss not to point this out for anyone that happens to be reading this. This may just be a "how to" for yourself and not production code, but that code could be very dangerous if it ever went public.
Make sure you do NOT TRUST a user_id stored in a cookie to determine what user is coming in via cookies. If you rely on that, and I come to your site, I can modify my cookie to any user_id I want and get into other people's accounts.
General Safety Rules:
A cookie should contain a GUID, or similar random string to identify the session. This random string should be sufficiently long (e.g. 32 characters or greater, IMHO) that it is not easy for someone to brute-force their way to hijacking sessions.
The user_id should be stored in the $_SESSION (or laravel's wrapper for session if applicable) so that the user doesn't have any access to the user_id to be able to modify it.
In plain PHP, this something like this for the login page:
session_start();
if( isValidPassword($_POST['username'], $_POST['password']) ) {
$_SESSION['user_id'] = $user->Id;
}
else {
die('invalid login credentials');
}
The session_start() method automatically generates a cookie for the user with that long, random string (so you don't even have to worry about that part.)
On subsequent pages, you just check the session user_id to know who is logged in:
session_start();
if( empty($_SESSION['user_id']) ) {
die('You are not logged in and cannot access this page');
}
Change as needed per Laravel's documentation, which if they have their own session wrapper, I'm sure is well documented on best practices.
Excellent description by #KevinNelson about cookies but Laravel does support fetching back any cookies you have queued in the current request. Try using
Cookie::queued('logged_in');
The catch is, the cookie will only be "queued" during the request that you queued it. You will have to use get like you are for any other requests.
Related
I'm trying to manually login the user using this snippet (after verifying the login data of course):
public function loginUser($user) {
$userArray = array('uid' => $user->getUid());
$GLOBALS['TSFE']->fe_user->is_permanent = true;
$GLOBALS['TSFE']->fe_user->checkPid = 0;
$GLOBALS['TSFE']->fe_user->createUserSession($userArray);
$GLOBALS['TSFE']->fe_user->user = $GLOBALS['TSFE']->fe_user->fetchUserSession();
$GLOBALS['TSFE']->fe_user->fetchGroupData();
$GLOBALS['TSFE']->loginUser = true;
//this somehow forces a cookie to be set
$GLOBALS['TSFE']->fe_user->setAndSaveSessionData('dummy', TRUE);
}
If I leave out the "setAndSaveSessionData" Part, the login doesn't work at all, after a page redirect the login data are gone and the user is logged out again. But the setAndSaveSessionData stores the session in a cookie and the user will remain logged in even after closing the browser - which is a behaviour I do not want (not without the user's consent). Is there a way to manually login the user without the "setAndSaveSessionData" part? I'm using Typo3 6.2.12 with extbase and felogin
Thank you very much in advance!
In some TYPO3 6.2.x (I don't remember which x exactly) there was a change introduced, which causes that you need to call AbstractUserAuthentication::setSessionCookie() method yourself... Unfortunately it has protected access so the best way to login user is creating some util class extending it:
typo3conf/your_ext/Classes/Utils/FeuserAuthentication.php
<?php
namespace VendorName\YourExt\Utils;
use TYPO3\CMS\Core\Authentication\AbstractUserAuthentication;
use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
class FeuserAuthentication extends AbstractUserAuthentication {
function __construct($uid) {
return $this->authByUid($uid);
}
// Authenticates user by uid
public function authByUid($uid) {
/** #var $fe_user FrontendUserAuthentication */
$fe_user = $GLOBALS['TSFE']->fe_user;
$fe_user->createUserSession(array('uid' => $uid));
$fe_user->user = $fe_user->getRawUserByUid($uid);
$fe_user->fetchGroupData();
$GLOBALS['TSFE']->loginUser = true;
$fe_user->setSessionCookie();
return $fe_user->isSetSessionCookie();
}
}
so to login your user by uid you just need to create new object of this class with $uid of fe_user as a constructor's param:
$this->objectManager->get(
'\VendorName\YourExt\Utils\FeuserAuthentication',
$user->getUid()
);
P.S. As you can see this class doesn't check if account exists and/or is enabled, so you need to check it yourself before authentication attempt.
A website is delivered HTTP(S), which is a stateless protocol. This means that something has to be saved on the client computer, because otherwise the server couldn't reliably recognize the user again. There are several ways to do this:
Use a session cookie (The way TYPO3 does it, PHP also does that)
Manually add a session ID to each request on a page, Java-based applications do that sometimes. This breaks if the user leaves the page and comes back later (in the same session, or in another tab without copying a link).
There are probably some more ways, but I can't come up with them right now
So my answer is: Since I believe it is hard to get TYPO3 to switch to another way of setting the session information (would be quite user unfriendly), there is no good way to avoid setting the cookie.
However:
The cookie is a session cookie, which expires when the browser session is ended. So closing the browser and reopening it should end the login, except if the browser restores the previous session when opened. Many modern browsers do this, especially mobile browsers. Ways to get around that:
Use the incognito or private mode of the browser
Set the browser to start a fresh session on each start and make sure the browser terminates when you are finished (again: watch mobile devices).
im using a script from here: http://www.php-login.net
I altered it to suit my own needs but i see this part in the script:
// if user has an active session on the server
elseif (!empty($_SESSION['user_name']) && ($_SESSION['user_logged_in'] == 1)) {
$this->loginWithSessionData();
// checking for form submit from editing screen
if (isset($_POST["user_edit_submit_name"])) {
$this->editUserName();
} elseif (isset($_POST["user_edit_submit_email"])) {
$this->editUserEmail();
} elseif (isset($_POST["user_edit_submit_password"])) {
$this->editUserPassword();
}
I am not too sure how session variables work since there on the server and technically they cant be altered directly however this part of the code shows it can be altered indirectly if someone messed with cookies.
private function loginWithSessionData() {
$this->user_name = $_SESSION['user_name'];
$this->user_email = $_SESSION['user_email'];
// set logged in status to true, because we just checked for this:
// !empty($_SESSION['user_name']) && ($_SESSION['user_logged_in'] == 1)
// when we called this method (in the constructor)
$this->user_is_logged_in = true;
}
Im not sure if its possible but if i messed with the cookies and set username=x and got lucky and set is_logged_in as 1 could that give the user access? Im sure there is a much safer method of validating a session or do cookies themselves also come with there own type of validation like checking the machine hash and that hash must also match with the hash we stored on the server? Instead of something as simple as user_logged_in should i use a random string called it iftodaywasarainyday and just comment it internally so i know what that value corresponds with my is_logged_in or does it even matter.
I will do some more reading up on the subject but i guess i took the authors word for it since the first 3 words on the page are "A simple, clean and secure" and the site does look quite good but as i was refactoring the code there is lots of todo statements which got me worried its work in progress rather than a finished script
Session data is stored server-side. The actual data isn't in the cookie at all. The cookie is just an ID that let's the server know which session data to load. Users cannot modify this session data unless you allow them to by writing code that does it.
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!
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 ;-)
I am fairly new to PHP. What is the best way to control access to a class throughout a PHP application and where is the best place to store these classes that will need to be accessed throughout the entire application? Example; I have a user class that is created on during the login process, but each time the page post it appears that the object is reinitialized.
I have tried to set property IsLoggedIn and then check that variable each time before creating the object as new again, but this doesn't seem work. I have also tried to use the isSet function in PHP to see if the class variable already exists
You're right, the state of your application is not carried over from request to request.
Contrarily to desktop applications, web applications won't stay initialized because to the server, every time it can be a another visitor, wanting something completely different. You know who's using the desktop application, but you don't necessarily know who's requesting the page. Imagine 10 users doing different thing simultaneously on your web application? You wouldn't keep the whole application running necessarily for each of those visitors. Imagine with 10,000 visitors...
There are ways to keep some data from request to request though. The application will be reinitialized each time, yes, but you can then reload the state of what you were doing. It always revolve around around the same general methods:
Cookies; Cookies are a small file that is kept on the client side and which content will be available on each request to you. In PHP, this is available using $_COOKIE variable. In all cases, you could serialize your classes instances and reload them afterwards. The problem is, you wouldn't want to put sensitive data there as any(malicious)body can see and modify it.
POST or GET; In each request, you pass a state in the $_GET request (the URL such as http://localhost/myscript.php?iamatstep=4. Or via a $_POST such as using a hidden input field in a form. This data could be encrypted and make sense only to you, but still, you are putting sensitive data back to the client and anybody could fiddle with it.
Database, Disk; Or anything else on the server. Again, you serialize your data in a file for example at the end of a request ready to be used again for the next request. The main advantage is that it stays on your server. The downside is that at this point, you don't know which data to extract back for which request as there might be multiple users on your application at the same time...
And this is where the notion of $_SESSION comes into play. It's just a packaged way of using all of this at the same time. It's not magical as often it's perceived by beginners. When you use a session, the data put into the $_SESSION is stored somewhere on the server (normally a file in a temporary directory although it can be changed to something else like a database) and a unique ID is attributed to this session and passed in a cookie that will follow the visitor from request to request. So the only thing on the client's side is a big number in the cookie. On the next request, the browser tells PHP on the server that it's session number 12345, loads the corresponding file if it exists and then the data is available to you again. If cookies are not enabled, it could be passed in a GET or POST, although it's often better not to go there (see session.use_trans_sid's note).
It often looks like that on each of your pages you need authentication.
<?php
// verify if we have a current session
if (isset($_SESSION['login'])) {
// get data in current session
$username = $_SESSION['login']['username'];
$isLoggedIn = $_SESSION['login']['isLoggedIn'];
} else {
$username = '';
$isLoggedIn = false;
}
// take care of the unauthorized users
if (!$isLoggedIn) {
// maybe a redirection here...
}
// do the things a logged in users has the permission to do
And to set the session, it'll probably look like that:
<?php
// handle the form post of your login page for example
if (isset($_POST['username']) && isset($_POST['password'])) {
$username = $_POST['username'];
$password = $_POST['password'];
// verify the username and password against a database
if ($everythingIsOkay) {
// we can consider this user logged in and create a session
$_SESSION['login']['username'] = $username;
$_SESSION['login']['isLoggedIn'] = true;
// and now maybe redirect the user to the correct page
}
}
// raise an error about an invalid login
And finally, maybe a logout.php page that would do something like that:
<?php
unset($_SESSION['login']);
// redirect the user to the login page
This kind of data is going to have to be stored in a session, the only thing that is carried from page to page is Session data (sessions/cookies/...) so your class initialization is not carried over.
You can add information like the users username to the session with:
$username //username from db
$name //name from db
$_SESSION['username'] = $username;
$_SESSION['name'] = $name;
or if you just want to have easy access to all the information about the user you can do:
$_SESSION['user'] = mysql_fetch_assoc($result); //where $result is the response from the db to your login query
after you do this $_SESSION['user'] will be an array with all the details you selected from the database.