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

Add __webpack__nonce to style tags #887

Closed
johannesnagl opened this Issue Jun 8, 2017 · 17 comments

Comments

Projects
None yet
7 participants
@johannesnagl

johannesnagl commented Jun 8, 2017

I already had a brief talk with @mxstbr about this a couple of weeks ago: https://twitter.com/mxstbr/status/824626370760364032

When trying to enforce strict rules about which content is allowed on a specific page, a Content Security Policy (CSP) is the way to go.

Styled-Components currently put all of their Styles as an inline style to the DOM. Therefore, a CSP would need to contain: style-src unsafe-inline. As the name already puts: This is unsafe and not the recommended way of securing your app.

Luckily, there is the concept of nonce attributes. Style/Script tags with a whitelisted nonce can be specified in the CSP. If Styled-Components would set this nonce, we could get rid of the unsafe-inline setting.

Luckily, WebPack is already supporting the concept of a global __webpack_nonce__ variable. Once set, all dynamically injected code created by WebPack will have a nonce attribute with the correct value.

What needs Styled-Components to do?

If the webpack_nonce variable is set, pass the value to every generated style tag inside the nonce attribute of the style tag.

Unluckily, the __webpack_nonce__ is not well documented and kind of a myth. See Google https://www.google.at/search?q=webpack_nonce__&oq=webpack_nonce__&aqs=chrome..69i57.4663j0j7&sourceid=chrome&ie=UTF-8#q=__webpack_nonce__ and GitHub: https://github.com/webpack/webpack/search?utf8=%E2%9C%93&q=__webpack_nonce__&type=

Further readings:

@mxstbr

This comment has been minimized.

Member

mxstbr commented Jun 8, 2017

This seems like a very reasonable thing to implement!

@sokra @TheLarkInn can you confirm that __webpack_nonce__ will be supported in the future? Can you point us to any docs about it/is it documented at all?

@sokra

This comment has been minimized.

sokra commented Jun 8, 2017

I guess there are no docs for it yet. But if you add docs for it it probably stays supported.

Here is the PR for the feature: webpack/webpack#3210

@arahansen

This comment has been minimized.

arahansen commented Aug 18, 2017

Unfortunately, nonce attributes are not supported in ie11

Is there any known workaround for avoiding such CSP violations as this in ie11?

@elzii

This comment has been minimized.

elzii commented Sep 27, 2017

I would love more discussion on this. PCI Compliance audits can mandate the need to have a CSP that prohibits using awesome libraries like this, or worse, having to remove them to pass compliance :-/

@arahansen

This comment has been minimized.

arahansen commented Sep 28, 2017

@elzii The discussion here resolved with the fact that ie 11 doesn't support CSP restrictions anyways. So even if your server restricts inline styles, ie11 will still render them, and you will not see any errors in the browser.

@mindhaq

This comment has been minimized.

mindhaq commented Feb 1, 2018

I would also love to see more discussion on this. My current setup with a strict Content-Security-Policy effectively prevents the use of styled components.

Inserting a static nonce with webpack seems like a bad idea as well. If all style elements have the same nonce everywhere everytime, this would defeat the whole purpose of having a nonce.

@mxstbr

This comment has been minimized.

Member

mxstbr commented Feb 1, 2018

We implemented support for __webpack-nonce__ back in July, what else are you looking for @mindhaq?

@johannesnagl

This comment has been minimized.

johannesnagl commented Feb 1, 2018

@simonpkerr

This comment has been minimized.

simonpkerr commented Mar 27, 2018

@johannesnagl can you point me at that working solution? I can't get this working.
I've added webpack_nonce to my entry point index.js like this...

const styleTag = document.getElementsByTagName('style')[0] || {};
__webpack_nonce__ = styleTag.nonce || '';

this means the nonce generated on the server and injected into the template can be picked up by the react app entry point. The nonce is getting picked up from the style tag, but webpack isn't picking up the webpack_nonce value.

@johannesnagl

This comment has been minimized.

johannesnagl commented Mar 27, 2018

This is our implementation!

/* global __webpack_nonce__ */ // eslint-disable-line no-unused-vars

// CSP: Set a special variable to add `nonce` attributes to all styles/script tags
// See https://github.com/webpack/webpack/pull/3210
__webpack_nonce__ = window.NONCE_ID; // eslint-disable-line no-global-assign, camelcase

In our layout file, which is served via PHP, we have the following, simplified code (above the script tag with the webpack-bundle of course):

<script nonce="<?= $currentNonce ?>">window.NONCE_ID = '<?= $currentNonce ?>';</script>
<script src="HERE_COMES_YOUR_BUNDLE.js"></script>
@simonpkerr

This comment has been minimized.

simonpkerr commented Mar 27, 2018

that looks pretty similar to what I've got. Does the webpack_nonce value need to be set before any imports? I'm getting an error.
The nonce shown in the image below is the one in the entry point file that references __webpack_nonce__. So its getting picked up in the entry file.

screen shot 2018-03-27 at 12 14 03

@mxstbr

This comment has been minimized.

Member

mxstbr commented Mar 27, 2018

I think it has to be before any imports. Since imports are hoisted, you'll have to create a separate file (import-nonce.js) and import that before anything else that imports styled-components.

@simonpkerr

This comment has been minimized.

simonpkerr commented Mar 28, 2018

thanks @mxstbr, that did it 👍

@johannesnagl

This comment has been minimized.

johannesnagl commented Mar 28, 2018

@simonkerr would you like to share the full setup with everyone, so that the next dev coming here has a better time then you had? #developerlove

@simonpkerr

This comment has been minimized.

simonpkerr commented Mar 28, 2018

@johannesnagl where would you suggest the best place to do that? I'm writing a blog post at the moment about all this stuff and was thinking of updating the webpack docs for nonces.

@johannesnagl

This comment has been minimized.

johannesnagl commented Mar 28, 2018

@simonpkerr Fixing the nonce docs is definitely needed - so +1 for this!

Regarding my comment: I would just paste a small code example here. Nevertheless, if you write a blog post, feel free to add the link here too!

@simonpkerr

This comment has been minimized.

simonpkerr commented Mar 28, 2018

So...in your server-side code you set up the nonce and expose it to your client-side code before any other scripts are defined

<script nonce="<?= $currentNonce ?>">window.NONCE_ID = '<?= $currentNonce ?>';</script>
<script src="HERE_COMES_YOUR_BUNDLE.js"></script>

In your entry point file, import your 'create-nonce.js' file before any files that reference styled components.

// (index.js)
import React from 'react';
import { Provider } from 'react-redux';
import { render, unmountComponentAtNode } from 'react-dom';
import { ThemeProvider } from 'styled-components';
import '../create-nonce';

import theme from './css/themes/default/theme';
import './css/default/baseline';
//...etc

Then in 'create-nonce.js' grab the global NONCE_ID variable...

__webpack_nonce__ = window.NONCE_ID;

Webpack will now add the nonce attribute to any injected script or style tag on a per request basis.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment