2

In my app, I have a User model and it has a rememberable_token column. When creating a user, a random secure string is saved in a before_create filter to act as a secure token for the user:

user.rememberable_token = SecureRandom.urlsafe_base64

In the session controller, it creates a permanent cookie with the value of that token so that the user doesn't get logged out when closing the browser and only gets logged out when they log out via the logout action:

Session controller:

def create
  .
  .
  cookies.permanent.signed[:permanent_user_session] = user.rememberable_token
end

def logout  
  cookies.delete :permanent_user_session
  redirect_to root_url  
end

The cookie is used in the application controller to determine if there is a current user as well as in a before_filter that is used in a few controllers to determine if a user is logged in and authorized.

Application controller:

def current_user  
  @current_user ||= User.find_by_rememberable_token(cookies.signed[:permanent_user_session]) if cookies.signed[:permanent_user_session]
end

def authorize
  unless User.find_by_rememberable_token(cookies.signed[:permanent_user_session])
    render :action => 'login'
  end
end

The question is if this is safe or if it is prone to session hijacking? If it is prone to hijacking, would it be alright if in the session#logout method it created a new rememberable_token for the user just before deleting the existing cookie (but not creating a new cookie with that value)?

Thank you.

ilmhlueq
  • 23
  • 2

2 Answers2

1

If someone is stealing the cookie, this code:

def current_user  
 @current_user ||= User.find_by_rememberable_token(cookies.signed[:permanent_user_session]) if cookies.signed[:permanent_user_session]
end

will still work. On your logout method you have to delete the token from user table and recreated at login.

Basically, what you are doing at create should be done at each login and reverted at each logout.

Eduard
  • 3,068
  • 1
  • 17
  • 25
  • If a user stays logged in for a week, then anyone that steals their cookie would be able to steal their session though. Is this worrying or is that actually possible with any type of login session cookie? – ilmhlueq Feb 06 '13 at 13:09
  • This is not a vulnerability of the session cookie. It is the same even if you keep the session on server side and only the session id on the cookie. You can expire session at every 30 minutes, but at each request reset the timer. This gives the attacker only 30 minutes interval to do the attack, but also removes the ability to keep the user logged in for weeks. – Eduard Feb 06 '13 at 13:12
  • 3
    Also, please be careful: And DO NOT STORE THE PERSISTENT LOGIN COOKIE (TOKEN) IN YOUR DATABASE, ONLY A HASH OF IT! The login token is Password Equivalent, so if an attacker got his hands on your database, he/she could use the tokens to log in to any account, just as if they were cleartext login-password combinations. Therefore, use strong salted hashing (bcrypt / phpass) when storing persistent login tokens. This and much more about logins you can find on this topic: http://stackoverflow.com/questions/549/the-definitive-guide-to-forms-based-website-authentication – Eduard Feb 06 '13 at 13:27
0

I'd probably do this:

On session create:

random_string = SecureRandom.urlsafe_base64
cookies.permanent.signed[:permanent_user_session] = random_string   
user.rememberable_token = Digest::MD5.hexdigest(random_string) && user.save

On session destroy:

cookies.delete :permanent_user_session

In the application controller:

def current_user  
  @current_user ||= User.find_by_rememberable_token(Digest::MD5.hexdigest(cookies.signed[:permanent_user_session])) if cookies.signed[:permanent_user_session]
end

def authorize
  unless @current_user
    render :action => 'login'
  end
end

This way, you're storing a hash of the token and a new one is regenerated for every new login (and expired on every log out). Rails takes care of CSRF but long-term sessions are probably not a good idea.

Simpleton
  • 5,889
  • 10
  • 48
  • 83