I am running Rails 3 configured to use memcached for session store. I have the following setup:
development.rb
config.cache_store = :mem_cache_store
session_store.rb
Foo::Application.config.session_store :mem_cache_store, :key => '_foo_session'
I can start the app fine, when I go to any page I get the following error:
ArgumentError (key too long "rack:session:__really_long_session_key__"):
I realize the limit on memcached key is 255. How can I get around this, or am I doing something wrong?
You're almost certainly seeing this because you're switching from the cookie store to memcached. Your browser still has the old session cookie, with the long ID. You need to delete this cookie from your browser and the problem will go away.
If you're switching from cookie store to memcached on a production site, this will be a problem because you don't have control over your user's browsers. You'll probably need to change the session key to avoid problems in this case.
Is it possible you switched from the cookie store or you run other cookie session store apps on the same domain (e.g. localhost)?
In this case the cookie session store is responsible for the huge session_id string (because it actually stores the whole session in it). Just delete your session cookie and you are fine.
If your "key" is more than 255 characters, it sounds like you are doing something wrong. Why is your session key that long? What's wrong with MD5 or SHA1?
Related
In Rails, the default for storing the session is using cookie_store.
Application.config.session_store :cookie_store, key: '_myapp_session'
But sometimes, the session is stored in a database, like Redis.
Application.config.session_store(
:redis_store,
servers: config.redis_server,
key: '_myapp_sessions',
)
When should we use the cookie store and when should we use a database?
When you need to store more than 4KB of data in your session.
When you need more control over expiring sessions. Here are two examples where you might need this kind of control:
If you make a change to your app that requires new information to be in the session or there is a security breach and you need to expire all sessions so that all users need to sign in again, it is much easier if the sessions live in a database vs needing to change the secret_key_base to invalidate cookie_store sessions.
A Maintained Session is where an attacker keeps a session alive indefinitely. The problem is mentioned here https://guides.rubyonrails.org/security.html#session-expiry If you want to protect against a Maintained Session this is easily done using a database by setting a created_at attribute on the session and not with a cookie_store session because it gets re-created with each request.
If your rails app running on a cluster(multiple servers) environment or session data goes beyond 4KB(cookie store has the limit of 4KB memory) then use Redis or any other database.
While we were using FileStore as cache store and DalliStore as session store, we could run Rails.cache.clear and it would simply clear the cache with no problems in Sessions whatsoever.
Now that we moved the cache store to mem_cache_store, if we run Rails.cache.clear we clear the cache but also sign out every user, destroying all sessions.
Is this the intended behavior?
#phoet was right on. In my initializers/session_store, config.session_store was set to CacheStore. That's not the default in Rails 4, which is :cookie_store.
What is confusing (and now I see the light) is this: no matter what cache store mecanism you choose, there will always be a cookie stored in the browser (with the name you set in that same file, right after the store mecanism, in the key: 'xxx' option - this key is actually the cookie name and has nothing to do with the key you set in secrets.yml to encrypt it).
If you use the default store mecanism (:cookie_store), the entire "session hash" will be stored in the cookie, and nothing on the server (database/memcached). Everything will be read and written directly in that cookie (which starting in Rails 4 is always encrypted if you set secret_key_base).
If you use any other storage (like CacheStore or ActiveRecordStore), the cookie will still be there, with the same name you set in the 'key' option, BUT it if you decoded it (you need the secret_key_base for that, google for decoding rails 4 session) you'll see will only contain the session ID, and then Rails will look for the data corresponding to that session either in the database (ActiveRecord) or memcached (CacheStore, considering you are using memcached and not FileStore for storing cache, but that's another config).
So, since my session store was set to CacheStore, when I did Rails.cache.clear the cookie wasn't being deleted (that's on the client side of course), but when Rails got the session ID inside that cookie it couldn't find anything in memcached to match it with.
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.
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"] %>
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.