Cookies without authentication ? (and cookie value) - ruby-on-rails

I have a Rails app with Devise and was checking on front end if my Rails app was implementing cookies in order to comply with European rules regarding cookies.
I was a bit surprised as my Rails app actually add cookies to the client even without any Devise authentication ...
The cookie has name _myapp_session
Actually it is a good thing as I could add the cookie law information inside this cookie (user gets to see the cookie law warning only once)
...Yet each time I reload the root page in my browser the cookie is renewed.. So it doesn't actually look like a session cookie.
Is there a wrong setup in my initializer or can someone help me fix this ? (or maybe this is completely normal)
EDIT : Maybe my mistake : the cookie value is changing on every page yet the session creation time is not changing so I guess it is still valid to consider it a session cookie. I will search the web for a thorough explanation on cookies as the cookie value changing all the time is probably a feature.

Cookies are created by default in Rails Application.
Also, you're probably using Rememberable module in Devise which uses cookies.
Devise 'refreshes' csrf token after each request. Hence why it changes.
Did you try to look inside cookie and see what it contains?
Here's how you might do it (old rails version):
https://blog.bigbinary.com/2013/03/19/cookies-on-rails.html

Related

Rails 4 session variable without a cookie

Because of the awesome EU directive on allowing users opt out from having cookies stored I have the following problem.
I have a message that displays at the top of the screen that asks the user to opt in or opt out.
if the user opts in, cookies are turned on using rack.policy, and the message is hidden. A cookie variable is set to say that the message should not be shown again for future visits. Perfect
If the user opts out. Cookies are disabled, fine. the message is cleared.... and a session variable is set to say don't show the message for this session. This would be fine, but it seems the session variable is saved in the same way as a cookie and the rack policy does not allow it to be displayed. The message therefore flashes up on every single page.
So first, thank you EU. Second, how do I save a "session variable" without saving to a cookie?
Unless you try going for something more exotic like local storage offered by the browser, you can't. The rails guide explicitly states:
All session stores use a cookie to store a unique ID for each session (you must use a cookie, Rails will not allow you to pass the session ID in the URL as this is less secure).
I'm no lawyer, but for what it's worth I believe that law is intended to apply to cookies used for marketing/tracking purposes and does not apply to cookies needed for the site to function like cookies used for authentication or ephemeral storage. With this in mind, you could use the rails's session cookie for must-have data and use separate cookies for other purposes that your application can disable.
I wouldn't take it as gospel, but this Wired article seems to a good job of providing a simplified explanation.

How does session and cookie work in Rails 4?

As I understand one of the strategies to store sessions is store it in the cookie. There is one thing I don't understand from the docs:
To prevent session hash tampering, a digest is calculated from the
session with a server-side secret and inserted into the end of the
cookie.
What does this mean? How do they prevent that, if I get a cookie from another user, and I use it in my browser, I can't pretend I am the other user? I guess I don't understand what session hash tampering means.
How do they prevent that, if I get a cookie from another user, and I
use it in my browser, I can't pretend I am the other user?
This is called session hijacking, and is covered in http://guides.rubyonrails.org/security.html#session-hijacking. The recommended way to to mitigate this is by "always forcing SSL connection in your application config file", like so:
config.force_ssl = true
The whole http://guides.rubyonrails.org/security.html is definitely worth a read, for more goodness like this.

Does Rails Devise gem uses cookies for authentication?

It would be great to have a supporting doc for the same.
I'm assuming the question can be restated as "Does Devise use a cookie to keep track of your session after authentication." If so, the answer is yes.
To test this, clear your cookies, log in and then check your cookies again. You'll see one for your website named after your app.
#Rodrigo, sessions are enabled by cookies. That's how the session can follow you through multiple pages. HTTP is inherently stateless. Cookies allow you to save state.
Not directly.
Devise is built on top of Warden, which uses the session. I don't see any easy way to use cookies for authentication (although you may use rememberable to keep it recorded between sessions). Sessions are enabled by cookies, so it uses the cookies indirectly.

How do I get Devise's Rememberable module to use http_only for the remember me cookie?

The rails session cookie is HttpOnly by default but the remember_user_token cookie set by Devise's Rememberable module is not.
As I understand it that cookie when sent will result in the user being issued a new session cookie, so surely it's as vulnerable to XSS.
So is there any way to set it to HttpOnly?
With the help of #camonz on #rubyonrails I came up with this monkey patch:
https://gist.github.com/749289
In Devise 1.1.3 the cookie options are hardcoded so a monkey patch is all I could think would work.
However, Devise 1.2rc looks like it will allow configuration because it pulls in resource.cookie_options (e.g. pulling cookie_options from the User model, so you should be able to set it there somehow - haven't figured that out yet).
P.S. I haven't figured out how to test this yet. To test manually in Chrome switch to the tab the cookie is set in, open Developer Tools with Alt + Cmd + I, switch to the Storage tab, click the item under 'Cookies' (localhost in my case), and look at the HTTP column. There'll be a tick if the cookie is HttpOnly. For reference the rails session cookie, called _session_id by default, is HttpOnly by default.

Implementation of "Remember me" in a Rails application

My Rails-app has a sign in box with a "remember me" checkbox. Users who check that box should remain logged in even after closing their browser. I'm keeping track of whether users are logged in by storing their id in the user's session.
But sessions are implemented in Rails as session cookies, which are not persistent. I can make them persistent:
class ApplicationController < ActionController::Base
before_filter :update_session_expiration_date
private
def update_session_expiration_date
options = ActionController::Base.session_options
unless options[:session_expires]
options[:session_expires] = 1.year.from_now
end
end
end
But that seems like a hack, which is surprising for such common functionality. Is there any better way?
Edit
Gareth's answer is pretty good, but I would still like an answer from someone familiar with Rails 2 (because of it's unique CookieSessionStore).
You should almost certainly not be extending the session cookie to be long lived.
Although not dealing specifically with rails this article goes to some length to explain 'remember me' best practices.
In summary though you should:
Add an extra column to the user table to accept a large random value
Set a long lived cookie on the client which combines the user id and the random value
When a new session starts, check for the existence of the id/value cookie and authenticate the new user if they match.
The author also recommends invalidating the random value and resetting the cookie at every login. Personally I don't like that as you then can't stay logged into a site on two computers. I would tend to make sure my password changing function also reset the random value thus locking out sessions on other machines.
As a final note, the advice he gives on making certain functions (password change/email change etc) unavailable to auto authenticated sessions is well worth following but rarely seen in the real world.
I have spent a while thinking about this and came to some conclusions. Rails session cookies are tamper-proof by default, so you really don't have to worry about a cookie being modified on the client end.
Here is what I've done:
Session cookie is set to be long-lived (6 months or so)
Inside the session store
An 'expires on' date that is set to login + 24 hours
user id
Authenticated = true so I can allow for anonymous user sesssions (not dangerous because of the cookie tamper protection)
I add a before_filter in the Application Controller that checks the 'expires on' part of the session.
When the user checks the "Remember Me" box, I just set the session[:expireson] date to be login + 2 weeks. No one can steal the cookie and stay logged in forever or masquerade as another user because the rails session cookie is tamper-proof.
I would suggest that you either take a look at the RESTful_Authentication plug in, which has an implementation of this, or just switch your implementation to use the RESTful Authentication_plugin. There is a good explanation about how to use this plug in at Railscasts:
railscasts #67 restful_authentication
Here is a link to the plugin itself
restful_authentication
The restful_authentication plugin has a good implementation of this:
http://agilewebdevelopment.com/plugins/restful_authentication
Note that you don't want to persist their session, just their identity. You'll create a fresh session for them when they return to your site. Generally you just assign a GUID to the user, write that to their cookie, then use it to look them up when they come back. Don't use their login name or user ID for the token as it could easily be guessed and allow crafty visitors to hijack other users' accounts.
This worked like a charm for me:
http://squarewheel.wordpress.com/2007/11/03/session-cookie-expiration-time-in-rails/
Now my CookieStore sessions expire after two weeks, whereby the user must submit their login credentials again in order to be persistently logged-in for another two weeks.
Bascially, it's as simple as:
including one file in vendor/plugins directory
set session expiry value in application controller using just one line
I would go for Devise for a brilliant authentication solution for rails.

Resources