JQuery 3.1.1 violation of the CSP directive

I am using jQuery version 3.1.1 and I am trying to implement content security policy directives on my web page.

I get the following error:

The inline script has been refused because it violates the following Content Security Policy: "script -src" self "'nonce-c20t41c7-73c6-4bf9-fde8-24a7b35t5f71'". Either the unsafe-built-in keyword, a hash ('sha256-KAcpKskREkEQf5B3mhDTonpPg34XnzaUC5IoBrOUrwY ='), or nonce ('nonce -...') is required to enable inline execution.

The error occurs on line 82 of the main jquery.js script file. The contents of this line are:

doc.head.appendChild( script ).parentNode.removeChild( script ); 

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

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

As you can see when CSP is violated, I use CSP level 2 (nonce), but it is ignored. Would it be possible (somehow) to tell jQuery about using this nonce when adding a script tag?

Thank you very much.

Regards, V.


UPDATE: This is what HTML looks like (using Express template for nonce)

 <script nonce="<%=nonce%>" type="text/javascript" src="jquery.js"></script> 

After rendering the HTML, the nonce attribute in the script tag matches the CSP nonce directive sent by the server.


UPDATE: It works with simple javascript

 <script nonce="<%=nonce%>" type="text/javascript"> var userEmail = "<%=user.user.email%>"; </script> 

Without the nonce attribute, this script tag violates the CSP directive.

+5
source share
2 answers

It seems that the jQuery bug or quirk, as it adds inline scripts, ends up discarding all their attributes, and I don’t see an obvious way to fix it to check it, I used the following HTML:

 <!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.textContent = '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.textContent = '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> 

When using jQuery to add, it goes through the following process (slightly reduced):

  • Creates a document fragment and adds a script tag to it
  • Applies type="false/" attribute to script tag
  • Removes the type attribute
  • If the src attribute is present, it retrieves the script via AJAX (not exploring this further)
  • If it does not work DOMEval( node.textContent.replace( rcleanScript, "" ), doc )

DomEval looks like this (with added comments):

 doc = doc || document; var script = doc.createElement( "script" ); script.textContent = code; doc.head.appendChild( script ).parentNode.removeChild( script ); 

As you can see, no attributes are transferred to the new element before it is added, and since such a CSP will fail.

The solution would be to simply use native JS to add the element, unlike jQuery, or perhaps wait for a bug fix / response in your report. I'm not sure their argument would be to exclude attributes so that inline script tags could be a security feature?

The following should achieve what you want without jQuery - just set the textContent attribute to the JS source code.

 var script = document.createElement('script'); script.setAttribute('nonce', '<%=nonce%>'); script.textContent = '// Code here'; document.head.appendChild(script); 

Therefore, in fact, this particular line causes an error: the added tag is actually a new tag with the same code and attributes that are not used for it, and since it does not have nonce , it rejected the CSP.

Update: I fixed jQuery to fix this problem (3.1.2-pre patch, but all tests), if you used my latest fix, I recommend updating this version!

Minified: http://pastebin.com/gcLexN7z

Unlimited: http://pastebin.com/AEvzir4H

The branch is available here: https://github.com/Brian-Aykut/jquery/tree/3541-csp

Link to the problem: https://github.com/jquery/jquery/issues/3541

Code Changes:

Line ~ 76 replace the DomEval function with:

 function DOMEval( code, doc, attr ) { doc = doc || document; attr = attr || {}; var script = doc.createElement( "script" ); for ( var key in attr ) { if ( attr.hasOwnProperty( key ) ) { script.setAttribute( key, attr[ key ] ); } } script.text = code; doc.head.appendChild( script ).parentNode.removeChild( script ); } 

Add attr to the var statement on line 5717 on

 var fragment, first, scripts, hasScripts, node, doc, attr, 

Change the else body next to line 5790 to:

 attr = {}; if ( node.hasAttribute && node.hasAttribute( "nonce" ) ) { attr.nonce = node.getAttribute( "nonce" ); } DOMEval( node.textContent.replace( rcleanScript, "" ), doc, attr ); 
+2
source

Ha, you just want to enable jquery, so you need to redefine the appendChild function (to disable it) before the jquery script and after deleting your custom function.

 <script> var oldAppend = document.head.appendChild document.head.appendChild = function(script){ if(script && script.tagName=='SCRIPT'){ document.createElement('fakeHead').appendChild(script)//because script need a parent in the line that create the error return script } return oldAppend.apply(this,arguments) } </script> <script nonce="<%=nonce%>" type="text/javascript" src="jquery.js"></script> <script> document.head.appendChild = oldAppend </script> 

EDIT: try this, it will override jQuery add function

 var oldAppend = $.fn.append $.fn.append = function($el){ var dom = ($el instanceOf $) ? $el[0] : $el if(dom && dom.tagName=='SCRIPT'){ this[0].appendChild(dom) return this } return oldAppend.apply(this,arguments) } 
+1
source

Source: https://habr.com/ru/post/1264706/


All Articles