Considerations When Building an Authentication System (Part 1: Session)

This is a 3 part series.

Background
Over the past couple of months, I’ve been implementing an authentication system for a Zend Framework project I’m working on in my spare time.  This post is going to outline considerations when building an authentication system for web applications built with Apache HTTPD, PHP and Zend Framework.

Authentication is a lot more complex than a simple username and password in a database, a form and some business logic to confirm that the credentials match.  When building an authentication system for your website, you’ll also need to consider browser persistence (remember me), session hijacking, database security and SSL/HTTPS and what impact these things have across multiple domains and servers.

Table of Contents for Part 1: Session


Session Cookies
Session persistence is built into PHP with the $_SESSION variable and accessible in Zend Framework with the Zend_Session component.  It’s an effective way of keeping persistence whilst a visitor is using your web application but expires after a short period of time, usually 20 minutes.  PHPSESSID is the default name of the browser cookie dropped on the browser by PHP.

One option for longer persistence is to increase the session lifetime in PHP (http://www.php.net/manual/en/session.configuration.php). This is not suitable when you’re talking about persisting a visitor’s login credentials for 7+days as it will introduce a large resource burden on Apache HTTPD, plus, sessions are cleared when Apache HTTPD is restarted.

To change the persistence duration of visitor’s sessions:

  • PHP ini – ini_set(‘session.remember_me_seconds’, 864000);    // 10 days
  • Zend_Session::setConfig(array(‘remember_me_seconds’ => 864000));   // 10 days


Multiple Servers
Session data is only accessible on the Apache HTTPD server that collected the data.  If a website runs across multiple servers and a visitor authenticates against one server, their credentials will be stored in that one server’s session (via PHP’s $_SESSION).  On the next request, if the visitor hits a second server, they will be prompted to authenticate again as the second server’s session does not have the credentials stored and does not have access to the first server’s session data.

To get around this, memcached can be used to store session data.  Memcached is a distributed cache which solves the problem of servers sharing their session data.  See implementation instructions here: http://www.vexedmonkey.com/2008/08/01/zend-framework-sessions-in-memcache/

Session Hijacking
Session hijacking (and here) is where a hacker sniffs a victim’s network traffic or gains access to the victim’s browser cookies and steals their session cookie.  The PHP session browser cookie, PHPSESSID, contains a string (session key) like “fe070316c67d426ce92df402c281ad1e”.  This session key is used by PHP to access the visitor’s session data (accessible via PHP’s $_SESSION).

If a hacker copied a victim’s session key and placed it into their own browser, they would gain access to the victim’s session and could use the website as if they were the victim.

RULE:  Sensitive data should always be transmitted over HTTPS
To mitigate this risk, it’s essential that all network traffic on the domain/subdomain containing sensitive information is done so over SSL (HTTPS).  Remember, over unencrypted HTTP, cookies are sent in plain text.

RULE:  Never Trust Visitor Inputs
A hacker could gain access to a victim’s cookies using a cross-site-scripting (XSS) hack.  To mitigate against this danger, it’s very important that all user supplied contents is run through a sanitisation/validation filter such as Zend_Filter, PHP’s filter_var() or HTMLPurifier.

Both Zend_Filter and filter_var() are excellent ways at sanitising and validating visitor inputs if the input is not HTML.  If the visitor input is HTML, Zend_Filter and filter_var() will not do the job as they cannot validate or sanitise HTML.

HTMLPurifier is a very well written and maintained library that should be used to filter all visitor inputs, particularly if the visitor inputs contain HTML code.

RULE:  Regenerate Session Cookie Regularly
To reduce the risk of session hijacking, the following code should be added when initiating Zend_Session:

<?php
// At the point at which session is initiated, regenerate session Id
Zend_Session::start()
Zend_Session::regenerateId();
?>

The above code will regenerate a visitor’s session Id on each request, reducing the chance of a hacker sniffing your network traffic, copying the victim’s session Id and then using it.

RULE:  Don’t allow session data to be accidentally sent over non-secure HTTP
If you were to require a visitor to login with their credentials over SSL (HTTPS), the session cookie is private and a hacker would not be able to view your session cookie or hijack your session.

What if the website then directed the visitor off to a non-secure page, or the visitor chose to view the website’s FAQ on a non-secure Url?  When the request to the non-secure Url is made, the session cookie would be transported over a non-secure Url, making session hijacking a very possible threat.

To mitigate this risk, there are a couple of choices:
1.  PHP session data is only available over SSL:

  • PHP ini – ini_set(‘session.cookie_secure’, 1);    //  0 – false,  1 – true
  • Zend_Session::setConfig(array(‘cookie_secure’ => 1));  // 0 – false, 1 – true

The limitiation is that non-secure Urls will not have access to PHP’s $_SESSION variable. No longer able to persist non-sensitive data such as visitor layout or page flow without requiring the whole user experience to run across SSL (HTTPS).

2.  Keep all secure communications with the server on a separate domain eg https://secure.example.com where the non-secure domain would be http://www.example.com
Both would have their own session cookie (PHPSESSID) meaning that a hacker could hijack the non-secure session by sniffing network traffic but would only find non-sensitive data and wouldn’t be able to view the contents of the secure one, which contains the visitor’s credentials.

Part 2: Cookies
Part 2 will cover the importance of cookies in authentication systems and how to effectively secure them to keep your visitor’s sensitive data safe.
Considerations When Building an Authentication System (Part 2: Cookies)

About the Author
Brett is the Lead Web Developer at BBC.com working on a number of products, such as the BBC International Homepage, News, Sport, Travel and the back-end work on the iPhone and iPad applications.

Advertisements
Posted in PHP, Zend Framework, Zend_Filter, Zend_Session
2 comments on “Considerations When Building an Authentication System (Part 1: Session)
  1. arurmamedov says:

    You genius, thank so much for “Session Hijacking Rules” , but i have one question, can i set all my site to use https:// ? There is any problem if i do this? I seen eBay use htpps:// only in determinate pages, Facebook use https:// ever.
    Thank in advance for reply and sorry for bad English.

    • brettscott says:

      Hi arurmamedov,

      Setting your whole site to HTTPS is a great idea, but there is a small issue in doing so.

      When a site is HTTPS, proxy servers (ISPs), your own reverse proxies (Varnish), mod_cache and browsers no longer cache the page’s contents. This means that your “Cache-Control: public” is not longer relevant or used.

      Every page request will come back to origin, increasing server load and user delay. One way to resolve this would be to put all assets (images, JavaScript files etc) onto http and have the main page as HTTPS, but Internet Explorer warns the user of mixed contents – which is bad. Although, these days I’m certain Amazon/Akamai CDN can handle hosting HTTPS assets these days – I’d have to look into that one 😉

      Now, if you’re website isn’t getting a huge amount of traffic then having users stay on HTTPS probably won’t be an issue for you. Defer the problem until you have heaps of traffic and you see your servers getting hammered with a huge amount of load. One solution would be to terminate the HTTPS requests at your infrastructure load balancer(s) and use a reverse proxy/Varnish to handle all the caching of these assets (images, JavaScript) and pages – this reduces the load on your servers but it does mean that traffic will be hitting your infrastructure.

      Good luck.
      Brett.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: