6 ms·
Here's a quick summary: There's a Rails design pattern where you send an AJAX request to your controller, and it returns a bunch of Javascript that gets eval'd
by 5vforest 13y ago
Here's a quick summary:
There's a Rails design pattern where you send an AJAX request to your controller, and it returns a bunch of Javascript that gets eval'd by the page you're on. This is used for say, infinite scroll. You'll click the 'load more' button, the server will render a partial containing your new records, and return something like:
$('#itemsList').append('<li>My new item</li><li>another new item</li>')
So guess what? This is susceptible to XSS-ish attacks.
Let's imagine that instead of a simple list item, this request was returning some sensitive information or a CSRF token. (Egor points to various examples of this.) Normally, executing a GET request from an unauthorized domain will not be allowed because of CORS. This is what prevents me from instructing the users of my website to make an AJAX request to gmail.com, allowing me to see all of their emails.
But "wait", you say, "the content type of this request is application/javascript."
So open developer tools and type this: (using jQuery for conciseness)
$.ajax({
url: 'https://basecamp.com/[BASECAMP_PROJECT_ID]/progress.js',
dataType: 'jsonp'
})
And boom, you have a bunch of sensitive information about your Basecamp project, accessible via JSONP request from any domain.
- ghiculescu 13y agoEgor talked about it more in his original post, http://homakov.blogspot.com.au/2013/05/do-not-use-rjs-like-techniques.html http://homakov.blogspot.com.au/2013/05/do-not-use-rjs-like-t... He also linked to a post from six years ago[0] which had a good solution the problem at the time: pass data, not code (and process this data on the client side). [0]: http://yehudakatz.com/2007/05/18/railsconf-talk-recap/ http://yehudakatz.com/2007/05/18/railsconf-talk-recap/
- KayEss 13y agoYour example makes it look like this is doable to any site that allows JSONP responses that contain sensitive data. Is this RoR specific because RoR will always allow JSON responses to be turned into JSONP, or is there something else at work? I'm suddenly pleased I've been holding off on doing JSONP as part of Django Slumber.
- KayEss 13y agoI just managed to confirm that a similar attack is possible against sites using DjangoRestFramework. I won't publish it as the site I used to test against is currently working on patching the vulnerability out.
- tomchristie 13y agoIf you believe you've found a security issue in Django REST framework I suggest raising emailing the security contact as listed here: http://django-rest-framework.org/#security http://django-rest-framework.org/#security Having said that, it's worth pointing out that Django REST framework does not return JSONP by default, and although it does for historical reasons include a JSONP renderer, the documentation recommends the use of CORS instead.
- KayEss 13y agoI did email it pretty much straight away, but I guess it didn't get through.
- homakov 13y ago>Is this RoR specific because RoR will always allow JSON responses to be turned into JSONP, or is there something else at work? you can't turn any JSON into JSONP. No, JSONP here is result of using RJS templates. It has nothing to do with original JSONP
- KayEss 13y agoExcept inasmuch as you're using a framework that allows any JSON data to also be requested as JSONP. The very first site I checked on this (which uses DjangoRestFramework) I was able to access email addresses from an attack page. This is purely due to DRF handling the JSONP for you without the devs really being aware of what was going on.
- homakov 13y agothis is slightly different vulnerability (JSON->JSONP upgrade) but it's really severe. Good find!
- philfreo 13y agoYou mentioned "creating a new record", which indicates a POST request. I believe this only a vulnerability if the server responds to jsonp requests in GET requests.
- 5vforest 13y agoYou're right, will update now.
- yeukhon 13y agoShould people still use eval()? Am I missing something about the eval call in JS? if so, isn't that the first vulnerability anyway?
- why-el 13y agoI think eval has some great use cases (maybe on a node.js server), just not what you are shipping off to the client.
- homakov 13y agosecond part of your post looks vague. I'd say any GET-accessible .js template is leaking all data it has inside. It's not precisely JSONP. It turns out to be JSONP, unintendedly. This is where it becomes vulnerable
- cykod 13y agoIsn't this solved by just requiring the CSRF token on any JS get requests? (In fact, isn't this just a cross-site request forgery with a different verb than we're used to?) I know it's only generally checked on posts, but turning it on for any xhr calls seems like it would solve any potential data leakage.
- 5vforest 13y agoSeems to me like this solution, or checking for `request.xhr?` are the best suggestions so far.
- why-el 13y agoThis one was mentioned by Homakov on Twitter I think. Though I would love to have it wrap the responder instead.
- homakov 13y agoit can be a solution, not ideal: proper non-xhr insertions on site.com will stop working. but for first step it's good enough.
- 1qaz2wsx3edc 13y agoMore importantly isn't this solved via authentication (basic auth).
- ketralnis 13y agobasic/digest auth doesn't solve this if you've recently used the target site any more than cookies do, because your browser caches the authentication for some time and won't ask you again. Also, very few web applications use basic auth, most use cookies.
- riffraff 13y agowhat I don't understand is: isn't the same information (say, a CSRF token) returned if the response is html (the AHAH pattern)? What makes rjs different? EDIT: ah, got it, invokation via GET
- why-el 13y agoQuick question, how are these files bypassing the authentication before_filter? I mean, a progress.js (Dont know what that is) probably belongs to a project, and therefore will hit that controller first, and the controller should make sure the file is not shipped to anyone but the authorized user. Am I missing something here?
- rst 13y agoThe attack scenario here is a request from an authorized browser which is run by a hostile page on a different website (e.g., due to phishing attack). And since the request comes from an authorized browser, the cookies typically checked by an authentication before_filter will be present. In detail: 1) the attacker knows of an authorized user, already logged in (most likely). So, any request sent by that browser to the target site will pass authentication checks. 2) they trick that user into loading a web page under their control by some means (e.g., phishing attack). 3) that web page, under their control, includes a <script> tag with a src attribute referencing target .rjs. It loads the target .rjs Javascript into a gimmicked environment in which the private data is captured. Since the web page is under the attacker's control, same-origin rules allow that captured private data to be sent back to the attacker directly. To counter this, the target site needs some way to verify that its own Javascript is making the request, not some hostile web site. Thus the talk of CSRF tokens and checking .xhr?. (The latter counts on the browser's same-origin rules to prevent an AJAX request from the hostile web site --- the same-origin rule blocks that, but in most current browsers, there's no way to prevent the attacker from tossing in a <script> tag.)