Sessions in Rails 4 - ruby-on-rails

If ActiveRecord::Store is being deprecated, what is the suggested method for maintaining session? Is encrypted cookie store the new standard? What if you want to maintain >4kb in state?

In Rails 4, includegem 'activerecord-session_store' in your Gemfile and run bundle install. Complete the migration and configuration as per https://github.com/rails/activerecord-session_store notes.
The other alternative is using the 'dalli' gem for session management.

Look out for the file named session_store.rb inside your config/initializers folder. There you should setup which kind of session you would like to use. A standard, cookie based one, should be like:
ProjectName::Application.config.session_store :cookie_store, key: '_project_name_session'
After that all you need to do is call the hash session from within your controllers. You can set any value there and it will persist in between requests.
As in Rails Guides:
config.session_store is usually set up in config/initializers/session_store.rb and specifies what class to use to store the session. Possible values are :cookie_store which is the default, :mem_cache_store, and :disabled. The last one tells Rails not to deal with sessions. Custom session stores can also be specified (...)

Related

Rails how to use an in Memory SessionStore

I'm looking for a way to use an in memory based session store in a Ruby on Rails application. The session contains a masterkey which can only be decrypted when the users logs in. This key should be available during the entire session.
Due to the nature of this key, the content of the session should not be stored anywhere locally. Also I don't want to transfer the content to any external application, such as memcached.
Thus is it possible to just use an in memory based session store similar to PHP or Java SE?
Rails 5
From version 5, Rails no longer creates a config/initializers/session_store.rb file at install.
In rails 5, the default session store is setup internally (to cookie store), and no longer through an application initializer, as was the case up to Rails 4.
cf. https://github.com/rails/rails/issues/25181
In a pure Rails 5 app (= non-migrated), to change your session store, e.g. from :cookie_store to :cache_store, you will have to create yourself the config/initializers/session_store.rb file, and then add the relevant instruction:
# Be sure to restart your server when you modify this file.
Rails.application.config.session_store :cache_store, key: '_your_app_session'
Beware that you will need to change the key from '_your_app_session' to match your application name (if for ex your app is named calculator then should be '_calculator_session')...
You can use a CacheStore to store session data in-memory.
# /config/initializers/session_store.rb
AppName::Application.config.session_store :cache_store
Or you can write your own SessionStore class:
http://guides.rubyonrails.org/configuring.html#rails-general-configuration
You can use a MemoryStore, but it's a really bad practice as it is not shared between machines, so your application will not be scalable.
From a security standpoint there's no real reason you shouldn't transfer this key to an external memcached or redis.
You should secure your production infrastructure as a whole, encrypt any data exchange between your servers, or put them in a trusted network, make good use of firewalls and follow best practices. Your cache servers should be as secure as your app servers, or databases, no excuses.

Devise for Twitter, Cookie Overflow error?

I am trying to integrate twitter into devise using this guide. I basically take all occurence of facebook and substitue it with twitter. However, when I sign in with twitter, I am getting the following error:
ActionDispatch::Cookies::CookieOverflow (ActionDispatch::Cookies::CookieOverflow):
at the following url:
http://localhost:3000/users/auth/twitter/callback?oauth_token=something&oauth_verifier=blah
Is there any nice way to get around fixing this problem?
Thanks!
The problem is with session["devise.facebook_data"] = env["omniauth.auth"]. Twitter's response contains an extra section that is very large and does not fit in the session. One option is to store env["omniauth.auth"].except("extra") in the session instead.
You can turn on ActiveRecord store for session.
Look in config/initializers/session_store.rb
comment out the line about using :cookie_store
uncomment the lines at the bottom about using :active_record_store
# Use the database for sessions instead of the cookie-based default,
# which shouldn't be used to store highly confidential information
# (create the session table with "rails generate session_migration")
MyApp::Application.config.session_store :active_record_store
Create migration before rails rails g session_migration and migrate it.

In a Sinatra App on Heroku, Session Is Not Shared Across Dynos

Which makes sense. But what are some preferred work arounds for this issue?
In my comment, I suggested using rack cookie based sessions, but looking into it, the Sinatra sessions are Rack cookie sessions anyway.
Looking further, I found this in the Sinatra docs:
To improve security, the session data in the cookie is signed with a session secret. A random secret is generate for you by Sinatra. However, since this secret will change with every start of your application, you might want to set the secret yourself, so all your application instances share it:
set :session_secret, 'super secret'
So it seems each Heroku dyno is generating a different key, and so can't read each others session cookies, and you need to specify a key so each dyno uses the same one.
Rather than add a secret key to your source code, you're probably better setting an environment variable:
$ heroku config:add SESSION_KEY=a_longish_secret_key
Then in your sinatra app:
enable :sessions
set :session_secret, ENV['SESSION_KEY']
You can also use a memcached session for performance or security. Have not tried it but looked easy. 5MB free on heroku.
# In your app.rb file just add following -
enable :sessions
set :session_secret, "some_random_value"

Rails sessions current practices

Anyone have any "best practices" tips for Rails and sessions? The default session type for Rails 3 is still CookieStore, right? I used SqlSessionStore for a while and it worked well, but I may move away from that in favor of CookieStore.
Is it still not a good idea to use CookieStore for sensitive info, even with salted info or is that better stored in the DB?
Use the database for sessions instead of the cookie-based default, which shouldn't be used to store highly confidential information
Create the session table with
rake db:sessions:create
Run the migration
rake db:migrate
Make sure you also tell rails to use ActiveRecord to manage your sessions too.
Rails 3
config/initializers/session_store.rb:
Rails.application.config.session_store :active_record_store
Rails 2
config/environment.rb:
config.action_controller.session_store = :active_record_store
Cookies are encrypted by default in Rails 4
In Rails 4, CookieStore cookies are encrypted and signed by default:
If you only have secret_token set, your cookies will be signed, but not
encrypted. This means a user cannot alter their user_id without knowing your
app's secret key, but can easily read their user_id. This was the default
for Rails 3 apps.
If you have secret_key_base set, your cookies will be encrypted. This goes a
step further than signed cookies in that encrypted cookies cannot be altered
or read by users. This is the default starting in Rails 4.
If you have both secret_token and secret_key_base set, your cookies will
be encrypted, and signed cookies generated by Rails 3 will be transparently
read and encrypted to provide a smooth upgrade path.
Active Record Session Store is Deprecated in Rails 4
This answer is now out-of-date with regard to Rails 4. The Active Record
Session Store has been deprecated and removed from Rails, so the following
generators will no longer work:
rake db:sessions:create
rails generate session_migration
This was pointed out in this answer. The reason that the Active Record
Session Store was deprecated is because the reads/writes to the database don't
scale well when you have a large number of users accessing your application, as
stated in this blog post:
...one major issue with the Active Record session store is that it is not
scalable. It puts an unnecessary load on your database. Once your application
receives a large amount of traffic, the sessions database table is
continuously bombarded with read/write operations.
As of Rails 4, the Active Record session store has be removed from the core
framework and is now deprecated.
If you still want to use the Active Record Session Store, it's still available
as a gem.
Current Rails Session Best Practices
For more current best practices for Ruby on Rails sessions, I advise that you
check out the lastest versions of the Ruby on Rails Security Guide.
I don't believe anything has changed in how anyone on any platform should handle cookie based sessions. Be skeptical of anything that passes beyond the server's control (cookies, form posts, etc.) Thats a general principle of web development.
As far the encryption, I don't know if anything has changed on that front.
Something to be mindful of with a cookie store is the limit to the amount of data, and the gotcha that this data will be sent on the wire in every request, where as a database store only transfers the id and the data lives on the server.
FWIW, rails 3.1 suggests running
rails generate session_migration
However this generates the exact same migration as
rake db:sessions:create
The Rails defaults seem pretty good to me- The CookieStore is fast and should cover the majority of use cases. Sure you're limited to 4kb and your data will be visible to the user, but the Rails way is to only use session for things like integer IDs and basic string values- If you're trying to store objects or highly confidential information in session you're probably doing it wrong.

Command to clear the cookie-based session store in Rails

I often want to clear the session store in Rails, in particular, the default cookie-based session store. Some sites seem to suggest that
rake tmp:sessions:clear
accomplishes this task, but it appears that it does not. What is the proper way to clear the cookie-based session store?
If you use Cookie based sessions
You can change the secret_token of your rails app. This will invalidate all existing sessions.
rake secret
Then copy the value in to
RAILS_ROOT/config/initializers/session_store.rb
Thats it. Remember to restart your app after this ;)
If you use database based sessions
rake db:sessions:clear
If you use file based sessions
rake tmp:sessions:clear
The problem is that cookies are client side. Running a rake task on your server won't delete cookies on all the machines that have visited the web page, obviously.
Perhaps you can use session.clear in your controllers somehow? You're right about changing the cookie key, though. Doing so would invalidate any session belonging to the old key. You would have to rescue from ActionController::StaleSession (or something like that), but it'd work.
Change the name of the session cookie. It won't delete the old cookies, but it'll force everyone to get a new session cookie.
It occurs to me now that what I want may not be possible depending on how the cookie-based store is implemented. If the cookies contain all the information the server needs (including a signature for data integrity) then the server does not need to store any information on its side therefore there is no way to invalidate existing cookies. I had assumed the cookie contained some key that corresponded to data on the server-side in order to verify that the cookie is valid, but now I realize this may not be the case.
If this is true, then the only way to clear cookies would be to change the server-side cookie secret used for signing and then presumably restart the server process.
If you are running this on a production server I recommend:
rake secret
Which is simply generating a random secure token. The rake task is basically doing this, which you could do in a console.
SecureRandom.hex(64)
Never check the production key into version control / GIT but use an environment variable instead. So in your config/secrets.yml file use something like:
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

Resources