3

I have to add CSP header to a site. Issue is that this is a legacy code and there are lots of inline scripts and styles in the HTML. I cannot use 'unsafe-inline' as the aim is to actually make the site secure and this directive gives red flag in OWASP ZAP tool scan. I can refactor the HTML and JS code to some extent but I have few questions:

  1. I have tried a fixed nonce (just for POC) and hash way of whitelisting the inline scripts. But since all the HTML is static how can I add a new nonce to the script tags for every request (as is the actual case for nonce)?

  2. Is providing hash of all the required scripts and styles better than nonce for such case?

  3. If I refactor the code for all HTML to remove all the inline scripts from the body tag and add the code in a single script tag in head, does that mean that the inline scripts are eliminated? In short, does in count as inline script?

1 Answers1

3
  1. But since all the HTML is static how can I add a new nonce to the script tags for every request (as is the actual case for nonce)?

A 'hash value' is commonly used, since it is difficult to dynamically insert the nonce="value" attribute into script and style tags every time the page is reloaded.
However for the Nginx web server there is a solution using a server filter (ngx_http_sub_module or ngx_http_substitutions_filter_module).
In the static HTML you use some "unique string":

<script nonce="@@=AAABBBCCCZZZ=@@"></script>

which is replaced by the server's filter to a server generated value ($request_id):

location / {
    subs_filter @@=AAABBBCCCZZZ=@@ $request_id;
    }

But these modules may be not built into Nginx server by default and you have to rebuild server.

  1. Is providing hash of all the required scripts and styles better than nonce for such case?

The 'hashe-value' uses mostly in SPA (Single Page Apps) where you have no possibility to refresh nonce value. But it's hard to manage CSP with a lot of hashes when you change code and need to replace some hashes by a new ones.

Therefore, in the case of server-side rendering, the 'nonce value' is more often used. Moreover 'nonce value' can be used not only for inline scripts, but for external ones too.

Also see the comment about JS frameworks below - these can be incompatible with 'nonce-value' or 'hash-value'.

  1. If I refactor the code for all HTML to remove all the inline scripts from the body tag and add the code in a single script tag in head, does that mean that the inline scripts are eliminated?

Negative. CSP counts as inline scripts not only the <script> tags but also built-in tags event handlers like <button onClick='...'> and javascript-navigation kind of <a href='void(0)'>.

Also some JS frameworks like jQuery require mandatory 'unsafe-inline' or 'unsafe-eval' and can be incompatible with 'nonce-value' or 'hash-value'.
jQuery is compatible with 'nonce-value' since v3.5.0. But jQuery hardly compatible with a 'hash-value' because of dynamically generates main script and inserting it into <head> section.

granty
  • 7,234
  • 1
  • 14
  • 21
  • Thanks for the detailed answer. Also do style attributes like height="100%" count as inline style? For eg.:
    – Hrishikesh Bawane Nov 02 '21 at 06:51
  • 1
    Tag attributes like `height="100%"`, `bgcolor="#eee"` are [not considered as inline styles](http://csplite.com/csp/test64/#test). Inline styles are: (1) Blocks of ``, (2) `style='...'` attribute in tags, and (3) `Element.setAttribute('style', ...)` javascript function. But setting props by JS like `Element.style.color = 'red';` are not inine styles. – granty Nov 02 '21 at 13:10
  • jQuery is compatible with 'nonce-value' since v3.5.0. => I am facing an issue using nonce. I have posted a [question](https://stackoverflow.com/questions/69933555/jquery-min-js-violates-csp-for-inline-style). Can you please check? – Hrishikesh Bawane Nov 12 '21 at 09:15
  • Hey @granty, I see that default-src 'self' is enough for external javascript files served from my server. Is that correct? – Hrishikesh Bawane Nov 17 '21 at 12:52
  • 1
    In general, yes, but there are exceptions. If you serving jQuery/AngilarJS/VueJS frameworks from your server, you have to allow either `'unsafe-inline'` or `'insafe-eval'` (or `'nonce'` for jQuery > 3.4). And do not use `default-src` directive to allow scripts, always use `script-src` one. Firefox has some security bugs when `script-src` fallbacks to the `default-src`. So `default-src 'self'; script-src 'self' 'nonce-abD34g==';` is preferable then `default-src 'self' 'nonce-abD34g==';` – granty Nov 17 '21 at 14:48
  • Understood thanks! Just a doubt, if 'self' works for external scripts why doesn't it work for inline scripts as they are being served from same origin? If inline-scripts are susceptible to XSS attacks why aren't external scripts susceptible? – Hrishikesh Bawane Nov 17 '21 at 18:08
  • inline scripts do not have origin, browser do not have ability to separate legitimate inline scripts from XSS-injected ones. The HTML page is susceptible to XSS attacks, but not the scripts. As a result of XSS, any third-party scripts, both inline and external, can be injected. – granty Nov 18 '21 at 04:46