Sessions and cookies in Ruby on Rails


An important issue rarely talked about with little documentation on Internet. So, here we go ... a guide to session and cookies in Rails. Session and cookies are an integral part of any good web application and rails has a good support for them. Continuing with our DRY approach, this guide contains link to cool articles with good description wherever necessary.

Table of Contents

  1. Introduction
  2. Sessions
    1. Session in rails
    2. Configure your sessions
    3. Storage options
    4. Session storage limitations
    5. Session and Security
    6. HowTo
      1. Implement session expiration
      2. Delete stale sessions
      3. Find out active users
      4. Access session data using session_id
    7. Miscellaneous
  3. Cookies
    1. Cookie on rails
    2. cookies vs. request.cookies
    3. CookieJar
    4. Miscellaneous

Introduction

HTTP is a stateless protocol which creates problem in uniquely tracking a visitor to a web application. The process of managing the state between browser and server is through the use of session IDs which uniquely identifies a client browser.

Session IDs can be stored and communicated in one of the following ways :
  1. Embedded in URL
  2. In form field
  3. Using cookies.

Information stored between multiple client browser request is called Session Data. Session data for each visitor can be stored at the server or in cookies. Upon client request to server, session data is extracted from session storage using session ID send by client browser. A good common example for session data is user information for authentication.

In the present times, its hard to imagine a good web application not using Sessions.

A wonderful article on implementation techniques of Session ID.
Tagged as  
Posted on 21 October
15 comment Bookmark   AddThis Social Bookmark Button Updated on 23 February

archive

Sessions and cookies in Ruby on Rails

An important issue rarely talked about with little documentation on Internet. So, here we go ... a guide to session and cookies in Rails. Session and cookies are an integral part of any good web application and rails has a good support for them. Continuing with our DRY approach, this guide contains link to cool articles with good description wherever necessary.

Table of Contents

  1. Introduction
  2. Sessions
    1. Session in rails
    2. Configure your sessions
    3. Storage options
    4. Session storage limitations
    5. Session and Security
    6. HowTo
      1. Implement session expiration
      2. Delete stale sessions
      3. Find out active users
      4. Access session data using session_id
    7. Miscellaneous
  3. Cookies
    1. Cookie on rails
    2. cookies vs. request.cookies
    3. CookieJar
    4. Miscellaneous

Introduction

HTTP is a stateless protocol which creates problem in uniquely tracking a visitor to a web application. The process of managing the state between browser and server is through the use of session IDs which uniquely identifies a client browser.

Session IDs can be stored and communicated in one of the following ways :
  1. Embedded in URL
  2. In form field
  3. Using cookies.

Information stored between multiple client browser request is called Session Data. Session data for each visitor can be stored at the server or in cookies. Upon client request to server, session data is extracted from session storage using session ID send by client browser. A good common example for session data is user information for authentication.

In the present times, its hard to imagine a good web application not using Sessions.

A wonderful article on implementation techniques of Session ID.

- Sessions -

Session in rails

Session in rails is a hash-like structure which allows you to store data across requests. Sessions can hold any kind of data object (with some limitations) because they store data using Data Marshalling (aka Data Serialization or Data Deflating).

Rails way of implementing session:
  1. session_id is a 32 hex character MD5 hash based upon time, random number and constant string. It is stored in cookie at client browser. Rails provides transparent support for session_id.
  2. Session storage discussed below.

Remember, you can insert or access values from session similar to hash ... but session is NOT a hash. Most of the other hash methods will not work with sessions.

Working with session in rails Data Serialization in Ruby CGI::Session creates a new instance of session everytime a new user visits your site.

Configure your sessions

Configure key, prefix, expiry and domain of your session. Switch on/off session at controller and action level. session_path and session_secure

Refer to next section on options for session storage.

Note: By default session_id is stored as key in cookies. For multiple rails application from same domain its a good practice to set 'session_key' to avoid conflicts.

Storage options

Ruby on Rails provides you with many session storage option.
  1. PStore
  2. ActiveRecordStore
  3. CookieStore
  4. DRbStore
  5. FileStore
  6. MemoryStore

CookieStore is available only in edge rails. PStore is the default option for stable release, whereas its CookieStore as default for edge rails.

Good description on session stores. Cookie-based session storage Improve performance : use SQLSessionStore instead of ActiveRecordStore Comparison of session storage option

Session storage limitations

Following objects cannot be stored in session storage:
  1. Bindings
  2. Singleton
  3. I/O objects
  4. Procedure objects
Do not store model objects in session
  1. Change in model objects saved in session would also change table row corresponding to model object.
  2. Breaks validations.
  3. On change in class definition, model objects in session will go out of sync.
  4. A general belief is marshalling/unmarshalling of session on each request is expensive. This might be wrong - read Eric Hodel's comment at :

Incase you are storing model objects in session, upon change in class definition you will need to delete sessions and then restart your applications.

More limitations :
  1. Store only user-specific data. Session data will become stale if other users can modify/update it. For e.g. if you store blog comments in session then session of active users need to be explicitly updated when new comment in made.
  2. Critical information should be stored in database and not sessions as you might loose information if client cookie is lost/deleted. For e.g. user purchase information on a shopping site.
  3. Session are not meant for storing massive objects or tons of information, use your application database instead.

Session and Security

A detailed look into security issues concerning sessions. Lookout into sections named as 'Session Hijacking' and 'Common Failings' Minimize session attacks Using XSS attacks a hacker can steal user's session-id ... be careful.

HowTo

Implement session expiration

A good description A concise version

Delete stale sessions

Every session created in session storage (ActiveReocord, PStore ...) is not deleted upon session expiration or browser close by client. Which means you will have to run a cron job to delete old sessions else your session storage will shoot up in size.

As a good practice disable sessions for those part of your web application which does not require sessions. This will avoid creation and storing unnecessary sessions in your storage.

Find out active users

If you want to find no. of active users, simply use updated_at column of sessions table.

Access session data using session_id

This might be helpful if another application in same domain wants to access your session.

Miscellaneous

  1. Use model method to access row in sessions table corresponding to current session. For e.g. session.model.id or session.model.updated_at
  2. Smart plugin for better session experience in rails specially for session expiration.
  3. Flash messages to communicate between actions are stored in sessions. So, if you switch off your sessions, flash messages will stop working.
  4. Do not let bots make unnecessary sessions
  5. Do not write unchanged sessions back to database -- improves performance
  6. Non-cookie session :

    If the client has cookies disabled, the session_id must be included as a parameter of all requests sent by the client to the server. The CGI::Session class will transparently add the session_id as a hidden input field to all forms generated. No built-in support is provided for other mechanisms, such as URL re-writing.

    If you care about browsers which do not support cookies, checkout the following plugins (disclaimer : I have never used these plugins :P )

    Beware, session information in URL might be dangerous. Someone might post a link to a product on a board and everyone following this link is logged with all user data available.

  7. PStore in Windows : Marshal Data Too Short Error

- Cookies -

Cookie on rails

Cookies are stored at client browser and is sent back to server on each request. Rails provides a hash-like structure ActionController#cookies in controller to manage cookies. Session in rails is implemented using cookies.

Description, options and example Note :
  1. Only string can be stored in cookies.
  2. session_id is by default stored in cookies at client browser.

cookies vs. request.cookies

Both cookies and request.cookies are used to access cookie information in your rails application. They are very different in their behavior which can be daunting for beginners. Examples below explains the basic difference between them.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

## cookies and request.cookies are different
cookies.class #=> ActionController::CookieJar
request.cookies #=> Hash

## how to access value from cookies and request.cookies
# First set some value in cookies
cookies[:key] = "value"

cookies["key"] #=> "value"
cookies[:key] #=> "value"
# both the output are of type String

request.cookies["key"] #=> "value"
request.cookies["key"].class #=> CGI::Cookie

request.cookies[:key].empty? #=> true
request.cookies[:key].class #=> Array

CookieJar

cookies in rails is of type CookieJar. CookieJar manages incoming and outgoing cookie information and works as follows.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

def index
  cookies[:key] = "val"
  puts cookies[:key]
  redirect_to :second_index
end

def second_index
  cookies[:key] = "newval"
  puts cookies[:key]
end

## Output :
## Open index page for the first time
# nil
# val

## Open index page the second time
# newval
# val
So,
cookies[] gives you value from the incoming cookie.
cookies[]= sets value in the outgoing cookie.

Reference :

Miscellaneous

Checkout cookie based session store explained above.

Testing cookies Open ticket - making CookieJar behave like a Hash. Performance and cookies : a good read