HTML5 cache and authorization issues - ruby-on-rails

I've got a problem after adding HTML5 caching to a singlepage app written in backbone on rails. Browser (chrome) isn't reloading the html and this causes problems in 2 ways:
1) The skeleton html for backbone sometimes changes - at very least to let backbone know that user is signed in. However with html not being loaded, the app doesn't know that (after refresh for example). I could query the server on page load, but that's another request which I hopped to avoid. Also this would force moving all the permisions logic to the client - so either duplicate cancan setting from the server OR embed it in html - and we run into above issue.
2) Rails' csrf tokens are in the html, and they too don't change - causing any ajax post to not work. For this one I'm not sure what to do. From what I read csrf token is generated for session so maybe on login/logout I could update it with js. However where to get it, would it work ?

i know this question is old but i just ran into the CSRF issue.
Try including the CSRF token as a comment in the manifest file. So whenever it changes it will change the manifest and force a reload.
CACHE MANIFEST
# include CSRF token in manifest to force reload when it changes
# <%= form_authenticity_token %>
to be safe you could run it through a hashing algorithm a few times

Related

Is it Secure to Use Token Authentication and Let Users Execute Custom Javascript Code on Subdomains

I am helping to create a Rails app that uses Ember for a front end MVC. For the app, it is hosting user content accessed via subdomains. On the subdomains, the user can upload custom JS and CSS. What I'm wondering about is if token authentication on the root domain will be safe if stored in Ember from the custom JS people could upload and run on their subdomains?
Provided the following:
Don't use cookies on *.domain.com or use cookies at all.
They can't run (or really display it unescaped in any way) the JS/CSS on your main site.
The ember app with your token doesn't run on their sub-domain (obviously).
They can't put HTML in a file with a different extension or even Content-Type on your subdomain (or you aren't using cookies). They could direct a user's web browser there and it'd display the HTML. Be wary of phishing though (looks like it's your secure content). I can't imagine you could prevent this easily other than not using cookies -- without 100% ensuring properly formatted JS/CSS which would present all kinds of problems.
You can limit cookies to domain.com and www.domain.com, but I don't recommend it (prone to mistakes). If you don't somebody can make a GET request through CSS or ie. an image tag (not to mention JavaScript) and it'll send the authenticated cookies to your server. Remember unescaped input in their app can leave holes too.
If your token is stored in ember, and they have access to custom JS where the app is running of course it'll leave your token vulnerable. If you run your ember app only on the www.domain.com, avoid cookies, storing the token only locally/in JS, you might be okay.
If they just put HTML code in a file with another extension and direct people there it'll be interpreted as HTML.

Where does Rails 4 store the authentication token for CSRF protection?

Inside one of my controllers, I write the following to protect certain pages from CSRF.
protect_from_forgery :only => [:foo, :bar]
When I load the URL's which correspond to foo and bar, and I view the HTML, I do not see any hidden input fields or meta tags which contain any security tokens, as described here.
However, during testing, I did observe that CSRF is not effective against these pages, although it is effective against other pages in the same application which are not protected.
So where does Rails 4 store the security token which is used for verifying that the request came from the original page?
Note that I have already read through the Ruby On Rails Security Guide, and from the section on protect_from_forgery, it says
This will automatically include a security token in all forms and Ajax
requests generated by Rails. If the security token doesn't match what
was expected, the session will be reset.
The problem is that this security token appears to be missing from the forms on the pages with CSRF protection enabled, even though CSRF is indeed not effective against them.
Note, this code is from a class project, in which one of the objectives is to perform a clickjacking attack to bypass the CSRF project. The question I am asking here is orthogonal to the purpose of the assignment.
I am simply curious about exactly how Rails does CSRF.
After doing rails server in the directly, the relevant URL which I cannot find the security token for is http://localhost:3000/protected_transfer.
The CSRF token is stored in the user's session (which is in a cookie by default, in Rails; encrypted cookie in Rails 4). It is additionally written into the page as both a <meta> tag (for use by Javascript libraries) via the csrf_meta_tags helper method, and in a hidden field in any forms generated by form_tag or form_for in the page.
Looking at this project, the reason the CSRF token doesn't appear is that the HTML is written with a literal <form> tag, rather than the form_for helper, which would include the CSRF token. Additionally, the csrf_meta_tags helper is not present in the layout, which is why the meta tag doesn't get written.
The form is hardcoded to post to <form action="post_transfer" method="post"> which should not be protected by CSRF protections, so this form should be CSRF-able, even though the view is marked as protect_from_forgery. The protected_post_transfer method isn't likely to accept even legitimate requests, since the authenticity token is never sent.
I suspect the instructors missed this, since the test would be to use the form legitimately (hitting the unverified endpoint, and letting it succeed), and then the student is instructed to attempt to CSRF against the protected endpoint (which will never pass muster anyway), so you end up testing two different things that produce the right results for the wrong reasons.

Ajax requests stop working after many successful requests

In my Rails + Devise app I have a table of links to multiple "contacts", each being a simple jquery $.get AJAX request which calls Contact#show.
Inevitably after clicking anywhere from 3-25 of the links (successfully!), a request will fail (response status 0 or failed to load resource depending on browser), after which it will never work again until the browser tab is closed or cache is cleared.
Here's the javascript for the request
$.get('/contacts/1312')
Details...
I do have csrf_meta_tags at the top of my layout
The request heads do include a "X-CSRF-Token" with the correct CSRF token from the meta tag
On chrome, the failed requests do not show up in the server logs
as a request. its as if they never made it. The only error reported
is in the chrome console which reports a failure. This leads me to believe it is browser related.
On Safari, upon first failure, it seems to destroy the session any subsequent requests result in a request for the sign_in page, which leads me to believe it may have something to do with devise
Update 3/30/13: After looking at many of the related question on SO (this one: Rails not reloading session on ajax post), which have to do with CSRF not being set correctly, I dont believe this issue is related to CSRF because it works properly several times before it fails.
i eventually did figure it out. I was using a feature datatables.js (a table library) that saved its state in the cookie. However, the data it was trying to save in the cookie exceeded the 4kb max, so my cookie was getting messed up , resulting in different behaviours across different browsers.

How to handle pages with stale CSRF authenticity tokens in Rails

In our Rails application, it is common for users to keep multiple browser tabs open for hours or days at a time. The problem occurs when in one of these tabs, the user logs out then logs back in (or the session expires and a new session is created).
This causes the CSRF authenticity tokens on all the other tabs to become invalid. If they try to submit any form or make any ajax request on those tabs without refreshing, they will get an error (and in fact get logged out because that is the default Rails behavior when a bad authenticity token is passed).
This behavior is clearly undesirable. I was wondering what people do to gracefully handle situations where a user has a window open to your site but the authenticity token is out of date.
What I don't want to do is just redirect them to the login page, because then they might lose their work, if for example they have been writng a long blog post or something.
The solution that comes to mind is to have some javascript that either polls the server to check whether the authenticity token has changed, or polls the user's cookies to check whether the session has changed. I have never heard of anyone doing either of these, so I wanted to see what the community thought.
First of: logging in/out/in won't lead to appearing a new csrf-token. It still will be saved in the user's cookie. Next time it logs in via the same browser it'll get the same token.
In latest versions of Rails no errors will be thrown in the case of incorrect token: all the Rails does -- just resets the session before passing it to a controller.
So, update your Rails and you'll get one pain less.
Are you sure you are talking about CSRF token and not session token? It does not make any sense at all to redirect to login on a CSRF token mismatch. You just tell the user to repeat whatever he tried to do. (In a traditional web application this typically comes up when a form is submitted; you can treat the CSRF mismatch as a validation error, and show the form again, keeping all the field values, and ask the user to resubmit. In a more AJAX-heavy application you can use some sort of generic CSRF flag in the response, and if it is set, ask the user to do whatever he did (press the button etc) once more, or even automate the whole thing without bothering the user.

Rails - Session not saving

I have a session that is set but it does not appear to carry over to other pages. I'm on Rails 2.3.5 and Ruby 1.8.7. Has anyone else experienced this issue?
I've had this issue in Rails 3.1 when CSRF verification fails. This can happen if you use a tag manually rather than generate it via one of the built-in methods provided by Rails.
Search your log file for "csrf" (case insensitive search). If you see a log entry showing a csrf failure, it's likely Rails is resetting your session.
You may be losing your session between requests which can happen if it's not established properly in the first place. If you examine your cookies you may see the session identifier changing, being re-assigned, because of a validation failure.
It's also possible that it's being assigned to a domain that the browser subsequently rejects. This happens if an application is configured to use a specific domain, and is then re-hosted under a different one, even localhost.
You might have not used csrf meta tag in your layout. Try removing ' protect from forgery ' in application_controller.rb in controllers folder. Then try running the app again, if it works then you didn't add tags to your layout.

Resources