I've noticed that after my app is deployed to Heroku the users are forced to log in again because their session cookies seem to expire.
Does anyone know what might be causing this? I'm using Devise and Rails 5.2, and my session store looks like this:
Rails.application.config.session_store :cookie_store,
key: '_example_session'
expire_after: 7.days,
domain: 'example.com'
My first suspicion was secret token might be regenerated somehow after deploy, but that doesn't seem to be case...
Related
We have a Rails 5.2.3 app in production using Devise 4.6.2 and being deployed at Heroku. The app was using a domain example.com and everything was fine. Today we needed to change that domain to app.example.com (example.com is now a WordPress site) and now when we try to log into the app we're getting:
Can't verify CSRF token authenticity
Completed 422 Unprocessable Entity in 19ms
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_controller/metal/request_forgery_protection.rb:211:in `handle_unverified_request'
One thing I've realized is that now our production app isn't setting the session cookie. Our staging app (which uses an example.herokuapp.com domain) sets a cookie named '_myapp_session' (and it's still working fine), while in our production app there's no cookie being set.
While googling about this I've found some mentions to the session_store.rb config (we didn't even had this file), so I created the file in config/initializers and tried to set to our app.example.com domain and also to domain: :all, but it didn't seem to make any difference.
Rails.application.config.session_store :cookie_store, key: '_app_myapp_session', domain: :all
What I am missing here? Why would the domain change stop the app from creating the session cookie?
Oh, and we're using Cloudflare as our DNS and its __cfduid cookie is being correctly set. Could that be related?
So, apparently it was indeed related to Cloudflare. Our app.example.com entry on Cloudflare's DNS was "proxied" and once I've set it to "DNS only" and waited a few minutes our session cookies started appearing again.
I've just now realized that Cloudflare has its own cache, so I've purged that and will try to use the "proxied" setting again, but if that doesn't work I'll just use it as DNS.
If someone has details on why Cloudflare's proxied setting would stop the cookies from being set, please let me know. Thanks!
Did you read this post about Cloudflare cached pages and CSRF?
Poor tl;dr: If you cache a page with a CSRF protected form you have to update de CSRF using Ajax.
https://blog.cloudflare.com/the-curious-case-of-caching-csrf-tokens/
We have a setup in a way that currently some pages are being served by a Rails 4 app and a Rails 5 app. All the authentication logic resides in the Rails 4 app and we are using Devise for authentication. The session_store.rb on the Rails 4 app looks like this Rails.application.config.session_store :cookie_store, key: '_app_store'. I want to have the current_user accessible in the Rails 5 app as well. Note: Both the apps are under the same domain. Also how should I go about setting devise on my Rails 5 app so that current_user is accessible.
First allow cookie to apply for all of your subdomains:
Rails.application.config.session_store :cookie_store, key: '_app_store', domain: :all
When the browser accesses a website, the website tells the browser to set a cookie. When this happens, it specifies the cookie name, value, domain, and path.
:domain => :all makes a dot in front of the cookie domain (which is whatever host your browser has browsed to), so the cookie applies to all subdomains.
Another good thread about this topic can be found here:
https://stackoverflow.com/a/4065929/1625253
So I have two rails apps on the same domain, which both use devise and ldap to authenticate to the same ldap server.
To store the cookie as cross session I changed both apps;
config\initializers\session_store.rb:
MyApp::Application.config.session_store :cookie_store, key: '_bioinf_exp_session', :expire_after => 2.hours, :domain => '.domain.com'
What this does is produce an: actioncontroller::invalidauthenticitytoken error in Devise::SessionsController.
Googling around I found that I needed to have the same secret keys in config\initializers\secret_store.rb. However, this didn't remove the problem.
I then tried giving the config.secret_key in devise.rb the same value across both apps, but the same error remains.
If someone could explain which parts I missing/misunderstanding that would be greatly appreciated.
I am working on a Rails app that recently went through a security audit, and one of the issues they came up with is that if the user gets the "session_id" from another users cookie, he is able to log in as that user. Is it possible to prevent this? How would I do it with my current setup?
Rails 3.2.12
devise (2.1.2)
My config/initializers/session_store.rb is
MyApp::Application.config.tap do |config|
config.session_store :active_record_store, config.session_options
end
Force SSL is enabled on production
config.force_ssl = true
I looked at Rails 4 Encrypted Cookie Replay Attack but since mine is using active record for sessions, not sure I can do the same.
I tried to add :session_limitable from Devise security extension, but it appears to be doing something else altogether.
To quote the security test result
Mitigate session replaying by ensuring that only 1 login is active at a time. -- able to login as another user just by changing the "_session_id" cookie
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.