It didn't help. Now I want people to take the issue seriously. This is a huge unsolved problem.
Developers have a tool which they don't know how to properly use. So they use it how they feel convenient. It leads to security breach. Reminds mass-assignment bug (sorry, i have to mention it every day to feel important)
How it works?
Attacker redefines RJS function(s), asks authorized user to visit specially crafted page and leaks data (which the user has access to) and his authenticity_token. Very similar to how JSONP works.
<script>
var bcx = {progress: {}};
var $ = function() {
return {prepend: function(data) {
window.data = data
}}
};
</script>
<script src="https://basecamp.com/2474985/progress.js"></script>
If it has any HTML form in it (especially when people use render_to_string), it also has user's authenticity_token automatically.
So RJS leaks 1) authenticity_token 2) a lot of private data. Thus the bug is as serious as XSS (can read responses + can craft proper requests). = must be fixed?
Some people are +1, some found it "useful in our projects" (=vulnerable), also DHH is against my proposal:
Not only are js.erb templates not deprecated, they are a great way to develop an application with Ajax responses where you can reuse your server-side templates. It's fine to explore ways to make this more secure by default, but the fundamental development style of returning JS as a response is both architecturally sound and an integral part of Rails. So that's not going anywhere.
What's left to do? Demonstrate with full disclosure: Gitlab, Redmine, Diaspora, Spree, Basecamp etc.
Gitlab: GITLABAPP/gitlab/gitlab-recipes/issues.js leaks authenticity_token, issues etc. Time to update.
— Egor Homakov (@homakov) November 30, 2013
Diaspora. Leaks CSRF token and private converstaions DIASPORA/conversations/CONV_ID.js Come on, you can't all be vulnerable?!
— Egor Homakov (@homakov) November 29, 2013
Redmine! We can leak REDMINE/boards/1/topics/quote/1.js iterate id to leak all comments. Sensible again, I guess? And token too, dig sources
— Egor Homakov (@homakov) November 29, 2013
Neeext, Spree! e.g. SPREEAPP/admin/products/new.js leaks admin's CSRF token and bunch of private info too. I'm necessary evil.
— Egor Homakov (@homakov) November 29, 2013
Even Rails creators get RJS wrong. https://t.co/8o2IUCyyFM leaks a lot of private data from your project. That's *sensible* huh?
— Egor Homakov (@homakov) November 29, 2013
And this is only a tiny part of vulnerable apps we have out there. Let's choose our next actions wisely:
- find a way to deny cross-site inclusion of JS templates, not breaking whole technique
- remove whole :js responder as an insecure technique
- don't not do anything about it
Is my app vulnerable?
If there are any .js.erb file under /app/views, most likely it is. Author of this article can perform a security audit for you, to make sure.
DHH's comment was really unfortunate. While I've never used RJS myself, I do use some of the applications that are affected by this security exploit and I'd certainly love if Rails removed this hack (RJS) as soon as possible.
ReplyDeleteRight now I guess I should be considering using an anonymous session for general navigation to avoid having my private data in affected sites stolen by some evil site... :( Pretty sad David's position :(
If you told me that I should stop doing something in my app I'd be just thankful and would stop doing it even before I really knew why it was dangerous...
Great Finding!
ReplyDeleteA fix for gitlab ?
ReplyDeletehttps://github.com/gitlabhq/gitlabhq/commit/da10cad1da7039a346f1f0d32325d8be4c3a1c56#diff-76918abb7bd6880e0d522635de6413fb
yes
DeleteCouldn't you just require authenticity_token on all JS requests?
ReplyDeleteyes but .xhr? is better. Script tag request can't add new headers, but theoretically can add token
DeleteFWIW, according to CVE-2011-0447, there are ways for attackers to forge headers on requests; that's when Rails started doing CSRF checks on AJAX POSTs, which it hadn't been doing previously. (CVE-2011-0696 is the same thing for Django.)
DeleteOn the flip side, the mitigation for that CVE included having Rails apps send the CSRF token with *all* AJAX requests, including GETs, so no changes client-side should be needed in most apps to send the CSRF token. You just have to check it.
Rails writeup on the earlier problem: http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails/
come on, of course i know about that. ajax GET doesnt need it.
Delete