Content Security Policy — Make Secure Applications

Sahil Aggarwal
5 min readMar 5, 2022

The new Content-Security-Policy HTTP response header helps you reduce XSS risks on modern browsers by declaring, which dynamic resources are allowed to load.

The core functionality of CSP can be divided into three areas:

  • Requiring that all scripts are safe and trusted by the application owner (ideally by making sure they match an unpredictable identifier specified in the policy called the CSP nonce),
  • Ensuring that page resources, such as images, stylesheets, or frames, are loaded from trusted sources,
  • Miscellaneous other security features: preventing the application from being framed by untrusted domains(frame-ancestors), transparently upgrading all resource requests to HTTPS, and others.

Now the major concerns here are as follows :

  • What should be the value of csp header to provide utmost security
  • What should be the value of csp header so that it will be applicable by all vapt vendors and also no major change required if my application is old .
  • What all things need to take care while deciding the header value , How Strict the header value should be .
  • How to write code (if someone is making a new application) so that it remains CSP Standards compatible .

In this Blog all the above doubts will be cleared .

Below is sample Header Value of CSP which can be applied at Production Environments

Content-Security-Policy: 
object-src 'none';
script-src 'nonce-{random}' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https: http:;
base-uri 'none';
frame-ancestors https://example.com

Let’s look at the properties of this policy as interpreted by a modern browser:

  • object-src ‘none’ Prevents fetching and executing plugin resources embedded using <object>, <embed> or <applet> tags. The most common example is Flash.
  • script-src nonce-{random} ‘unsafe-inline’ The nonce directive means that <script> elements will be allowed to execute only if they contain a nonce attribute matching the randomly-generated value which appears in the policy.
    Note: In the presence of a CSP nonce the unsafe-inline directive will be ignored by modern browsers. Older browsers, which don’t support nonces, will see unsafe-inline and allow inline scripts to execute.
  • script-src ‘strict-dynamic’ https: http: ‘strict-dynamic’ allows the execution of scripts dynamically added to the page, as long as they were loaded by a safe, already-trusted script (see the specification).
    Note: In the presence of ‘strict-dynamic’ the https: and http: whitelist entries will be ignored by modern browsers. Older browsers will allow the loading of scripts from any URL.
  • ‘unsafe-eval’ allows the application to use the eval() JavaScript function. This reduces the protection against certain types of DOM-based XSS bugs, but makes it easier to adopt CSP. If your application doesn’t use eval(), you can remove this keyword and have a safer policy.
  • base-uri ‘none’ Disables <base> URIs, preventing attackers from changing the locations of scripts loaded from relative URLs. If your application uses <base> tags, base-uri ‘self’ is usually also safe.
  • frame-ancestors https://example.com — This means that your application page can be opened in iframe of application page served by example.com only .

Now , if you have decided some CSP header value and want to check if it is ok to use or not ,

You can check at the following link : CSP Evaluator

I hope First two concerns listed above are cleared and now moving to next one

Not only setting the correct value makes your application safe , we need to make some changes to client side code also to make the application CSP compatible .

Code Changes

Random Nonce in Code

Above we talk about the random nonce which needs to be set on CSP header , but the question how security can be achieved by setting the random nonce in the header . the answer of this question is as follows :

  • We also need to set this same nonce in the parent script tag also and when the browser is requesting a page it checks nonce value from script tag and header and matches it and if it does not match then mark script as unsafe .
  • With ‘strict-dynamic’, dynamically generated scripts implicitly inherit the nonce from the trusted script that created them. This way, already- executing, legitimate scripts can easily add new scripts to the DOM without extensive application changes. However, an attacker who finds an XSS bug, not knowing the correct nonce, is not able to abuse this functionality because they are prevented from executing scripts in the first place.

Code Before CSP compatibility

<script src="/path/to/script.js"></script>
<script>foo()</script>

Code After CSP compatibility

<script nonce="${nonce}" src="/path/to/script.js"></script>
<script nonce="${nonce}">foo()</script>

Refactor inline event handlers and javascript: URIs

Inline event handlers (onclick=”…”, onerror=”…”) and <a href=”javascript:…”> links can be used to run scripts, so an attacker who finds an XSS bug could inject such HTML and execute malicious JavaScript. CSP requires refactoring those patterns into safer alternatives.

In most cases the changes will be straightforward. To refactor event handlers, rewrite them to be added from a JavaScript block:

Code before CSP compatability

<script> function doThings() { ... } </script> <span onclick="doThings();">A thing.</span>

Code after CSP compatability

<span id="things">A thing.</span> <script nonce="${nonce}"> document.addEventListener('DOMContentLoaded', function () { document.getElementById('things') .addEventListener('click', function doThings() { ... }); }); </script>

For javascript: URIs, you can use a similar pattern:

Code before CSP compatability

<a href="javascript:linkClicked()">foo</a>

Code after CSP compatability

<a id="foo">foo</a> <script nonce="${nonce}"> document.addEventListener('DOMContentLoaded', function () { document.getElementById('foo') .addEventListener('click', linkClicked); }); </script>

Uses of eval().

If your application uses eval() to convert JSON string serializations into JS objects, you should refactor such instances to JSON.parse().

If you cannot remove all uses of eval() you can still set a CSP policy, but you will have to use the ‘unsafe-eval’ CSP keyword which will make your policy slightly less secure.

There are many frameworks in this time , where we do not write the html and js instead we write coe in java and framework convert it into js for example GWT . Now in these case the code generated should be CSP compatible is the responsibility of frameworks .

For more knowledge on CSP you can read the following research paper and for knowing what all other options can be added to csp header and browser support visit content-security-policy.com

So, Let’s make your application more safe by including CSP header in your application .

Please comment more suggestions if any related to CSP .

Explanation of this blog can be found at :

Originally published at http://hello-worlds.in on March 5, 2022.

--

--