Vaadin Flow & Content-Security-Policy (CSP)

Hi there,

i am trying to understand CSP Content Security Policy | Advanced Security Topics | Security | Flow | Vaadin Docs

I dont use any manually added JS Code in my App. Is this Link still up to date or does it supports this out of the box now?

Is it enough to add a header “Content-Security-Policy”?

Yes, the docs page is up-to-date, and it is not enough to only add the header, you need the other parts as well. This way of nonce-based CSP works on 24.5 and newer. For an example application, please check out the repository at GitHub - vaadin/flow-crm-tutorial at 24.5-strict-csp

Ok thank you and the csp.js must be also added -do i need to modify it or is it static?

Once it works i should see a green check for it on securityheaders.com or is there also a way to check it locally? (I dont see the header in network tab of developer console)

Edit: vaadin.productionMode=true in application.properties and run from IntelliJ with vm option -Dspring.profiles.active=prod works.

now i see the Header in devtools from the browser. But the app loads infinit :thinking:

I get the following issue in the browser console:

Refused to execute inline script because it violates the following Content Security Policy directive: “script-src ‘nonce-xxxxx’”. Either the ‘unsafe-inline’ keyword, a hash (‘sha256-4xxxxx’), or a nonce (‘nonce-…’) is required to enable inline execution.

Refused to create a worker from ‘http://localhost:8080/sw.js’ because it violates the following Content Security Policy directive: “script-src ‘nonce-xxx-3exxx7’”. Note that ‘worker-src’ was not explicitly set, so ‘script-src’ is used as a fallback.

Looks like it doesnt work without adding something

Strange! I get diffrent nonce values:

from browser source code i see

 <script type="module" crossorigin src="./VAADIN/build/indexhtml-BjXpE5na.js" nonce="b8417896-xxxxxx6aae94e3"></script>
        <style>

And the error contains another one, is that correct?

Refused to execute inline script because it violates the following Content Security Policy directive: “script-src ‘self’ ‘nonce-d9cc58xxxxxx-e5d4defab4ff’”. Either the ‘unsafe-inline’ keyword, a hash (‘sha256-42l3QX/grwVfMPqfeV2KpGFj3WKVY5nMfWpTY5CMQmE=’), or a nonce (‘nonce-…’) is required to enable inline execution.

Is there a hyphen which is missing after nonce?

.v-reconnect-dialog,.v-system-error {position: absolute;color: black;background: white;top: 1em;right: 1em;border: 1px solid black;padding: 1em;z-index: 10000;max-width: calc(100vw - 4em);max-height: calc(100vh - 4em);overflow: auto;} .v-system-error {color: indianred;pointer-events: auto;} .v-system-error h3, .v-system-error b {color: red;}[hidden] { display: none !important; }

The issue looks like the script “window.Vaadin = window.Vaadin ??” has no nonce. Every other script is fine. Some one has an idea?

I use following bean in my Application

  @Bean
    public VaadinServiceInitListener cspNonceInjector() {
        return serviceInitEvent -> serviceInitEvent.addIndexHtmlRequestListener(response -> {
            String nonce = UUID.randomUUID().toString();
            response.getVaadinResponse().setHeader("Content-Security-Policy",
                    "script-src 'self' 'nonce-" + nonce + "';");

            response.getDocument().getElementsByTag("script").forEach(script -> {
                if (!script.hasAttr("nonce")) {
                    script.attr("nonce", nonce);
                }
            });
        });
    }

Are you using any Hilla features? The CSP only works for Flow, not Hilla.

Also, please clone the GitHub - vaadin/flow-crm-tutorial at 24.5-strict-csp repository and check if you are able to run the app from that branch (24.5-strict-csp). mvn spring-boot:run -Pproduction from command line should do it.

Also PWA is not supported with CSP, so make sure you do not have a @PWA annotation present.

Hilla i dont use, at least not that I know of. How could I check that?

I will try now on another application.

PWA is disabled. Push should work, right?

In my other app it’s the same script which has no nonce attribute and prevent the app from loading. No PWA, no Push. Using Vaadin 24.5.0 on it and on the other app its 24.5.5


<script>window.Vaadin = window.Vaadin ?? {};
window.Vaadin.views = {};</script>

Shouldnt be the demo also be with nonce in the scripts? Fusion CRM Tutorial Dont see them, also there is no header present

In my own app (which is not loading because of the script error) the header is set and securityheaders.com doesn’t complaint about its missing. So generally it works, but the script prevent the app from working :confused:

Okay one step further.

The push issue is gone after I set "script-src 'self' 'nonce-" + nonce + "'" (self is important)

No I still struggle with the first issue, which I think is a bug in the/a framework

<style>.v-reconnect-dialog,.v-system-error {position: absolute;color: black;background: white;top: 1em;right: 1em;border: 1px solid black;padding: 1em;z-index: 10000;max-width: calc(100vw - 4em);max-height: calc(100vh - 4em);overflow: auto;} .v-system-error {color: indianred;pointer-events: auto;} .v-system-error h3, .v-system-error b {color: red;}</style><style>[hidden] { display: none !important; }</style><!--CSSImport end--><!--Stylesheet end--><meta name="robots" content="noindex"><link href="icons/favicon.png" rel="icon" sizes="192x192"><link href="icons/favicon.png" rel="shortcut icon"><script>window.Vaadin = window.Vaadin ?? {};
window.Vaadin.views = {};</script> ``` 

where the last script has no nonce and prevent vom loading

An another step forward with a new issue :smiley:

Vaadin uses hilla inside. Excluding hills removed the script which got no nonce.

 <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-spring-boot-starter</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.vaadin</groupId>
                    <artifactId>hilla</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

But now the last error:

FlowClient-CFpeFTrH.js:1. blocked

The marked function has been blocked its an eval function. Therefor I need help, can’t find it by myself. There Vaadin should have hands on or?

Does no body uses this CSP? Crazy that no one hat this issues

image

I have now added:

  response.getVaadinResponse().setHeader("Content-Security-Policy",
                    "script-src 'self' 'unsafe-eval' 'nonce-" + nonce + "';");

so the app starts and securityheaders.com shows a green tag for CSP. so far so good. But the val Method should be removed from FlowClient.js. Is that a bug or does any other add-on write into this file?

1 Like

Hi!

Great that you got forward. I updated the CRM tutorial 24.5-strict-csp branch to use latest stable Vaadin version, and added the Hilla exclusion as well. Will also add info about the exclusion to the docs page later on.

For some reason I’m not able to reproduce the issue you have with the FlowClient eval call. I am also not using the ‘self’ keyword in the header, just this what is in the github repo already:

response.getVaadinResponse().setHeader("Content-Security-Policy", "script-src 'nonce-" + nonce + "'");

Also, the deployed version of CRM demo is not built from the strict-csp branch so it does not use csp at all. I don’t think there are too many users of this CSP yet since it is such a new feature, I do know a couple though and so far the only reported issue was about push not working and that was fixed.

If it’s possible for you to provide a bare-bones example project that can be used to reproduce the FlowClient eval issue, it would be easier to troubleshoot. Maybe create an issue on Flow repo and attach project there?

Hi Teppo,

thanks for tanking the topic serious and thanks good it works with push ;D Otherwise it would be a showstopper. Unfortunately i can not publish the project yet. Can a addon be the evil which adds the eval method? How could i find out which addon could this be?

Hi,

yes, it can definitely be an add-on as well. If you’re using the csp.js file from crm-tutorial, it should log a warn-level message to browser console, showing what the offending call is. Logging is done here: flow-crm-tutorial/src/main/frontend/csp.js at 24.5-strict-csp · vaadin/flow-crm-tutorial · GitHub

If you have a limited set of add-ons you could potentially check the sources and search for offending calls. At least Page.executeJs and Page.addDynamicImport calls are potential offenders.

The only warnings i get are as follows

In my first project i could get CSP to work perfectly. Now i try to add it to antoher project but it want work, there i get the same issue with the flowclient.js

Hilla is excluded, nonce is set (except to <script>window.Vaadin = window.Vaadin ?? {}; window.Vaadin.views = {};</script>)

Something is wrong since that snippet comes from Hilla’s index html request listener: hilla/packages/java/endpoint/src/main/java/com/vaadin/hilla/route/RouteUnifyingIndexHtmlRequestListener.java at main · vaadin/hilla · GitHub

Ok but that should has nothing to do with the script which get no nonce attribute right?

Well if Hilla is excluded, the <script>window.Vaadin = window.Vaadin ?? {}; window.Vaadin.views = {};</script> part should not be there at all. Not that it really matters since skipping executing that snippet does not break anything if you don’t have any Hilla views.

As for why you don’t get a browser log output for the FlowClient issue, I have no idea. Just to confirm - does this issue break the application, or does it work anyway?

It beaks it since the app is loading infinite.

Have i forget something? I removed @PWA Annotation, i excluded Hilla, and build production but this window script still is in source without nonce

Vaadin dev is excluded from production so hilla should not be in it

Maybe add exclusion for com.vaadin.hilla-dev as well (under vaadin-core).