gbRememberMePlugin - 1.0.0

A secure "remember me" functionality

You are currently browsing
the website for symfony 1

Visit the Symfony2 website


« Back to the Plugins Home

Signin


Forgot your password?
Create an account

Tools

Stats

advanced search
Information Readme Dependencies Releases Changelog Contribute
Show source

gbRememberMe plugin

The gbRememberMe is a Symfony plugin that changes the behavior of the "remember me" feature of the sfDoctrineGuard plugin, allowing to remember multiple browser instances on multiple computers and detecting cookie theft.

Installation

  • Install the plugin (via a package)

    symfony plugin:install gbRememberMePlugin
    
  • Install the plugin (via a Git checkout)

    git checkout git://github.com/gbirke/gbRememberMe.git plugins/gbRememberMePlugin
    
  • Activate the plugin in the config/ProjectConfiguration.class.php

    class ProjectConfiguration extends sfProjectConfiguration
    {
      public function setup()
      {
        $this->enablePlugins(array(
          'sfDoctrinePlugin', 
          'sfDoctrineGuardPlugin',
          'gbRememberMePlugin',
          '...'
        ));
      }
    }
  • Rebuild your model

    symfony doctrine:build-model
    symfony doctrine:build-sql
    
  • Update you database tables by starting from scratch (it will delete all the existing tables, then re-create them):

    symfony doctrine:insert-sql
    

    or do everything with one command

    symfony doctrine-build-all-reload frontend
    

    or you can just create the new tables by using the generated SQL statements in data/sql/plugins.sfGuardAuth.lib.model.schema.sql

  • If you want to enable a warning page when cookie theft has occured, or the option for the user to remove all his stored login tokens, enable the gbSecurity module in your settings.yml of your application

          all:
            .settings:
              enabled_modules:      [default, sfGuardAuth, gbSecurity]
    
  • Clear your cache

    symfony cc
    
  • Add the "Remember Me" filter to filters.yml above the security filter:

    remember_me:
      class: gbRememberMeFilter
     
    security: ~
  • Change the parent class in myUser.class.php

    class myUser extends gbSecurityUser
    {
    }
    

Customize gbSecurity module templates

By default, gbSecurity module comes with 2 very simple templates:

  • warningSuccess.php contains the warning the user receives when a cookie theft has been detected.
  • overviewSuccess.php contains the page where a user sees how many "remember me" tokens are stored and can clear them.

If you want to customize one of these templates:

  • Create a gbSecurity module in your application (don't use the init-module task, just create a gbSecurity directory)

  • Create a template with the name of the template you want to customize in the gbSecurity/templates directory

  • Symfony now renders your template instead of the default one

gbSecurityUser class

This class inherits from the sfGuardSecurityUser class from sfGuardAuth and is used for the user object in your symfony application. (because you changed the myUser base class earlier).

The only methods that have been changed are the signIn and signOut methods to accomodate the new "remember me" scheme. The signIn method of sfGuardSecurityUser is always called with the $remember param set to false.

Change the name or expiration period of the "Remember Me" cookie

By default, the "Remember Me" feature creates a cookie named gbRemember that will last 30 days. You can change this behavior in app.yml:

all:
  gb_remember_me_plugin:
     token_expiration_age:  1296000   # 15 days in seconds
     cookie_name:           myAppRememberMe

Detecting that a user has not logged in with his credentials

When a user logs in via "remember me" cookie, you can't be sure he is really whom he claims to be. So before any "dangerous" action in your application (change credentials, see stored credit card information) you should check how the user has logged in and ask again for his credentials if he logged in with the "remember me" function:

// In your "dangerous" action
if($this->getUser()->getAttribute('logged_in_with_remember_me', false)) {
  // Store current action and params
  // forward to an action where the user must enter his credentials
}

How does the cookie theft protection work?

The regular "remember me" function works by storing a unique 128-bit persistent token in a cookie. The token is also stored in the database, together with the user id. When the cookie exists in a request, the user is logged in without needing credentials. The login token can be sniffed from the HTTP headers or stolen from the server when an attacker gets access to the token database. The attacker can then impersonate the users. There is no protection against that, but a theft can be detected by storing a second token, that is regenerated on every login. In the best case the user logs in before the attacker, the token of the attacker gets invalid and he can't log in. In the worst case the attacker logs in first. When the user logs in, his token is invalid and he can be informed of the security breach.

In either case, when an invalid token is encountered, all "remember me" tokens should be purged from the database. If you have activated the gbSecurity module, the warning action where does that for you. When an invalid token is detected, the visitor is redirected to that action.

This method has been described in the blog article "[Improved persistent login cookie best practice][1]". Other than described in the article gbRememberMePlugin does not store the user id in the cookie for security reasons.

The cookie that is set is marked "HTTP only" so it can't be read via JavaScript. This is another security improvement compared to the "remember me" function of sfGuardAuth.

Future plans

For increased security, I'd like to incorporate different "salts" into the token:

  • the user agent
  • the ip address
  • a random string

The cookie contains the unsalted tokens, db contains the salted tokens, making it even more difficult for an attacker to impersonate a user.

[1][http://jaspan.com/improved%5Fpersistent%5Flogin%5Fcookie%5Fbest%5Fpractice]