Skip to content
This repository has been archived by the owner on Jan 11, 2023. It is now read-only.

Security Nonce for sapper.scripts #343

Open
AlexRiedler opened this issue Aug 6, 2018 · 14 comments
Open

Security Nonce for sapper.scripts #343

AlexRiedler opened this issue Aug 6, 2018 · 14 comments

Comments

@AlexRiedler
Copy link

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 :)

@Rich-Harris
Copy link
Member

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!

@AlexRiedler
Copy link
Author

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

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?

@Seb35
Copy link
Contributor

Seb35 commented Mar 25, 2019

In the meantime this was implemented by @nolanlawson on 7 September 2018 (e377515) and documented (sveltejs/sapper-legacy.svelte.dev@6cde0fa).

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.

@ShimShamSam
Copy link

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

@evanleck
Copy link

evanleck commented May 7, 2019

@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...

@Conduitry
Copy link
Member

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.

@evanleck
Copy link

evanleck commented May 8, 2019

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.

@evdama
Copy link

evdama commented Jul 9, 2019

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

shimport@1.0.1.js: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

@lmaccherone
Copy link

+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?

@antony
Copy link
Member

antony commented Aug 21, 2019

@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.

@Conduitry
Copy link
Member

Conduitry commented Aug 21, 2019

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'.

@martinburger
Copy link

@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.

@bryantbiggs
Copy link

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

@benmccann
Copy link
Member

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

script += `var s=document.createElement("script");try{new Function("if(0)import('')")();s.src="${main}";s.type="module";s.crossOrigin="use-credentials";}catch(e){s.src="${req.baseUrl}/client/shimport@${build_info.shimport}.js";s.setAttribute("data-main","${main}")}document.head.appendChild(s)`;

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

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests