Ruby on Rails Security Project

Exploring the Security of Rails and friends.

Ruby on Rails Security Project header image 2

Session fixation in Rails

April 15th, 2007 · 4 Comments

These attacks focus on fixing a user's session identifier known to the attacker, and forcing the user's browser and the web application into using this identifier. The first step in such attacks is to create a valid session identifier. While other session managements (in PHP, for example) accept arbitrary identifiers, and create a valid session with the session identifier if it does not exist yet, this is not possible in Ruby on Rails.Rails accepts only session identifiers which have been generated by itself, and will issue a new one if you propose an arbitrary one. So with Rails applications, an attacker has to access the site of web application in order to obtain a valid session identifier.

The next step is to force a victim's web browser into using this identifier, which is know as the actual session fixation. According to RFC2965, a website cannot set a cookie for another domain. So the attacker cannot set a cookie for the web application by luring him on a site that he controls. One possibility to fixate the session, which requires the ability to sniff and modify data traffic between the user and the web application, is to change the session identifier in a response from the server. Or, if he has access to the user's DNS-server, he can redirect requests to a server taken over by the attacker, which forwards and modifies request to and from the original web server. The next two possibilities to fixate the session have to do with User Agent Injection (also: XSS) vulnerabilities. The first approach to do this is to change the cookie by setting document.cookie to a desired value, for example in JavaScript:

 

document.cookie='_session_id=16d5b78abb28e3d6206b60f22a03c8d9';

However, a web application administrator might know this vulnerability, and therefore has an appropriate flter for that. A less known approach is to set the cookie with an injected <META> HTML tag. Normally, <META> tags belong between the <HEAD> tags at the beginning of the document, however, it will be processed by the browser anywhere in the document. Inject this line, for example:

<meta http-equiv=Set-Cookie content="_session_id=
4cf69dc5fee46251bdc1f99ef55f52b6">

After the session identifier has been successfully injected into the user's browser and he logged in to the trap session, the attacker will be able to use the session, until the user logs out.

A good countermeasure against creating a valid session identifier is to not to issue them on pages that everyone can access. That means, for example the login page, should not send a session identifier to the yet unauthorized user, do so only after the user has been authorized. With the following you can turn the use of sessions in a specific controller off:

 

session :off # turn it off for any action
# or turn it off for any but these actions
session :off, :except => [ :change_password, :edit, :delete ]

However, you have to bear in mind that a request to any URL which issues a session identifier to logged in users also issues it to unauthorized users, but redirects then. And if the application is open to everyone, i.e. you can sign up on your own, you cannot prevent an attacker from signing up and retrieving a valid session identifier.

One of the most effective countermeasures is to issue a new session identifier after a successful login. That way, an attacker cannot use the fixed session identifier. By the way,this is also a good countermeasure against session hijacking. The following lines create a new session in Rails:
 

reset_session

Tags: Rails

4 responses so far ↓

  • 1 graste // Apr 18, 2007 at 5:33

    Thanks for all theses posts. They are always a nice read. All web applications suffer from the same problems, regardless of the used programming language and framework. To refer to some of the more important things here with solutions for RoR is a good thing. :)

  • 2 SJML // May 21, 2007 at 23:09

    When I try to use:


    @request.reset_session
    @session = @request.session

    I end up with a nil session object by the time I hit the next controller. Do I have to do something special to make sure it gets saved? I’m using ActiveRecord to store my sessions, if that makes a difference.

  • 3 Sanjeev // Jun 19, 2007 at 13:27

    just execute

    reset_session

    older session will be deleted and and you session will contain a new session record.

  • 4 Jon // Sep 12, 2007 at 8:31

    Unfortunately, this doesn’t save any session data that you have created; that’s why (I think) that SJML is getting a nil object; that’s the same issue I have and I haven’t been able to figure out how to quickly save my data, except to copy it over one at a time. That’s not great, since that means I have to know in one method things that have been saved for another method. Even more, you lose the “back” information stored in the “session_back_or_default” method of the login controller…

Leave a Comment