In my Rails application I make set of AJAX calls at once and that causes sending the same session cookie for each request.
The problem is that rails sets new session cookie in every response and therefore it expects that cookie value in the request after.
I'm looking for server-side solution because I don't want to chain those requests (they are time consuming).
Is it possible to change this behavior? And what security risks would come with it?
(I'm using Rails 4.1.0)
Many thanks
If the user doesn't already have a session cookie then there is nothing you can do.
If you can guarantee that the user already has a session (for example, if you require users to be logged in) then you may be able to do this with a server side session store.
With a server side session store the session cookie just contains an identifier - even if your overlapping ajax requests change values in the session they will not change the session cookie. In general this is better security wise: for example, old sessions can't be replayed after the user has logged out. Rails switched to the cookie store by default for performance reasons: no external data store needs to be accessed (however it does slightly increase the amount of data sent on each request)
Switching to a serverside session store isn't enough though and still leaves you open to race conditions. It is very easy to end up with a sequence along the lines of
Request A loads session
Request B loads session
Request B completes, saves session
Request A saves session and overwrites the session changes made by B
You need a session store that will attempt to merge any changes it has made with any changes that may have occurred from other requests.
I wrote such a session store some time ago. I haven't updated it for rails 4, since it isn't something i need anymore but you may be able to (or at least find inspiration in it)
Related
Because of the awesome EU directive on allowing users opt out from having cookies stored I have the following problem.
I have a message that displays at the top of the screen that asks the user to opt in or opt out.
if the user opts in, cookies are turned on using rack.policy, and the message is hidden. A cookie variable is set to say that the message should not be shown again for future visits. Perfect
If the user opts out. Cookies are disabled, fine. the message is cleared.... and a session variable is set to say don't show the message for this session. This would be fine, but it seems the session variable is saved in the same way as a cookie and the rack policy does not allow it to be displayed. The message therefore flashes up on every single page.
So first, thank you EU. Second, how do I save a "session variable" without saving to a cookie?
Unless you try going for something more exotic like local storage offered by the browser, you can't. The rails guide explicitly states:
All session stores use a cookie to store a unique ID for each session (you must use a cookie, Rails will not allow you to pass the session ID in the URL as this is less secure).
I'm no lawyer, but for what it's worth I believe that law is intended to apply to cookies used for marketing/tracking purposes and does not apply to cookies needed for the site to function like cookies used for authentication or ephemeral storage. With this in mind, you could use the rails's session cookie for must-have data and use separate cookies for other purposes that your application can disable.
I wouldn't take it as gospel, but this Wired article seems to a good job of providing a simplified explanation.
I'm coming from PHP background and have a question regarding RoR user sessions. By default PHP uses file storage with write locks for user session data. So it prevents processing of multiple requests by the same client at the same time. How does RoR behaves with sessions?
The default session store in rails store the entirety of the session data in the session cookie itself (known as the cookiestore).
One side effect of this is that if 2 overlapping requests both try and update the session then the last one to send a response back to the client 'wins'.
I don't think any of the session stores commonly in use with Rails have the concurrency property you describe.
I am learning Rails by reading the online guide(for Rails v2.3). The guide is great, however, there is a confusion for me, that's:
there is a chapter explains the Session of Rails and another chapter explains Cookies of Rails. The explanation is easy to understand separately, but when compare the two, reader like me does not see the significant difference between Session and Cookies . Especially under which situation session should be used and under which situation Cookies should be used ?
Besides, in the session chapter, there is a concept of CookieStore , what is the difference between the CookieStore and Cookies then?
Could someone explain to me these?
Sessions & Cookies both hold the ability to store some information (e.g : the current_user id) in between two or more requests which (in http) are otherwise stateless.
But Session is more of an abstract concept related to the notion of being in a certain state for a specific amount of time : the info it contains can be stored in the database, in a server side file, in a redis hash OR in a cookie.
Cookies are always the little text file navigators have to store some persistent data in between requests... But having some data on the client side can be insecure so that's why it is often encrypted. But it's true the notion can overlap with session.
TL;DR : session the abstract concept of holding temporary data. Cookies one (common) way of doing it.
A cookie is a small text file stored in the browser.
A session is the concept of a state of being "in-use", and that state can have data associated with it. Rails keeps track of sessions with cookies, and lets you choose different storage for associated data and access it with the same session interface.
CookieStore means all the session information is stored inside the cookie itself. You can choose to use various other stores where appropriate, and it'll still be available with your session accessor methods.
In addition to the session, you can set other cookies to store information on the user's browser. These are not tied to the session and can be set, accessed and deleted independently.
Example 1, storing a logged-in user's shopping cart in a session:
session[:embarassing_products] = ['ooh',
'naughty',
'lucky_im_using_activerecord_store',
'only_the_session_id_is_in_the_cookie',
'other_data_arent_in_the_browser']
The shopping cart is preserved for the user's session. You can set the session to end when the browser window is closed, when the user logs out, or when a certain amount of time passes.
Example 2, remembering a browser's last language preference for your domain in a cookie:
cookie[:lang] = 'en-US'
This information is stored inside the cookie itself. Unless the cookie expires or is deleted (by you or the user), it stays inside the browser.
As to me the main difference is that the session data stored on the server, whereas the cookies are stored on the client (browser).
So you can trust the data from the session. Information from the cookie can be manipulated, stolen, and thus should not be relied on for critical use (for right access for example).
Second point, is that cookies have a limited size, and are only text-based. You can store in session many complex objects (but beware of memory consumpation), and you don't have to transfer them to client then back at each request.
And typically the session only persists until the user shuts down their browser. That's useful for typical logins. Whereas if you needed information to persist between sessions you could use a cookie with a longer duration, for example a 'remember me' flag that persists even after the browser is restarted.
If I receive a request to the url host.com/site-directory/page-slug.html?session={someValidNonExpiredSessionGuid} and I detect a session cookie with the value: {someOtherValidNonExpiredSessionGuid}, then
Which session is the correct session to associate with the request?
Here's some background:
The pattern I am using for maintaining state across HTTP requests is to store a unique ID in the querystring, form collection and/or cookie. Then, on each request, I locate the unique Id and pull date from a database table. If the id is not valid, or the session is expired, a new session will be created (with a new id, a new cookie, etc).
The default behavior is that all forms will have a field:
<input type="hidden" name="session" value="{someGuid}" />
All links to other pages on the site will have an appended querystring parameter
a sample link
And, if the user's browsing device supports cookies, a cookie will be set having the session's value.
If I have validated that the user's browsing device supports cookies, then my form and querystring will no longer require the the session id field/parameter.
However, I am having a conceptual issue in deciding whether the session parameter of the querystring should take precedence over the cookie value or vice-versa. It seems like I could potentially get bad data in either circumstance. I could get data with a bad querystring parameter if the user bookmarked a page with the session parameter included in the URL. I could also get bad data from the cookie, if a user closes the browser without terminating the session, and the session expire-window has not yet closed. It also seems like both options could be vulnerable to a malicious user intercepting the request and sending a request with the same session information.
So, once again, my question is
If I receive a request to the url host.com/site-directory/page-slug.html?session={someValidNonExpiredSessionGuid} and I detect a session cookie with the value: {someOtherValidNonExpiredSessionGuid}, then Which session is the correct session to associate with the request?
I am leaning towards the cookie session, because it seems like the most common scenario will be a bookmark with the session included. I've already decided that the form post data should take the greatest precedence, because a page will always render the form with the correct ID, and the only possible situation with a wrong, non-expired ID is a very quickly implemented XSS attack, which is circumvented by including a request-scoped anti-forgery token field.
In addition to the primary question I appreciate any insight to any security-related or logical oversights I have expressed in this description. I apologize for the long post, but felt it was necessary to explain the situation. Thank you very much for your input.
Also, it is not necessarily relevant to the question, but I am using ASP.NET MVC in most situations, and setting my cookies manually with Response.Cookies.
From a security standpoint sessions should not be stored in query strings.
For example:
If sessions are stored in queries and you link to a remote host on the same page, the users valid session could be sent to the remote host via the referer header.
Sessions should always be stored in cookies.
You should try to store it in the cookie (looking the the browser caps to see if the browser supports cookies) and then have a fall back for query string.
I too would lean towards using the cookie session ID in case of ambiguity. This primarily because I'd trust the cookie implementation to be more well baked, more well tested, and more idiot-proof than my own home brewed session tracking implementation. For e.g. there are cases where ASP.NET automatically knows to clear the session cookies, renew them etc.
Also, I would design it so the cookies aren't persistent to minimize the edge cases. If the user closes the browser, then the session is closed.
The other simplification I would consider is to have either cookies or URL based tracking and not both. If the browser supports cookies, there is really no reason to also track the session through a URL.
Thoughts?
Curious ... What were your reason to rule out using the stock ASP.NET cookieless session implementation? - http://msdn.microsoft.com/en-us/library/aa479314.aspx#cookieless_topic2
If I receive a request to the url
host.com/site-directory/page-slug.html?session={someValidNonExpiredSessionGuid}
and I detect a session cookie with the
value:
{someOtherValidNonExpiredSessionGuid},
then Which session is the correct
session to associate with the request?
To answer your specific question, I'd recommend putting session management in the cookies as opposed to the querystring. As has been mentioned, cookies can be set to expire whereas the querystring cannot. This allows your thin-clients to assist in their own session maintenance by removing their own expired cookies. Moreover, since cookies are dropped to specific browsers, you reduce the chances of another browser spoofing the original browser session.
The only way I would use the querystring to pass session information would be as a backup method to re-establish a browser session onto a new browser instance. Here's a scenario: you have an active session using browser A on machine A which suffers some catastrophic error. You want a way to re-establish that same session on another browser instance on either the same machine or on another machine. If your code-behind can recognize that the session cookie doesn't exist, but that a valid session id exists in the querystring, you could initiate a challenge-response to verify the integrity of that session id and then drop a new session cookie on the new machine. Kinda extreme in my humble opinion, but the functionality might be useful in certain situations.
ADDED: I understand that you may want to accommodate users who have turned cookies off on their browsers, and while you can use the querystring to hold the session id I'd recommend against it. But if you must, encrypt that sucker using browser-machine specific information.
I think I might be misunderstanding something about Rails sessions, so please bear with me, I might not be phrasing my question the best way.
I'm working on an iPhone app with a Ruby on Rails backend. I have a web view which by default goes to the index action of one controller (and uses sessions), and in the background a bunch of API calls going to a different controller (and which don't need to use sessions).
The problem is, the sessions set by my web view seem to be overwitten by the API calls. My staging server is pretty slow, so there's lots of time for the requests to overlap each other - what I see in the logs is basically this:
Request A (first controller) starts. Session is empty.
Request B (second controller) starts. Session is empty.
Request A finishes. Request A has done authentication, and stored the user ID in the session. Session contains user ID.
Request B finishes. Session is empty.
Request C starts. Session is empty - not what I want.
Now, the strange thing is that request B should NOT be writing anything to the session.
I do have before and after filters which READ from the session - things like:
user = User.find_by_id(session[:id])
or
logger.debug session.inspect
and if I remove all of those, then everything works as expected - session contents get set by request A, and they're still there when request C starts.
So. I think I'm missing something about how sessions work. Why would reading from the session overwrite it? Should I be accessing it some other way? Am I completely on the wrong track and the problem is elsewhere?
Thank you for any insights!
This is the result of a race condition caused by how rails handles session. See http://www.paulbutcher.com/2007/05/race-conditions-in-rails-sessions-and-how-to-fix-them/
It seems like you can't have concurrent requests modifying session reliable. The solution is to use a different method of storing session (e.g. active_record or redis) or you could eliminate the concurrent requests.
Your sessions are maybe cookie based. If that's the case then each of request is starting with the same cookie(session). The cookie holds the session content. Try switching the storage to be on the server. But I in your case with the authentication I think it would be much better to not do this async.
Request A (first controller) starts. Session is empty.
Request B (second controller) starts. Session is empty.
Request A finishes. Request A has done authentication, and stored the user ID in the session. Session contains user ID
.....AND returning the session content in a cookie.
Request B finishes. Session is empty.
THIS one is setting blank session.
Request C starts. Session is empty - not what I want.
Thats because B has set reset the session
It's possible this is because you are storing the user id as ":id" in the session object. :id may be a reserved key in the object. Try using a different name such as session[:user_id].
Good luck!