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

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"

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.

is rails "secret_token" still important with config.session_store(:cache_store)?

i've done my google due diligence and can't find an explicit answer. so, good people of stack overflow...
if, in a rails 3 app, i'm not using cookies to store sessions, is it important to securely manage the "Application.config.secret_token"? furthermore, it is used at all?
The secret_token is used by the cookie_store, used to store session data client side. Here is a nice write-up of how to execute arbitrary code using a known secret_token.
This cookie_store is more precisely ActionDispatch::Session::CookieStore, a rack middleware that rails loads into your rack stack when you set session_store(:cookie_store). So if you're setting that to :session_store you should be fine not setting secret_token.
You can examine Rails.configuration.middleware to see all your middlewares and confirm ActionDispatch::Session::CookieStore is not one of them.
FWIW, a rails 3.2 app will start with secret_token not set, but requests that try to set session variables will fail 500. I haven't tracked down exactly where the failure happens.
But if you're not setting secret_token, and you don't have ActionDispatch::Session::CookieStore in your rack stack, and your app appears to work, you are safe from that particular attack.
The other use of secret_token is digest authentication.
In summary, to answer the question, if you're not using digest authentication, and you don't use cookie_store (e.g., by setting session_store(:cache_store)), then secret_token is not important.
The Application.config.secret_token is also used for HTTP Basic and Digest Access Authentication.
Rais 3.2 HTTP Basic and Digest Access Authentication source file
Basic and Digest Access Authentication RFC

How to secure a Rails app against Firesheep?

I have not been able to find an easy guide for securing a Ruby on Rails app against a Firesheep.
In case you don't know, Firesheep jacks session cookies if your app doesn't force SSL and set the secure flag in the cookie. I had to do some searching to find these two things, so I thought I'd post what I found here and see if there is anything else I'm missing.
Step 1 Force SSL
There are two ways to do this that I found. One is using the ssl_requirement plugin, but this is a pain because you have to specifically specify ssl_required :action1, :action2 in every controller.
The preferable way appears to be by using Rack Middleware, via this post: Force SSL using ssl_requirement in Rails 2 app. Works like a charm.
Step 2 Make cookies secure
For this I followed these directions, which tell you to put the following in your config/environment/production.rb file:
config.action_controller.session = {
:key => 'name_of_session_goes_here',
:secret => 'you need to fill in a fairly long secret here and obviously do not copy paste this one',
:expire_after => 14 * 24 * 3600, #I keep folks logged in for two weeks
:secure => true #The session will now not be sent or received on HTTP requests.
}
This was all pretty straight-forward on my Rails 2.x app. Did I miss anything? Is it different for Rails 3?
Looks pretty good to me. It's pretty similar in Rails 3, though by default the session config is stored in config/initializers/session_store.rb. I usually tweak mine to look something like...
MyApp::Application.config.session_store :cookie_store, :key => '_my_app_session',
:secure => Rails.env == 'production', # Only send cookie over SSL when in production mode
:httponly => true, # Don't allow Javascript to access the cookie (mitigates cookie-based XSS exploits)
:expire_after => 60.minutes
And the secret is held in config/initializers/secret_token.rb:
MyApp::Application.config.secret_token = 'secret secrets are no fun...'
If you have access to your Apache (or whatever) config, you can also force SSL usage at that level. Strikes me as a more appropriate place to do that, but I guess not everyone has that option.
Seeing as this SO post ranks pretty high in Google I thought I'd share the approach I used for securing an app.
If you want to ensure SSL and also ensure secure cookies then you could use a Rack middleware:
https://github.com/tobmatth/rack-ssl-enforcer
I evaluated lots of different options and configuration settings for doing this but the rack middleware felt like the best option with the least amount of config - very easy to deploy. It has some great config options to filter specific rules, hosts, paths etc.
I tested that it does indeed set secure cookies correctly and it does. The one thing I noted was it only did it when logging out and logging in again - but that was using Devise.

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"] %>

are cookies mandatory for Ruby on Rails app?

is it true that Rails depend on cookies? It seems that flash is a part
of session, and session uses cookies... so when i disable cookie in
Firefox, a Rails app that was working shows
[error]
ActionController::InvalidAuthenticityToken
so is it true that for a RoR app to work, cookies are mandatory?
Update: or, to make the Rails app work again, what is the simplest way? (and if it is one server only (Apache running mod_rails), then is it easier?)
They are not mandatory, but there are some things you can't do without cookies. You can turn the authenticity tokens off as described here.
It's not mandatory to use cookies, but it is the rails default from 2.x up. Using cookies serves as a simple solution to some more difficult problems that arise when you try to store cookies in memory on multiple servers (and you get into things like sticky sessions, losing user data etc).
You can set where rails stores your session data; that is the flash and anything that's associated with the specific user. In environment.rb you can configure where you store your sessions using the config.action_controller.session_store. The options for this are: :cookie_store, :active_record_store, :p_store, :drb_store, :mem_cache_store, or :memory_store.
cookie_store is the default, if you comment the option out or remove it from environemnt.rb. It's also the most versatile. If you have multiple servers, one request for a user might come into one server, and the next request might come into a different server. In this situation, you couldn't use memory_store, as the 2nd server wouldn't know anything about the current user.
By storing session information in an encrypted cookie, there is less load on the server to store this information. The only downside is that each request to the server needs to pass the cookie (usually <1k), but it's not a noticeable difference in anything I've ever experienced.
:cookie_store, :mem_cache_store and :active_record_store are the most commonly used ones.

Resources