How do I integrate the value of __webpack_nonce___

2020-05-27 03:56发布

From my understanding of Content Security Policy, the nonce has to change on every request. That means (I think) it must be generated at run-time on the client, not at build-time in the Webpack config. I've tested the webpack_nonce functionality in my app and it works great.

Unfortunately, I'm not sure how to get that value, generated at run-time on the client, to the actual CSP policy, which is either set as a meta-tag in the index.html file (or some equivalent) or on the server itself.

I suppose you could set the CSP meta-tag dynamically on the client, but that seems like a security risk. I've experimented with the csp-webpack-plugin, which calculates hashes of files at build-time and then adds them to the index.html. This process makes sense to me, it just didn't support our use case.

I just feel like I'm missing something with using webpack_nonce.

1条回答
Fickle 薄情
2楼-- · 2020-05-27 04:21

We were able to get a dynamic nonce by having webpack build our index page (e.g via HtmlWebpackPlugin) as a template then serving it dynamically. This way, you can set __webpack_nonce__ to an interpolation expression like <%=nonce%> and the server view engine can sub in your dynamic nonce at page-load time. For example, if you're using express:

Webpack config:

const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: 'index.js',
  output: {
    path: __dirname + '/dist',
    filename: 'index_bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: __dirname + '/dist/index.ejs',
    })
  ]
}

Webpack entry point (index.js):

__webpack_nonce__ = '<%=nonce%>';

Express app:

// Generate dynamic nonce on each request cycle
const uuid = require('node-uuid');
app.use((req, res, next) => {
  res.locals.nonce = uuid.v4();
  next();
});

app.set('view engine', 'ejs');
app.route('/').get((req, res, next) => {
  res.render('path/to/index.ejs', { nonce: res.locals.nonce });
});

The injected <script> tags will have the literal attribute nonce=<%=nonce%> appended, which the server will then interpolate when serving your page.

Note that if you use a custom template with HtmlWebpackPlugin, you might want to set a different interpolation delimiter for ejs otherwise Webpack will interpolate the nonce expression at build time instead of runtime.

Express app:

const ejs = require('ejs);
ejs.delimiter = '?'; // Means instead use __webpack_nonce__ = '<?=nonce?>'
查看更多
登录 后发表回答