Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Content Security Policy (CSP) nonce available in template.html #1248

Closed
martinburger opened this issue Jun 2, 2020 · 4 comments
Closed

Make Content Security Policy (CSP) nonce available in template.html #1248

martinburger opened this issue Jun 2, 2020 · 4 comments

Comments

@martinburger
Copy link

@martinburger martinburger commented Jun 2, 2020

Is your feature request related to a problem? Please describe.

I would like to use Content Security Policy (CSP) nonces in template.html. For instance:

<script nonce="rAnd0m123" src="/lib/bootstrap-4.5.0/js/bootstrap.min.js"></script>

That way, I would not have to include 'self' in script-src anymore. According to Google's CSP Evaluator, "'self' can be problematic if you host JSONP, Angular or user uploaded files."

Describe the solution you'd like

I would like to use something like %sapper.cspnonce% in my template.html file:

<script nonce="%sapper.cspnonce%" src="/lib/bootstrap-4.5.0/js/bootstrap.min.js"></script>

Sapper would replace %sapper.cspnonce% with the value of res.locals.nonce, if any.

Describe alternatives you've considered

I could not find any way to include the nonce injected via res.locals = { nonce: uuidv4() } in server.js.

How important is this feature to you?

I would like to maximize security for the users of my Sapper app.

Additional context

See Content Security Policy (CSP) in the Sapper documentation for more details on that approach.

@martinburger martinburger changed the title Make Content Security Policy (CSP) nonces available in template.html Make Content Security Policy (CSP) nonce available in template.html Jun 2, 2020
@Conduitry
Copy link
Member

@Conduitry Conduitry commented Sep 25, 2020

This has been added in 0.28.9.

@Conduitry Conduitry closed this Sep 25, 2020
@evdama
Copy link

@evdama evdama commented Sep 26, 2020

I've upgraded and want to use it. I've two script tags in my template.html, the first one gets the nounce, but not the second one... output from chrome devtools below:
Screen Shot 2020-09-26 at 08 44 17

Here's my template html.html snippet with two times nonce="%sapper.cspnonce%"

    <script src="https://www.gstatic.com/firebasejs/7.21.1/firebase-app.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.21.1/firebase-auth.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.21.1/firebase-firestore.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.21.1/firebase-storage.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.21.1/firebase-messaging.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.21.1/firebase-performance.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.21.1/firebase-analytics.js"></script>
    <script nonce="%sapper.cspnonce%" src="./firebase-init.js"></script>

    <script src="https://cdn.jsdelivr.net/npm/gun@0.2020.520/gun.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/gun@0.2020.520/nts.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/gun@0.2020.520/sea.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/gun@0.2020.520/lib/radix.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/gun@0.2020.520/lib/radisk.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/gun@0.2020.520/lib/store.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/gun@0.2020.520/lib/rindexed.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/gun@0.2020.520/lib/then.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/gun@0.2020.520/lib/webrtc.js"></script>
    <script nonce="%sapper.cspnonce%" src="./gun-init.js"></script>

And here the snippet from my server.js creating the nounce

const helmetMiddleware = ( request, response, next ) => {
    helmet({
      contentSecurityPolicy: {
        directives: {
          defaultSrc: ["'self'"],
          connectSrc: [ 'api.stripe.com', 'hooks.stripe.com' ],
          frameSrc: [ 'js.stripe.com', 'hooks.stripe.com' ],
          imgSrc: [ '*.stripe.com' ],
          scriptSrc: [ "'self'", 'js.stripe.com', ( request, response ) => `'nonce-${ response.locals.nonce }'` ],
        },
        browserSniff: false,
      },
    })
  }

Seems the first appearance of nonce="%sapper.cspnonce%" is replaced just fine with the actual nounce but not the second one and so on?! Can anyone confirm?

@martinburger also, if I understand correctly I could get rid of the self in my scriptSrc line now no?
scriptSrc: [ 'js.stripe.com', ( request, response ) => `'nonce-${ response.locals.nonce }'` ]
instead of
scriptSrc: [ "'self'", 'js.stripe.com', ( request, response ) => `'nonce-${ response.locals.nonce }'` ]

@mhatvan
Copy link

@mhatvan mhatvan commented Sep 26, 2020

@evdama I am quite sure it is only getting replaced once because String.replace() only replaces the first occurrence:

.replace('%sapper.cspnonce%', () => nonce_value);

The code should look something like this imo: .replace(/%sapper.cspnonce%/g, () => nonce_value);

Regarding the self in scriptSrc:
the files ./firebase-init.js and ./gun-init.js are part of your own domain, so you need self

@benmccann
Copy link
Contributor

@benmccann benmccann commented Sep 26, 2020

I've filed a bug to track that issue: #1565. If anyone wants to send a PR for it I will help review it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
5 participants
You can’t perform that action at this time.