Devise for Twitter, Cookie Overflow error? - ruby-on-rails

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.

Related

How to prevent a session replay attack with Rails and Devise?

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

How can I reset all devise sessions so every user has to login again?

At some mystery point X with this rails app hosted on heroku, a logged in user would suddenly be logged in as another user. I am using the devise gem for authentication.
This has occurred for 2 users that we know of. I am currently tracking down what the root cause of this issue could be.
What I need to do right now is invalidate all devise sessions in order to force users to login again. After a user logs in, the problem seems to go away.
I tried reseting my secret_token but I was not forced to login again. I then scaled my web dynos down and then back up. I also restarted the app. All trying to get the secret_token change to reset the sessions.
Any other ideas?
You should be able to change your session cookie name to invalidate all sessions, which lives in config/initializers/session_store.rb
YourApp::Application.config.session_store :cookie_store, key: '_change_me_session'
Changing your session_token will work if you're storing your sessions in cookies (default).
But if you're storing in active_record, then you can delete all the sessions by:
rake db:sessions:clear
then: BAM! no more sessions.
Update on the accepted answer, now it is
rake tmp:clear
rake -T
...
rake tmp:create # Creates tmp directories for sessions, cache, sockets, and pids
If your sessions don't store any other critical information, you could clear the sessions:
rake db:sessions:clear
Devise has a thing called timeoutable can you work with that?
Check out
module ClassMethods
Devise::Models.config(self, :timeout_in)
end
I'm just guessing that you could do something like:
User.all.each do |user|
user.timeout_in 1.second
end
But I'm not sure if this only manages new sessions.. and not existing ones?
Actually this is overly complex.. just try:
User.all.each do |user|
sign_out user
end
See this post Log out all user with Devise
to do something like this from the console you will need to check out this example and adjust it for your needs
How to sign in a user using Devise from a Rails console?
sign_out_all_scopes(lock = true) ⇒ Object
Sign out all active users or scopes. This helper is useful for signing out all roles in one click. This signs out ALL scopes in warden. Returns true if there was at least one logout and false if there was no user logged in on all scopes.
source:
http://www.rubydoc.info/github/plataformatec/devise/Devise/Controllers/SignInOut
When cookie store is used, we have to regenerate the app secret_token which is used to encrypt the cookies.
file to configure secret_token: config/initializers/secret_token.rb
bundle exec rake secret Can be used to generate a new secret token.
https://www.tigraine.at/2012/08/03/how-to-expire-all-active-sessions-in-rails-3
Try this on your controller actions.
def index
reset_session
end

Sessions in Rails 4

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 (...)

Rails + Sinatra apps sharing sessions

I haven't found a good answer to this yet. How can I get my Rails app and Sinatra app (mounted in my Rails app's config.ru) to share a session successfully? If I visit my Sinatra app first, then the Rails app, I get an error like undefined method sweep for {}:Hash, presumably because Rails uses a custom subclass of Hash for storing session info, and Rack::Session::Cookie doesn't. My code so far:
config.ru
map "/" do
run MyRailsApp::Application
end
map "/sinatra" do
use Rack::Session::Cookie,
key: "_app_session",
secret: "<SECRET_KEY>"
run MySinatraApp
end
config/initializers/session_store.rb
MyRailsApp::Application.config.session_store :cookie_store, key: '_app_session'
config/initializers/secret_token.rb
MyRailsApp::Application.config.secret_token = "<SECRET_KEY>" # same as config.ru
Anything I've missed?
A quick grep of the Rails source reveals sweep is a method on ActionDispatch::Flash::FlashHash, which Rails stores in the session under the flash key.
Sinatra-Flash also uses the flash key of the session, but it stores a plain Hash object there.
Rails is getting the object at session['flash'], which is the Hash put there by Sinatra, assuming it is a FlashHash and trying to call sweep on it, hence the error message: undefined method sweep for {}:Hash.
A possible work around might be to use a different key in the Sinatra app for the flash rather than the default (e.g. flash(:my_flash)[:error]="foo").
That won't help if you want to use the flash to see messages when going between Rails and Sinatra though.
The "undefined method sweep for {}:Hash" issue is with your browser storing previously cached cookies. Just delete the cookies related to the application and refresh the browser. It worked for me.

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.

Resources