Repository navigation
getScript requires 'unsafe-inline' CSP rule #3969
Description
jQuery should be able to load scripts via $.getScript without causing unsafe-inline CSP violations.
Look at the following test case:
index.html
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://code.jquery.com 'sha256-DOU0/sVUxitk2MNb5zXL6o3XIe+ZQ5oKG5jmGDO9PmQ='">
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<input id="btnJQuery" type="button" value="Load script via jQuery" />
<input id="btnScriptTag" type="button" value="Load script via script tag" />
<script>
console.log("start");
$("#btnJQuery").on("click", function() {
$.getScript("payload.js");
});
$("#btnScriptTag").on("click", function() {
let scriptEl = document.createElement("script");
scriptEl.onload = function() { console.log('onload', arguments); };
scriptEl.onerror = function() { console.log('onerror', arguments); };
scriptEl.src = "payload.js";
document.head.appendChild(scriptEl);
});
</script>payload.js
console.log("OK");
If you click on the Load script via jQuery button the following error is shown in the browser's console (Chrome in this case):
jquery-3.3.1.js:111 Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' https://code.jquery.com 'sha256-DOU0/sVUxitk2MNb5zXL6o3XIe+ZQ5oKG5jmGDO9PmQ='". Either the 'unsafe-inline' keyword, a hash ('sha256-oKrRnv4NSECe1z+2Q8HSC47J9uP6ALT0+UguOrbK7UU='), or a nonce ('nonce-...') is required to enable inline execution.
On the other hand if you click on the Load script via script tag button then the script is loaded without issues and the text OK is shown in the console.
Note: I am reporting this issue, because third-party libraries use $.getScript() and they consider this a jQuery issue (rightly) and won't fix this by their own because they expect the fix from jQuery.
For example see this issue: jackocnr/intl-tel-input#541
Security considerations
Using constructs which require unsafe-inline or unsafe-eval are generally not recommended and the security community considers them as bad practice.
Mozilla MDN states the following about unsafe-inline:
Disallowing inline styles and inline scripts is one of the biggest security wins CSP provides.
Google recommends the same in their Web Fundamentals guide
If you must have inline script and style, you can enable it by adding 'unsafe-inline' as an allowed source in a script-src or style-src directive. You can also use a nonce or a hash (see below), but you really shouldn't. Banning inline script is the biggest security win CSP provides, and banning inline style likewise hardens your application.
you can enable them by adding 'unsafe-eval' as an allowed source in a script-src directive, but we strongly discourage this.
So I hope you will consider changing the current behavior for the sake of a safer web (taking into account how widespread your library is).
Activity
mgol commentedon Feb 7, 2018
Thanks for the report. This looks like a duplicate of #3541 so I'm closing it.
koczkatamas commentedon Feb 7, 2018
I am not sure that the linked PR in #3541 resolves this problem. It is similar problem, but I am not sure it's the same that's why I opened this issue.
dmethvin commentedon Feb 7, 2018
Yeah i don't think it's the same. You can avoid the problem by adding a nonce or hash but we should discuss whether to always inject a script tag for external files.
koczkatamas commentedon Feb 7, 2018
It would be great workaround for me if you could add a global flag for jQuery or an
ajaxSetupsetting that if enabled, then jQuery would use thescript tag + srcmethod for every request. It could be disabled by default of course.AFAIS this could be a workaround for those who disabled the
unsafe-inlineusage in their CSP.mgol commentedon Feb 7, 2018
Ideally, as I suggested in #3541 (comment), we'd feature detect
script.onerrorsupport and use thescript tag + srcapproach if it's supported. If it's not possible to feature detect that, though, then maybe we should introduce a flag that enables CSP support and avoid stuff that violates it even if it makes some very old browsers unusable.Feature detection ideas welcome!
mgol commentedon Feb 7, 2018
I'll add this to the
3.4.0milestone, this sounds like something we should resolve.mgol commentedon Feb 7, 2018
Hmm, instead of detecting
script.onerrorsupport we could detect if CSP is enabled by:This is similar to what e.g. AngularJS does. What do you think?
dmethvin commentedon Feb 7, 2018
Agreed on 3.4.0 and landing this with gh-3782 would be nice in order to deal with all CSP issues in one release. I think it would be better and more consistent to always use a script tag regardless of CSP, if we have to make an exception for Android 4.0 to work then we'd only get/eval there.
@koczkatamas In general we've sworn off global flags because they make it very difficult for a large page full of plugins written at different times by different people to depend on consistent behavior. The
jQuery.ajaxdocumentation is already pretty difficult to understand because of all the options and the way they interact. Changing the rules retroactively makes it worse. Subtle behavior changes like this are also difficult for jQuery Migrate to detect and warn about.Keep in mind that this won't help the original case you linked to since they were using jQuery 1.12 which has not been maintained for a while. They would need to update to 3.4.0 to get this fix.
koczkatamas commentedon Feb 7, 2018
@dmethvin If you can auto-detect
onerrorsupport then I consider that a superior solution, so feel free to forget my 'global flag' idea. :)The issue I linked was opened by somebody else, we are using jQuery 3 and we are prepared to switch to latest jQuery at any time. (Especially if the CSP fix lands.)
@mgol please note that
new Function( "" );technically tests forunsafe-evaland notunsafe-inlineand AFAIK it will send a warning to thereport-uriendpoint configured in the CSP which can cause unnecessary traffic.I am not sure how, but I think Angular (at least the latest versions) solves this otherwise. We use Angular and we don't get any
unsafe-*errors from it.mgol commentedon Feb 7, 2018
@dmethvin It's not just Android 4.0 but all <=4.3. How would you make an exception for those Android Browsers without UA-sniffing?
dmethvin commentedon Feb 8, 2018
@mgol yeah it looks like although Android sets the property to a function if you create an attribute, it doesn't run the function on a 404. Maybe it does on a script error but I didn't try.
https://jsfiddle.net/dmethvin/cxby538z/
19 remaining items
dmethvin commentedon Feb 9, 2019
mgol commentedon Jul 23, 2020
I've just looked at this issue and I'm a bit puzzled by @gibson042's comment:
Maybe I'm missing something but this seems to concern synchronous script execution that we do during DOM manipulation but this issue is about
$.getScriptwhich is already asynchronous. As far as I understand, the only blocker is that some legacy browsers like Android Browser can't do error handling for non-inline scripts as they lack theonerrorattribute support. Does that mean we can just flip the behavior of$.getScriptfor 4.0 without all that complexity? The issue about synchronous script execution in DOM manip is already tracked in #1895.Ajax: Avoid CSP errors in the script transport for async requests
mgol commentedon Jul 29, 2020
PR: #4763.
mgol commentedon Aug 24, 2020
Adding the
Behavior Changelabel per @dmethvin's comment: #4763 (review)Ajax: Avoid CSP errors in the script transport for async requests
Ajax: Avoid CSP errors in the script transport for async requests