Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue using JQuery 3.1.1 and CSP #3541

Closed
victorgaspar opened this issue Feb 14, 2017 · 51 comments
Closed

Issue using JQuery 3.1.1 and CSP #3541

victorgaspar opened this issue Feb 14, 2017 · 51 comments

Comments

@victorgaspar
Copy link

@victorgaspar victorgaspar commented Feb 14, 2017

Description

Hi,

I'm using JQuery version 3.1.1 and I'm trying to implement Content Security Policy directives on my webpage.

I'm getting the following error:
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' 'nonce-c20t41c7-73c6-4bf9-fde8-24a7b35t5f71'". Either the 'unsafe-inline' keyword, a hash ('sha256-KAcpKskREkEQf5B3mhDTonpPg34XnzaUC5IoBrOUrwY='), or a nonce ('nonce-...') is required to enable inline execution.

The error is produced on line 82 of the main jquery.js script file. The content of this line is:
doc.head.appendChild( script ).parentNode.removeChild( script );

Basically, it adds an inline script tag to the DOM, and violates the CSP.

I do not want to use 'unsafe-inline'. Is there any other way to circumvent this error?

As you can see on the CSP violation, I'm using CSP level 2 (nonce). Would it be possible (some how) to inform JQuery to use this nonce when appending the script tag?

Thank you very much.

Kind regards,
V.

@Brian-A
Copy link

@Brian-A Brian-A commented Feb 26, 2017

Looks like all attributes get stripped by this call on line 5782
DOMEval( node.textContent.replace( rcleanScript, "" ), doc );
A new script tag gets created without any attributes and as a result the nonce is no longer present which causes the CSP violation.

The following can be used to demonstrate/replicate the issue:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Security-Policy" content="default-src http://localhost 'nonce-123456' ; child-src 'none'; object-src 'none'; script-src 'nonce-123456';">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.js" nonce="123456"></script> <!-- HTML nonce works -->
    <script nonce="123456">
        //This works
        console.log('Inline nonce works');

        //This will also work
        var s = document.createElement('script');
        s.setAttribute('nonce', '123456');
        s.innerHTML = 'console.log("Dynamically generated inline tag works")';
        document.head.appendChild(s);

        // This won't work
        var s2 = document.createElement('script');
        s2.setAttribute('nonce', '123456');
        s2.innerHTML = 'console.log("Dynamically generated inline tag appended via jQuery doesn\'t work")';
        $(document.head).append( s2 ); // This will throw a CSP error    
    </script>    
</head>
<body>

</body>
</html>

@timmywil
Copy link
Member

@timmywil timmywil commented Feb 27, 2017

Seems like this would be easy to fix. We can probably add the nonce attribute to our script tag if it exists.

@timmywil timmywil added this to the Future milestone Feb 27, 2017
Brian-A pushed a commit to Brian-A/jquery that referenced this issue Feb 28, 2017
Fixed CSP tags being stripped

Fixes: jquery#3541
@Brian-A
Copy link

@Brian-A Brian-A commented Feb 28, 2017

I've implemented a fix by adding an optional argument to DOMEval which takes an object of attributes and passing the nonce through to it if one is present on a script tag. It currently passes all tests and I've added a relevant test to test that the nonce attribute does remain.

https://github.com/Brian-A/jquery/tree/3541-csp

Let me know if you'd like me to submit a PR or make any changes :)

@victorgaspar
Copy link
Author

@victorgaspar victorgaspar commented Feb 28, 2017

Hi Brian, your solution works flawlessly! Hopefully it is promoted to main branch soon enough. In the meantime, I'm going to remove JQuery completly and use plain javascript to enable CSP. I'm quite surprise that such a powerful and widely use library as JQuery is not 'CSP friendly'. It took me two days until I finally decided to post the question.

Thanks for the help!

@koczkatamas
Copy link

@koczkatamas koczkatamas commented Aug 23, 2017

Maybe I posting to the wrong issue (fix me pls!), but jQuery fails to handle the most common CSP-related case correctly.

In my case replaceWith is called with a HTML including this snippet

<script src="/docs/assets/js/page_helper.js"></script>

And jQuery takes this script tag, downloads the JS file with Ajax (evalUrl) and tries to put the JS code inline into a new script tag via which triggers CSP (unsafe-inline is disabled in CSP which is basically a must-have configuration).

var n = t.createElement("script");
n.text = e,
t.head.appendChild(n).parentNode.removeChild(n)

Repro case: jquery_csp_bug.zip (should be running on a HTTP server hosted on a http(s):// endpoint)
Expected behavior: console shows test.js running
Actual behavior: console shows the following error:

Refused to execute inline script because it violates the following Content Security Policy directive: "default-src http: https:". Either the 'unsafe-inline' keyword, a hash ('sha256-VcShpWhuVGQiiDKCgS044k0QHqA0fnQ2a3xoroT4FaE='), or a nonce ('nonce-...') is required to enable inline execution.

Is there any workaround for this? Should I open a new issue or will this be handled as part of this issue?

@dmethvin
Copy link
Member

@dmethvin dmethvin commented Aug 23, 2017

The changes that @Brian-A wrote here look good, we just need a PR with that and some unit tests to ensure they work and aren't broken by subsequent changes.

@Brian-A
Copy link

@Brian-A Brian-A commented Aug 28, 2017

@dmethvin I've submitted a PR here.

@koczkatamas if you can include a nonce in your policy & snippet my patch should do the trick (See above for example), alternatively if you're able to (which I'm guessing is unlikely or difficult given the details you've provided) the following will work without violating CSP:

var s = $("<script></script>");
$('body').append(s);
s.attr('src', 'test.js');

Hopefully this is helpful :)

Brian-A added a commit to Brian-A/jquery that referenced this issue Sep 14, 2017
Fixed CSP tags being stripped

Fixes: jquery#3541
Brian-A added a commit to Brian-A/jquery that referenced this issue Sep 14, 2017
Fixed CSP tags being stripped

Fixes: jquery#3541
@subversivo58
Copy link

@subversivo58 subversivo58 commented Nov 8, 2017

Accompanying the PR... was there any definition about the change request?

The good application of CSP is important for the application, is there any forecast of when this can be added to the core?

@Brian-A
Copy link

@Brian-A Brian-A commented Nov 9, 2017

I updated the PR with the requested changes although I see now it may have gotten missed/lost due to the thread being marked as outdated? #3766 (comment)

@cnizzardini
Copy link

@cnizzardini cnizzardini commented Jan 23, 2018

Has this issue been resolved in any versions of jQuery?

@timmywil
Copy link
Member

@timmywil timmywil commented Jan 24, 2018

Not yet, but this should make it into the next release.

@mgol
Copy link
Member

@mgol mgol commented Jan 24, 2018

@timmywil If that's the case, the Milestone should get updated. Now it just points to Future.

@timmywil timmywil removed this from the Future milestone Jan 24, 2018
@timmywil timmywil added this to the 3.4.0 milestone Jan 24, 2018
@mgol
Copy link
Member

@mgol mgol commented Feb 7, 2018

I've been wondering - the error is caused by us manually evaling the downloaded script. Now, when cross domain we already do it differently, via a script tag with the src attribute set, see:
https://github.com/jquery/jquery/blob/3.3.1/src/ajax/script.js#L47-L74

Is there any reason why this has to be restricted to cross-domain?

@dmethvin
Copy link
Member

@dmethvin dmethvin commented Feb 7, 2018

It's been a LOOOONG time but I think this was because the onerror event for scripts is relatively recent--is it now supported everywhere? To avoid silent failures for 404s and script errors we grabbed the source and evaled it.

@mgol
Copy link
Member

@mgol mgol commented Feb 7, 2018

@dmethvin I've just tested (test case: http://output.jsbin.com/kosexoy) and it doesn't work in IE 8 but works in IE 9+; it also works in iOS 7+ which is what we support.

Unfortunately, it also doesn't work in Android Browser (all 4.0-4.3). Fortunately, Android Browser doesn't seem to support CSP so perhaps it'd work to extend the cross-domain way of loading scripts to modern browsers? Not sure how to check it, though. Android Browser satisfies document.createElement('script').onerror === null even though unknown attributes should have a value of undefined.

@aimee-katherine
Copy link

@aimee-katherine aimee-katherine commented Feb 10, 2018

Hi, I'm using JQuery version 3.3.1 and I'm trying to implement Content Security Policy on my webpage.

I'm getting the following error:

Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' 'nonce-8WJnAqGXkJewcnh5byFtLu1IRq9Zu0Adv31B0k18DLaNBD1xHb19y8ppRMlY'
The error is produced on line 2 of jquery.min.js script file. The content of this line is:

function m(e,t,n){var i,o=(t=t||r).createElement("script");
Is there a way around this problem without having to use "unsafe-inline"? I've been looking all over the internet, desperate for a solution. =( I tried what Brian suggested to no avail...

@Brian-A
Copy link

@Brian-A Brian-A commented Feb 10, 2018

Hi @aimee-katherine the following comments assume you're dynamically generating the script tags as that's what this issue is related to. you could try adding a hash ( sha256-yourhash; )of the script to your CSP although this isn't something I've tested with dynamically generated script tags I only tested if the attributes on the tag were stripped. Alternatively I've patched 3.1.1 to work with some dynamically generated tags and should work fine if the tag is generated using jQuery and a nonce (or possibly hash) is applied https://github.com/Brian-A/jquery/tree/3541-csp

If my comments don't help an example of how you're creating the script tags or a test case would help immensely :)

@Pomax

This comment was marked as off-topic.

@mgol

This comment was marked as off-topic.

@Pomax

This comment was marked as off-topic.

cnsgithub added a commit to cnsgithub/primefaces that referenced this issue Jul 25, 2018
…xpected since outerHTML does not execute contained scripts (patched jquery as suggested in jquery/jquery#3541 by preserving the nonce attribute in jquery's DOMEval function)
@jlherren
Copy link

@jlherren jlherren commented Sep 13, 2018

I implemented @timmywil's solution by adding 'nonce' to preservedScriptAttributes which works great in Chrome, but still failed on Edge/Firefox. The problem is these browsers seem to be picky about how you read/write the nonce attribute of the script element. So in addition to that I had to modify the code as follows:

for ( i in preservedScriptAttributes ) {
	// "node.getAttribute(i)" works in Edge/FF but not in chrome and "node[i]" works in chrome but not in Edge/FF
	// so just try both
	var val = node[i] || node.getAttribute(i);
	if ( val ) {
		// "script[i] = val" doesn't work in Edge/FF, setAttribute() works everywhere
		script.setAttribute(i, val);
	}
}

@boompig

This comment was marked as off-topic.

@timmywil

This comment was marked as off-topic.

cnsgithub added a commit to cnsgithub/primefaces that referenced this issue Nov 19, 2018
…xpected since outerHTML does not execute contained scripts (patched jquery as suggested in jquery/jquery#3541 by preserving the nonce attribute in jquery's DOMEval function)
mgol added a commit to mgol/jquery that referenced this issue Jan 9, 2019
@mgol mgol self-assigned this Jan 9, 2019
@mgol
Copy link
Member

@mgol mgol commented Jan 9, 2019

A new PR: #4269.

mgol added a commit to mgol/jquery that referenced this issue Jan 9, 2019
@tandraschko
Copy link

@tandraschko tandraschko commented Jan 14, 2019

@mgol do you have a compiled jquery.js of your branch? So i could just test it.

@mgol mgol closed this in #4269 Jan 14, 2019
mgol added a commit that referenced this issue Jan 14, 2019
Fixes gh-3541
Closes gh-4269
mgol added a commit that referenced this issue Jan 14, 2019
Old iOS & Android Browser versions support script-src but not nonce, making the
nonce test impossible to run. Browsers not supporting CSP at all are not
a problem as they'll skip script-src restrictions completely.

Ref gh-3541
Ref gh-4269
Ref c7c2855
@mgol
Copy link
Member

@mgol mgol commented Jan 14, 2019

@tandraschko The PR has landed so you can try https://code.jquery.com/jquery-git.js. Just please don't load this file in production. :)

@tandraschko
Copy link

@tandraschko tandraschko commented Jan 15, 2019

@mgol all right, thanks :)
What about $.globalEval? Should we provide a way to pass the nonce?
How can i use DOMEval from my scripts until we we introduce something for $.globalEval?
XXX(?).DOMEval(myScript, document, { nonce: 'mynonce') }?

@mgol
Copy link
Member

@mgol mgol commented Jan 15, 2019

@tandraschko It's not possible to pass nonce through $.globalEval at the moment. The merged PR just makes nonce preserved during DOM manipulation. If you'd like to see support for nonce in $.globalEval, please submit a separate issue. Thanks!

@tandraschko
Copy link

@tandraschko tandraschko commented Jan 15, 2019

@mgol Done: #4278 - Thanks :)

mgol added a commit that referenced this issue Jan 21, 2019
Fixes gh-4278
Closes gh-4280
Ref gh-3541
Ref gh-4269
@jfoclpf
Copy link

@jfoclpf jfoclpf commented Feb 9, 2019

Good day
Considering that the error still persists, why the milestone 18 for v.3.4.0 and attached to this issue, doesn't mention this issue?
Thanks in advance

PS: Now I see is set to v4.0.0 through #3969. Thanks

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.