Sapper: Security Nonce for sapper.scripts

Created on 6 Aug 2018  Ā·  14Comments  Ā·  Source: sveltejs/sapper

Issue: when we use sapper.scripts for injection (changed from sapper.main) we now no longer have access to inject nonce for scripts; maybe there is a better way to do this? (CSP policy)

Any ideas would be greatly appreciated :)

enhancement pending clarification

Most helpful comment

I'm surprised that shimport is used in the non-legacy build. I would expect it could probably be removed.

https://github.com/sveltejs/sapper/blob/67cb6be0befd087bafb4491772d21aad6ea4e75f/runtime/src/server/middleware/get_page_handler.ts#L348

It looks like SvelteKit doesn't contain Shimport at all - though it doesn't have legacy asset support yet. Perhaps we should keep an eye out when we add legacy support to SvelteKit and see if we can add Shimport only in the legacy case there

All 14 comments

This sounds like a good and sensible idea, though I have to confess I've never used nonce before 😬 Could you walk me through the process of generating/applying it? Thanks!

Basically on the request, a UUIDv4 is normally generated and put into the CSP header like so:

HTTP Header:
Content-Security-Policy: default-src 'self'; script-src 'nonce-4AEemGb0xJptoIGFP3Nd'

and then when the script tag is generated it uses the nonce:

<script type="text/javascript" nonce="4AEemGb0xJptoIGFP3Nd"> ... </script>
````

In javascript I have seen people use helmetjs/csp library, and do something like:

For generating UUID for nonce
```js
var uuidv4 = require('uuid/v4')

app.use(function (req, res, next) {
  res.locals.nonce = uuidv4()
  next()
})

and then upstream when generating the actual payload:

return '<script nonce="' + res.locals.nonce + '">alert('hello world');</script>'

for the lengthy read troy hunt gives a good read for it: https://www.troyhunt.com/locking-down-your-website-scripts-with-csp-hashes-nonces-and-report-uri/

It basically blocks scripts from running on the page that do not have the nonce that matches the one the the HTTP Header.

I probably have time to investigate on how to implement this; would it make more sense to somehow add parameters to %sapper.scripts% ; or would it make more sense to support this feature by configuration?

In the meantime this was implemented by @nolanlawson on 7 September 2018 (e3775158) and documented (sveltejs/sapper.svelte.technology@6cde0fae822affbb058697e54fb43ec68b40ad13).

I’ve just tested with Helmet and Polka on my app (here) and it works: a nonce is added in the CSP by Helmet and the nonce is used in %sapper.scripts%.

Is there anything else to do in this issue? -- btw thanks for this issue and the implementation, that’s an interesting feature.

@Seb35 I'm having an issue with Rollup's use of Shimport. It's using eval() which fails the nonce check.

@Seb35 @ShimShamSam @nolanlawson I'm getting errors using the recommended setup for CSP in Firefox:

Content Security Policy: The page’s settings blocked the loading of a resource at eval (ā€œscript-srcā€).
Loading failed for the <script> with source ā€œblob:http://localhost:3000/de7746fc-d74d-4648-8c1c-2084c3af7b23ā€.
Content Security Policy: The page’s settings blocked the loading of a resource at blob:http://localhost:3000/de7746fc-d74d-4648-8c1c-2084c3af7b23 (ā€œscript-srcā€).

It looks like something's trying to eval or load a script from the blob protocol, right? I wonder if that's Shimport...

That's almost certainly Shimport, yes. The good news is that caniuse is telling me that Firefox 67 is going to natively support dynamic imports, So whenever that comes out, Firefox shouldn't even need to use Shimport.

It sounds like CSP needs to include 'unsafe-eval' to work in browsers that don't support dynamic imports natively, right? Shimport appears to use eval and source from the blob: protocol, which would mean our script-src would be 'self' 'unsafe-eval' blob:. I tested that out locally and it works, though Sapper appears to try and connect to localhost:10000 as well.

According to caniuse, that's for current and previous versions of Firefox and Edge.

having implemented CSP just yesterday using this code in server.js

app.use( ( request, response, next ) => {
    response.locals.nonce = uuidv4();
    next();
} );

app.use(
    helmet(
        {
            contentSecurityPolicy: {
                directives: {
                    scriptSrc: [
                        "'self'",
                        ( request, response ) => `'nonce-${response.locals.nonce}'`
                    ]
                },
                browserSniff: false
            }
        }
    ),
    sapper.middleware(),
    compression({ threshold: 0 })
);

I also see

[email protected]:1 Refused to load the script 'blob:http://localhost:3000/c4f0757d-0cb2-4663-b33a-7d8495546172' because it violates the following Content Security Policy directive: "script-src 'self' 'nonce-12c733c1-28d6-44d8-8c91-b71af9f59e3b'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.

Can we get rid of shimport now that it seems both Firefox and Edge already have dynamic import support?
https://caniuse.com/#feat=es6-module-dynamic-import

+1 on getting rid of shimport. I'm being told that I won't be allowed to go into production with a new product that has unsafe-eval in my CSP.

Until that happens, is there a way to turn it off today?

@evdama is there a reliable way to polyfill for es6 dynamic module import? It is important we maintain support for Edge < 76 and sadly IE11.

You should be able to disable it by forking Sapper and editing the code that loads it in get_page_handler.ts. I think using the webpack logic even when using Rollup would work.

edit: You'll also need to change the script tag to type='module'.

@Seb35 @ShimShamSam @nolanlawson I'm getting errors using the recommended setup for CSP in Firefox:

Content Security Policy: The page’s settings blocked the loading of a resource at eval (ā€œscript-srcā€).
Loading failed for the <script> with source ā€œblob:http://localhost:3000/de7746fc-d74d-4648-8c1c-2084c3af7b23ā€.
Content Security Policy: The page’s settings blocked the loading of a resource at blob:http://localhost:3000/de7746fc-d74d-4648-8c1c-2084c3af7b23 (ā€œscript-srcā€).

It looks like something's trying to eval or load a script from the blob protocol, right? I wonder if that's Shimport...

For me, switching from rollup to webpack solved above CSP violation.

any update on the removal of shimport or is this a rollup issue?

I'm surprised that shimport is used in the non-legacy build. I would expect it could probably be removed.

https://github.com/sveltejs/sapper/blob/67cb6be0befd087bafb4491772d21aad6ea4e75f/runtime/src/server/middleware/get_page_handler.ts#L348

It looks like SvelteKit doesn't contain Shimport at all - though it doesn't have legacy asset support yet. Perhaps we should keep an eye out when we add legacy support to SvelteKit and see if we can add Shimport only in the legacy case there

Was this page helpful?
0 / 5 - 0 ratings

Related issues

keyvan-m-sadeghi picture keyvan-m-sadeghi  Ā·  4Comments

Rich-Harris picture Rich-Harris  Ā·  3Comments

BMorearty picture BMorearty  Ā·  3Comments

antony picture antony  Ā·  3Comments

milosdjakovic picture milosdjakovic  Ā·  3Comments