I'm new to PHP and trying to get my head around security.
I have an admin page that gives access to certain administrative tasks. Right now, it lets you repopulate database tables with some seed data.
To access the admin page, you first need to login. Currently the login is not over https (it will be soon).
If you authenticate, a token is written into $_SESSION. In every admin page, the token is checked. If invalid, the page is redirected to the login page.
My question:
Is this the proper way to "lock" down sensitive administrative tasks in PHP? Checking a value inside the $_SESSION variable? What more should I be doing?
That's pretty much the standard way to do it. Authenticate the user against your user database / password file / some other authentication data, store the state of authentication in a session variable and finally check whether the session variable is properly set every time the user attempts to make an action that requires authorization.
You could look into role based Access Control Lists if you need a more fine grained level of control. This way, authenticated users are granted or denied access to certain parts of your application based on the role you have given them. This is an additional security measure on top of regular password authentication.
If you only got one user, e.g. the admin, ACL is overkill though.
Session IDs are stored client-side usually as a cookie. If someone steals the cookie, they can hijack the session. Even if you use a secure connection for the login, later, unsecured requests will send it over the wire, and any XSS vulnerabilities can be used to capture the session cookie regardless of encrypted communication. Use session_set_cookie_params to limit the subdomain and path of the pages the cookie is sent to.
You can try to use non-spoofable client data to detect hijacking. Since you don't have control over the protocol, about the only such data is the remote IP, though an attacker can make a blind attack while spoofing their IP. However, this doesn't protect against hijackers behind the same NAT as the valid user and has problems with proxied requests.
You might be able to work out something with HTTP digest access authentication. It's a challenge-response authentication protocol and thus designed to work without protocol-level encryption. However, it's based on MD5, which has known weaknesses. Considering the life of the challenge, this may not be an issue. Digest auth is vulnerable to a man-in-the-middle attack.
Related
How do you prevent multiple clients from using the same session ID? I'm asking this because I want to add an extra layer of security to prevent session hijacking on my website. If a hacker somehow figures out another user's session ID and makes requests with that SID, how can I detect that there are different clients sharing a single SID on the server and then reject the hijack attempt?
EDIT
I have accepted Gumbo's answer after careful consideration because I've come to the realization that what I'm asking for is impossible due to the restrictions of a stateless HTTP protocol. I forgot about what is perhaps the most fundamental principle of HTTP, and now that I think about this question seems a bit trivial.
Let me elaborate what I mean:
After User A logs in on example.com, he is given some random session ID, for simplicity's sake, let it be 'abc123'. This session ID is stored as a cookie on the client side and is validated with a server-side session to ensure the user who logged in remains logged in as he moves from one webpage to another. This cookie of course would not need to exist if HTTP were not stateless. For that reason, if User B steals User A's SID, and creates a cookie on his computer with the value 'abc123', he would have successfully hijacked User A's session, but there is simply no way for the server to legitimately recognize that User B's request is any different from User A's requests, and therefore the server has no reason to reject any request. Even if we were to list the sessions that were already active on the server and try to see if someone is accessing a session that is already active, how can we determine that it is another user who is accessing the session illegitimately and not the same user who is already logged in with a session ID, but simply trying to make another request with it (ie navigate to a different webpage). We can't. Checking the user agent? Can be spoofed - but good as a Defense in Depth measure nevertheless. IP Address? Can change for legitimate reasons - but instead of not checking for the IP address at all, I suggest checking something like the first two octets of the IP, as even a user on a data plan network who constantly has a changing IP for perfectly legitimate reasons would only usually have the last two octets of their IP change.
In consclusion, it is the stateless HTTP that condemns us to never being able to fully protect our websites from session hijacking, but good practices (like the ones Gumbo has provided) will be good enough to prevent a good majority of session attacks. Trying to protect sessions from hijacking by denying multiple requests of the same SID is therefore simply ludicrous, and would defeat the whole purpose of sessions.
Unfortunately, there is no effective way to unmistakably identify a request that originates from an attacker in opposite to a genuine request. Because most properties that counter measures check like the IP address or user agent characteristics are either not reliable (IP address might change among multiple requests) or can be forged easily (e. g. User-Agent request header) and thus can yield unwanted false positives (i. e. genuine user switched IP address) or false negatives (i. e. attacker was able to successfully forge request with same User-Agent).
That’s why the best method to prevent session hijacking is to make sure an attacker cannot find out another user’s session ID. This means you should design your application and its session management that (1) an attacker cannot guess a valid session ID by using enough entropy, and (2) that there is no other way for an attacker to obtain a valid session ID by known attacks/vulerabilities like sniffing the network communication, Cross-Site Scripting, leakage through Referer, etc.
That said, you should:
use enough random input for generating the session ID (see session.entropy_file, session.entropy_length, and session.hash_function)
use HTTPS to protect the session ID during transmission
store the session ID in a cookie and not in the URL to avoid leakage though Referer (see session.use_only_cookies)
set the cookie with the HttpOnly and Secure attributes to forbid access via JavaScript (in case of XSS vulnerabilities) and to forbid transmission via insecure channel (see session.cookie_httponly and session.cookie_secure)
Besides that, you should also regenerate the session ID while invalidating the old one (see session_regenerate_id function) after certain session state changes (e. g. confirmation of authenticity after login or change of authorization/privileges) and you can additionally do this periodically to reduce the time span for a successful session hijacking attack.
Can we do something like this.
Store session id in database.
Also store the Ip address and the HTTP_USER_AGENT for that session id.
Now when a request comes to the server containing that matching session id, Check from which agent and ip it is coming from in your script.
Can make this funda work by make common function or class for session so that every request is verified before it is processed. It would hardly take some micro seconds. But, If many users are visiting your site and you have huge database of sessions, then this might be little performance issue. But, It would surely be very secure compared o other methods like
=> Using regenerating sessions.
In regenerating session ids, there is again little chance of session hijacking.
suppose, user's session id is copied and that user is not working or active for sometime and no request is made to server with old session id asking to regenerate new one. Then In case session id is hijacked, hacker will use that session id and make request to server with that id, then server will respond back with regenerated session id and so that hacker can go on using the services. Actual user will no longer be able to operate because he is unknown of what the regenerated id is and what request session id is to be passed in request. Completely Gone.
Please correct me if i m wrong somewhere.
There are lots of standard defenses against session hijacking. One of them is to match each session to a single IP address.
Other schemes may use an HMAC generated from:
the network address of the client's IP
the user-agent header sent by the client
the SID
a secret key stored on the server
The reason only the network address of the IP is used is in case the user is behind a public proxy, in which case their IP address can change with each request, but the network address remains the same.
Of course, to truly be secure, you really ought to force SSL for all requests so that the SID can't be intercepted by would-be attackers in the first place. But not all sites do this (::cough:: Stack Overflow ::cough::).
Session hijacking is a serious threat, it has to handle by using a secure socket layer for advanced application which involves transactions or by using simple techniques like using cookies, session timeouts and regenerates id etc as explained above.
When the internet was born, HTTP communications were designed to be stateless; that is, a connection between two entities exists only for the brief period of time required for a request to be sent to the server, and the resulting response passed back to the client.
Here are a few methods which hackers follow to hijack the session
Network Eavesdropping
Unwitting Exposure
Forwarding, Proxies, and Phishing
Reverse Proxies
Always recommend SSL Secure Sockets Layer
Use cookies also to following ini_set() directives at the start of your scripts, in order to override any global settings in php.ini:
ini_set( 'session.use_only_cookies', TRUE );
ini_set( 'session.use_trans_sid', FALSE );
Use Session Timeouts and Session Regenerate ID
<?php
// regenerate session on successful login
if ( !empty( $_POST['password'] ) && $_POST['password'] === $password )
{
// if authenticated, generate a new random session ID
session_regenerate_id();
// set session to authenticated
$_SESSION['auth'] = TRUE;
// redirect to make the new session ID live
header( 'Location: ' . $_SERVER['SCRIPT_NAME'] );
}
// take some action
?>
In my view you can store session id in database when users login and check everyone for the same before loggin in. delete the same session id which you have stored in database when users logout. You can easily findout session id of each and every user or else I can help you.
One of the easy implementations can be done by making a table in database , as logged users , then at login, update that table with user name and his SID , this will prevent other logins as same user , now at the time of log out , just run a simple query , which deletes the logged in data in database , this can also be used to trace logged in user on ur website at a time .
Obviously when you'll set session cookie in the browser, that cookie is sent in the request. Now when request comes, Server will check the session id in database and grant access. To prevent that only its important to store agent and ip so that before checking server makes sure that sessions access is granted to the unique client and not the unique session id which can be hijacked.
I don't know about the coding part well. So I can tell u an algorithm to do this. Setting stuffs like SSL, or setting the session cookie to secure and httpOnly wont work if a user sniffs the session id from a LAN network(Provided user and attacker are in the same LAN).
So what you can do is, once the user successfully logs into the application, set unique token to each and every pages of the web application and keep a track of this at the server side. So that if the valid user sends the request to access a particular page, the token of that page will also be sent to the server side. Since the tokens are unique for a user for a particular session, even if the attacker can get the session id, he cannot hijack the users session as he cannot provide the valid token to the server.
#Anandu M Das:
I believe what you may be referring to is the use of session tokens with each session ID. This site can explain the use of tokens with sessions:
https://blog.whitehatsec.com/tag/session-token/
Although session tokens are easily compromised by an XSS attack, this doesn't mean that they should never be used. I mean let's face it, if something was compromisable by a security vulnerability on the server, its not the fault of the method, its the fault of the programmer who introduced that vulnerability (to highlight points made by Hesson and Rook).
If you follow proper security conventions and practicies and secure your site from SQL injection, XSS, and require all sessions be managed over HTTPS, then you can easily manage the potential attack from CSRF by use of server-side tokens, stored within the session, and updated everytime the user would cause a manipulation to their session (like a $_POST being submitted). Also, NEVER store sessions or their contents in a url, no matter how well you think they are encoded.
When the security of your users is paramount (which it should be), the use of session tokens will allow better or more advanced functionality to be provided without compromising their session security.
How do you prevent multiple clients from using the same session ID? I'm asking this because I want to add an extra layer of security to prevent session hijacking on my website. If a hacker somehow figures out another user's session ID and makes requests with that SID, how can I detect that there are different clients sharing a single SID on the server and then reject the hijack attempt?
EDIT
I have accepted Gumbo's answer after careful consideration because I've come to the realization that what I'm asking for is impossible due to the restrictions of a stateless HTTP protocol. I forgot about what is perhaps the most fundamental principle of HTTP, and now that I think about this question seems a bit trivial.
Let me elaborate what I mean:
After User A logs in on example.com, he is given some random session ID, for simplicity's sake, let it be 'abc123'. This session ID is stored as a cookie on the client side and is validated with a server-side session to ensure the user who logged in remains logged in as he moves from one webpage to another. This cookie of course would not need to exist if HTTP were not stateless. For that reason, if User B steals User A's SID, and creates a cookie on his computer with the value 'abc123', he would have successfully hijacked User A's session, but there is simply no way for the server to legitimately recognize that User B's request is any different from User A's requests, and therefore the server has no reason to reject any request. Even if we were to list the sessions that were already active on the server and try to see if someone is accessing a session that is already active, how can we determine that it is another user who is accessing the session illegitimately and not the same user who is already logged in with a session ID, but simply trying to make another request with it (ie navigate to a different webpage). We can't. Checking the user agent? Can be spoofed - but good as a Defense in Depth measure nevertheless. IP Address? Can change for legitimate reasons - but instead of not checking for the IP address at all, I suggest checking something like the first two octets of the IP, as even a user on a data plan network who constantly has a changing IP for perfectly legitimate reasons would only usually have the last two octets of their IP change.
In consclusion, it is the stateless HTTP that condemns us to never being able to fully protect our websites from session hijacking, but good practices (like the ones Gumbo has provided) will be good enough to prevent a good majority of session attacks. Trying to protect sessions from hijacking by denying multiple requests of the same SID is therefore simply ludicrous, and would defeat the whole purpose of sessions.
Unfortunately, there is no effective way to unmistakably identify a request that originates from an attacker in opposite to a genuine request. Because most properties that counter measures check like the IP address or user agent characteristics are either not reliable (IP address might change among multiple requests) or can be forged easily (e. g. User-Agent request header) and thus can yield unwanted false positives (i. e. genuine user switched IP address) or false negatives (i. e. attacker was able to successfully forge request with same User-Agent).
That’s why the best method to prevent session hijacking is to make sure an attacker cannot find out another user’s session ID. This means you should design your application and its session management that (1) an attacker cannot guess a valid session ID by using enough entropy, and (2) that there is no other way for an attacker to obtain a valid session ID by known attacks/vulerabilities like sniffing the network communication, Cross-Site Scripting, leakage through Referer, etc.
That said, you should:
use enough random input for generating the session ID (see session.entropy_file, session.entropy_length, and session.hash_function)
use HTTPS to protect the session ID during transmission
store the session ID in a cookie and not in the URL to avoid leakage though Referer (see session.use_only_cookies)
set the cookie with the HttpOnly and Secure attributes to forbid access via JavaScript (in case of XSS vulnerabilities) and to forbid transmission via insecure channel (see session.cookie_httponly and session.cookie_secure)
Besides that, you should also regenerate the session ID while invalidating the old one (see session_regenerate_id function) after certain session state changes (e. g. confirmation of authenticity after login or change of authorization/privileges) and you can additionally do this periodically to reduce the time span for a successful session hijacking attack.
Can we do something like this.
Store session id in database.
Also store the Ip address and the HTTP_USER_AGENT for that session id.
Now when a request comes to the server containing that matching session id, Check from which agent and ip it is coming from in your script.
Can make this funda work by make common function or class for session so that every request is verified before it is processed. It would hardly take some micro seconds. But, If many users are visiting your site and you have huge database of sessions, then this might be little performance issue. But, It would surely be very secure compared o other methods like
=> Using regenerating sessions.
In regenerating session ids, there is again little chance of session hijacking.
suppose, user's session id is copied and that user is not working or active for sometime and no request is made to server with old session id asking to regenerate new one. Then In case session id is hijacked, hacker will use that session id and make request to server with that id, then server will respond back with regenerated session id and so that hacker can go on using the services. Actual user will no longer be able to operate because he is unknown of what the regenerated id is and what request session id is to be passed in request. Completely Gone.
Please correct me if i m wrong somewhere.
There are lots of standard defenses against session hijacking. One of them is to match each session to a single IP address.
Other schemes may use an HMAC generated from:
the network address of the client's IP
the user-agent header sent by the client
the SID
a secret key stored on the server
The reason only the network address of the IP is used is in case the user is behind a public proxy, in which case their IP address can change with each request, but the network address remains the same.
Of course, to truly be secure, you really ought to force SSL for all requests so that the SID can't be intercepted by would-be attackers in the first place. But not all sites do this (::cough:: Stack Overflow ::cough::).
Session hijacking is a serious threat, it has to handle by using a secure socket layer for advanced application which involves transactions or by using simple techniques like using cookies, session timeouts and regenerates id etc as explained above.
When the internet was born, HTTP communications were designed to be stateless; that is, a connection between two entities exists only for the brief period of time required for a request to be sent to the server, and the resulting response passed back to the client.
Here are a few methods which hackers follow to hijack the session
Network Eavesdropping
Unwitting Exposure
Forwarding, Proxies, and Phishing
Reverse Proxies
Always recommend SSL Secure Sockets Layer
Use cookies also to following ini_set() directives at the start of your scripts, in order to override any global settings in php.ini:
ini_set( 'session.use_only_cookies', TRUE );
ini_set( 'session.use_trans_sid', FALSE );
Use Session Timeouts and Session Regenerate ID
<?php
// regenerate session on successful login
if ( !empty( $_POST['password'] ) && $_POST['password'] === $password )
{
// if authenticated, generate a new random session ID
session_regenerate_id();
// set session to authenticated
$_SESSION['auth'] = TRUE;
// redirect to make the new session ID live
header( 'Location: ' . $_SERVER['SCRIPT_NAME'] );
}
// take some action
?>
In my view you can store session id in database when users login and check everyone for the same before loggin in. delete the same session id which you have stored in database when users logout. You can easily findout session id of each and every user or else I can help you.
One of the easy implementations can be done by making a table in database , as logged users , then at login, update that table with user name and his SID , this will prevent other logins as same user , now at the time of log out , just run a simple query , which deletes the logged in data in database , this can also be used to trace logged in user on ur website at a time .
Obviously when you'll set session cookie in the browser, that cookie is sent in the request. Now when request comes, Server will check the session id in database and grant access. To prevent that only its important to store agent and ip so that before checking server makes sure that sessions access is granted to the unique client and not the unique session id which can be hijacked.
I don't know about the coding part well. So I can tell u an algorithm to do this. Setting stuffs like SSL, or setting the session cookie to secure and httpOnly wont work if a user sniffs the session id from a LAN network(Provided user and attacker are in the same LAN).
So what you can do is, once the user successfully logs into the application, set unique token to each and every pages of the web application and keep a track of this at the server side. So that if the valid user sends the request to access a particular page, the token of that page will also be sent to the server side. Since the tokens are unique for a user for a particular session, even if the attacker can get the session id, he cannot hijack the users session as he cannot provide the valid token to the server.
#Anandu M Das:
I believe what you may be referring to is the use of session tokens with each session ID. This site can explain the use of tokens with sessions:
https://blog.whitehatsec.com/tag/session-token/
Although session tokens are easily compromised by an XSS attack, this doesn't mean that they should never be used. I mean let's face it, if something was compromisable by a security vulnerability on the server, its not the fault of the method, its the fault of the programmer who introduced that vulnerability (to highlight points made by Hesson and Rook).
If you follow proper security conventions and practicies and secure your site from SQL injection, XSS, and require all sessions be managed over HTTPS, then you can easily manage the potential attack from CSRF by use of server-side tokens, stored within the session, and updated everytime the user would cause a manipulation to their session (like a $_POST being submitted). Also, NEVER store sessions or their contents in a url, no matter how well you think they are encoded.
When the security of your users is paramount (which it should be), the use of session tokens will allow better or more advanced functionality to be provided without compromising their session security.
I'm somewhat new to web development and I need to develop a user system - so users can register, login etc.
I initially stored the user data in a Session variable upon login, but felt the need to re-architecture that because I realized I would never be able to support 'remember me' functions, and decided to use cookies.
My current system is this:
User logs in: I verify username and password against stored values in DB
I set username and password to their own cookies. username cookie persists so the username field can be populated when the user revisits. Password cookie expires when user leaves.
Each time a page loads, my PHP script checks to see if the password cookie exists, which means the user is logged in.
The problem is, the third step seems somewhat insecure to me. Currently, I only check to see if the password cookie exists, but I do not compare it against the database everytime a page loads. Couldn't an unauthorized user create a password cookie and set it to some random string manually, and get through my authentication system? He would be able to impersonate any user by setting the user cookie manually as well. Should I be comparing the value of the password cookie against my database on every page load?
So, if I use session in conjunction with cookies, I imagine doing something like this:
if (!isset($_SESSION['user']))
{
authenticate_user_from_cookie();
set_session('user');
}
else
{
//user is already logged in
}
When you call session_start() it will reconnect the current request to a session ($_SESSION), or create a new session. Apache saves these sessions to disk (by default in your /tmp folder) and reconnects you to the session automagically with a cookie named PHPSESSID (this can be changed in PHP.INI), that is stored after the first time you call session_start() on the first request.
You can authenticate your user by whatever means you want, but typically you could use lookup the username + (encrypted password - e.g. sha1($password.'salt string that only you know')) pair in your database or permanent storage and then simply set $_SESSION['loggedIn'] = true or $_SESSION['user'] = 1 or whatever flag you want in the $_SESSION.
You can go as far as creating a User class (many frameworks do that), representing everything you know about the logged-in authenticated user and then ask the object $_SESSION['User']->isAuthenticated() or something like that.
If you want to not have the user reenter their password each time you can implement a Remember Me feature (special random cookie that you generated when they authenticated and stored in the database), that will set a special cookie in their browser that won't expire at the end of the session that you look when someone makes a request who isn't authenticated.
This is not php specific but if you're new, I would recommend reading the OWASP guide. OWASP is an excellent resource for secure web development info. The OWASP site will cover much more than we can here.
For a more php specific answer, they have this guide. Point 2.10 addresses your question more directly.
Just checking for a cookie's existence is by no means a way to authenticate a user or validate his identity. So yes, you should be checking on every page load, if you're sticking with the cookie based authentication. As long as there's an index / primary key on the lookup into the user table, the query will be fast to pull the user's information and check against the cookie values.
To be more specific, the cookie(s) that you're setting are just as valuable as the user's username and password, they're nearly synonymous. So, you can also save information about the user when you issue the cookie, such as IP and User-Agent, which you can also verify to try and ensure the cookies match the user.
A few more tips:
1.) Make sure you do input validation for both the password and the userid and make certain that you are validating the values on the server side as any client-side validation can easily be bypassed by malicious users. If you don't validate on the server you will be opening yourself to various types of attacks such as SQL injection and people will be able to compromise your database. Make sure you are escaping any potentially malicious strings
2.) Make sure you have login logouts, so that if people try to to put in too many wrong credentials you block their IP for a few minutes. This will discourage brute force attacks.
Make sure that this works for both bad userids as well as bad passwords as attackers can iterate over either (e.g. they can keep the password the same and try many user ids).
3.) If you are using salts, do not store the salt in the same place as the password hashes. If someone breaks into your database you don't want them to have both the hashes and the salts because it will make the hashes easy to crack using rainbow tables.
4.) Make sure you are using SSL/TLS to encrypt traffic traffic between the server and the user, otherwise an attacker can steal the cookie by sniffing the network and login as your user. (Look up Firesheep, it was a big problem for Facebook and Gmail for a little while...)
5.) Don't do any custom encryption schemes, use only trusted cryptographic libraries and algorithms to perform hashes. (e.g. PHP's sha1 is good, doing your own little rotation on password characters is not).
6.) As recommended, you should check out OWASP, it's the best resource for securing a web application.
What is the best way to know if user is the right guy and not a hacker?
For example in my project when user is logging in I create some session variable with some number and then on other pages I check this session variable and according to it's value give user some options.
So can hacker change this variable somehow so server side will grant him access to some options ?
If so what is the best way of holding some users rights and passing them to different pages , so server can grant that user with some options ?
To understand Session Hijacking more clearly, there are several methods by which a hacker hijacks the session let me put some light on different types of session hijacking.
according to Wikipedia
There are four main methods used to perpetrate a session hijack:
Session fixation, where the attacker sets a user's session id to one known to him, for example by sending the user an email with a link that contains a particular session id. The attacker now only has to wait until the user logs in.
Session sidejacking, where the attacker uses packet sniffing to read network traffic between two parties to steal the session cookie. Many web sites use SSL encryption for login pages to prevent attackers from seeing the password, but do not use encryption for the rest of the site once authenticated. This allows attackers that can read the network traffic to intercept all the data that is submitted to the server or web pages viewed by the client. Since this data includes the session cookie, it allows him to impersonate the victim, even if the password itself is not compromised.1 Unsecured Wi-Fi hotspots are particularly vulnerable, as anyone sharing the network will generally be able to read most of the web traffic between other nodes and the access point.
Alternatively, an attacker with physical access can simply attempt to steal the session key by, for example, obtaining the file or memory contents of the appropriate part of either the user's computer or the server.
Cross-site scripting, where the attacker tricks the user's computer into running code which is treated as trustworthy because it appears to belong to the server, allowing the attacker to obtain a copy of the cookie or perform other operations
While there are several solution to stop this kind of hijacking for example for the second one using a SSL or https would be appropriate to avoid it. however if you want to add more security for your session then one solution i came across is by allowing passing of seesionId's via Cookies only, and generate and additional session token that is passed via URL. and only request that contain a valid Session toekn may access the session.
Below is the example demonstrating the example taken by Orielly PHP CookBook.
ini_set('session.use_only_cookies', true);
session_start();
//Create a random salt value
$salt = 'Hjkhkjh9089&j98098';
$tokenstr = (str) date('W') . $salt;
//Create a md5 hash to be used for token.
$token = md5($tokenstr);
if (!isset($_REQUEST['token']) || $_REQUEST['token'] != $token) {
// prompt for login
exit;
}
$_SESSION['token'] = $token;
output_add_rewrite_var('token', $token);
Now what output_add_rewrite_var does it it adds another name/value pair to the url rewrite mechanism via Get method. read more about the function here. output_add_rewrite_var
to read more about session security i suggest you read this article http://hungred.com/useful-information/solutions-session-attacks/
hope this helps you in understanding the vulnerabilities of sessions and how to fix it.
create hash from ip ( better not ) , session id and some other unique data in user cookie and check for each request... with this way you can control session hijack
in other hand you must have table to each session for privilege like acl system ... save all setting in database and with session id find all settings
Honestly, if you're not fluent in authentication methods, I'd suggest using an established provider (or similar, such as Google, Facebook, Twitter, etc. using oAuth) who have experts in the subject. Why try and re-invent the wheel when there are large companies with field experts providing this exact service? Using these providers will also give you insight into how to provide secure authentication for your systems.
I want to learn the whole details of web application authentication. So, I decided to write a CodeIgniter authentication library from scratch. Now, I have to make design decision about how to determine whether one user is login.
Basically, after user input username & password pair. A cookie is set for this session, following navigations in the web application will not require username & password. The server side will check whether the session cookie is valid to determine whether current user is login. The question is: how to determine whether cookie is valid cookie issued from server side?
I can image the most simple way is to have the cookie value stored in session status as well. For each HTTP request, compare the value from cookie and the value from server session. (Since CodeIgniter session library store session variables in cookies, it is not applicable without some tweak.) This method requires storage in server side.
For huge web application that is deployed in multiple datacenters. It is possible that user input username & password when browsing in one datacenter, while he/she access the web application in another datacenter later. The expected behavior is that user just input username & password once. As a result, all datacenters should be able to access the session status. That is possible not applicable even the session status is stored in external storage such as database.
I tried Google. I login Google with Asian proxy which is supposed to direct me to datacenters in Asian. Then I switch to North American proxy which should direct me to datacenters in North America. It recognize my login without asking username and password again.
So, is there any way to determine whether user is login without server side session status?
No, that's impossible.
These datacenters is not isolated from each other but interconnected.
It is distributed but solid "external storage such as database"
Cross-domain authorization is another matter but easily achieved too.
What's the use anyway of such an information - just the fact the user logged in, without any user options, credentials - anything? Why without a database on the server side?
Useful resources:
session_save_handler allows you to replace PHP's file-based session handling by your own mechanisms, e.g. connecting to an external database
this SO question deals with mySQL replication.
This is only one of many issues when going multi-server with a PHP solution - I'm sure there is more to find on the topic in SO's search.
Also, consider looking on Server Fault.
Assuming that the user is authenticated just because something which looks like a session cookie exists is a very bad idea. Also your code is going to become very messy when you start trying to measure facts about the session without calling session_start() first. A better solution is to store the fact the user is authenticated (and potentially some of the authorization infromation) in the session itelf, e.g.
session_start();
if (!$_SESSION['auth_user']) {
if ($_POST['username'] && $_POST['password']
&& check_valid($_POST['username'],$_POST['password']) {
$_SESSION['auth_user']=$_POST['username'];
} else {
// user is not logged in
header('Location: /login.php');
print 'You are not logged in';
exit;
}
}
C.
So, is there any way to determine whether user is login without server side session status?
Yes, there is. The server should set a cookie with encrypted user ID (and possibly other data). If all servers share the key, then they also know how to decrypt that cookie, and thus can independently authenticate the user. If the cookie also contains unencrypted user ID, then you can use a custom one-way encryption function (aka hash with salt or MAC) to check if it's valid. If you really care about security, you can encrypt more data e.g. IP address, expiry date, etc. If you want, you can also use asymmetric encryption, with public and private keys, and/or digital signature.