Reputation: 63
While hardening my CSP by removing all unsafe-inline scripts by giving them a nonce, I ran into a problem on a particular page of my website. I edited everything to make it more easily understood on a small scale scenario.
product.php loads the template for which the product will be displayed.
<div id="productDisplay"></div>
<script nonce="sampleCorrectNonce" type="text/javascript">
product();
</script>
product.php?id=123 loads the actual product data and needs to be refreshed with new information through different scenarios.
if ($_GET['action'] === 'displayProduct') {
echo '
samleData
<script nonce="sampleCorrectNonce" type="text/javascript">
productReady();
productOptions();
</script>
';
}
On product.php there is an initial javascript code that fires and loads product.php?id=123 into an DIV by ID.
product = function() {
$("#productDisplay").load("//"+ document.domain + "/shop/product.php?action=displayProduct&id=123");
}
A nonce has been created to allow CSP on inline scripts. Despite the fact that the nonce matches exactly and the < script > is presented inline on the same page, it still triggers an error.
<html>
<body>
<div id="productTemplateStuffa"></div>
<div id="productDisplay">
samleData
<script nonce="sampleCorrectNonce" type="text/javascript">
productReady();
productOptions();
</script>
</div>
<div id="productTemplateStuffb"></div>
<script nonce="sampleCorrectNonce" type="text/javascript">
product();
</script>
</body>
</html>
For some reason, I cannot figure out how to include PHP echoed content from jQuery's load into a DIV while keeping CSP happy.
Firefox's Console Error:
Content Security Policy: The page’s settings blocked the loading of a resource at self (“script-src https://example.loc/ 'nonce-sampleCorrectNonce' 'unsafe-inline' 'unsafe-eval'”). Source: productReady(); ....
This is essentially what the header is sending, I edited it down to keep it simple and hide all external content.
Content-Security-Policy: base-uri 'self'; default-src 'self'; connect-src 'self'; font-src 'self'; form-action 'self'; frame-ancestors 'none'; img-src 'self' data:; media-src 'none'; object-src 'none'; script-src 'self' https://example.loc/ 'nonce-sampleCorrectNonce' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; upgrade-insecure-requests
Removing this fixes the error...
<script nonce="sampleCorrectNonce" type="text/javascript">
productReady();
productOptions();
</script>
Doing this, does NOT fix the error...
<script nonce="sampleCorrectNonce" type="text/javascript">
</script>
This is how Chrome, above, and Firefox, below, shows the inline script content.
<script nonce="" type="text/javascript" src="https://example.loc/theme/assets/global.jquery.min.js?v=1540058004"></script>
<script nonce="sampleCorrectNonce" type="text/javascript" src="//example.loc/theme/assets/global.jquery.min.js?v=1540058004"></script>
Deleting everything inside the script tag, still triggers the error. OK, since it's triggering a GET method, it's setting new headers with a new nonce. If I didn't have the script tags on the GET page, it wouldn't be a problem. I have an unsolvable problem, since the content is dynamic, a hash won't even work.
Doing this on the GET page, allows the headers to match the nonce from the GET request but now viewing source shows mismatched nonces, expectedly. Which means the CSP will trigger still.
<script nonce="' . Headers::getInstance()->getScriptHash() . '" type="text/javascript">
I apologize for the length of this post. I solved the problem by simply rewriting the code so there is no inline script on the GET request. This is what you should be doing anyway and is probably why they designed CSP to work this way.
Upvotes: 0
Views: 2178
Reputation: 40695
If all the rendered markup contains the same nonce(s) as your CSP header, it will work. So there is a possibility that not all the rendered nonces are part of your header. Since you mentioned in a comment that you think that should not be the problem, it can be assumed that you have other inline scripts still present in your markup.
Here's what Chrome says:
Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list.
Firefox should say something like this:
Content Security Policy: Ignoring "'unsafe-inline'" within script-src: nonce-source or hash-source specified
Since you obviously have a nonce-x
in your source list, the unsafe-inline
directive will be ignored. Since you still have that directive in there I can only assume you still have other inline scripts that don't use the nonce which probably explains your error.
Upvotes: 0