This plugin will generate meta content for your Content Security Policy tag and input the correct data into your HTML template, generated by html-webpack-plugin.
All inline JS and CSS will be hashed and inserted into the policy.
Install the plugin with npm:
npm i --save-dev csp-html-webpack-pluginInclude the following in your webpack config:
const HtmlWebpackPlugin = require('html-webpack-plugin'); const CspHtmlWebpackPlugin = require('csp-html-webpack-plugin'); module.exports = { // rest of webpack config plugins: [ new HtmlWebpackPlugin() new CspHtmlWebpackPlugin({ // config here, see below }) ] }By default, the csp-html-webpack-plugin has a very lax policy. You should configure it for your needs.
A good starting policy would be the following:
new CspHtmlWebpackPlugin({ 'script-src': '', 'style-src': '' }); Although we're configuring script-src and style-src to be blank, the CSP plugin will scan your HTML generated in html-webpack-plugin for external/inline script and style tags, and will add the appropriate hashes and nonces to your CSP policy. This configuration will also add a base-uri and object-src entry that exist in the default policy:
<meta http-equiv="Content-Security-Policy" content=" base-uri 'self'; object-src 'none'; script-src 'sha256-0Tumwf1AbPDHZO4kdvXUd4c5PiHwt55hre+RDxj9O3Q=' 'nonce-hOlyTAhW5QI5p+rv9VUPZg=='; style-src 'sha256-zfLUTOi9wwJktpDIoBZQecK4DNIVxW8Tl0cadROvQgo=' "> This configuration should work for most use cases, and will provide a strong layer of extra security.
This CspHtmlWebpackPlugin accepts 2 params with the following structure:
{object}Policy (optional) - a flat object which defines your CSP policy. Valid keys and values can be found on the MDN CSP page. Values can either be a string, or an array of strings.{object}Additional Options (optional) - a flat object with the optional configuration options:{boolean|Function}enabled - if false, or the function returns false, the empty CSP tag will be stripped from the html output.- The
htmlPluginDatais passed into the function as it's first param. - If
enabledis set the false, it will disable generating a CSP for all instances ofHtmlWebpackPluginin your webpack config.
- The
{string}hashingMethod - accepts 'sha256', 'sha384', 'sha512' - your node version must also accept this hashing method.{object}hashEnabled - a<string, boolean>entry for which policy rules are allowed to include hashes{object}nonceEnabled - a<string, boolean>entry for which policy rules are allowed to include nonces{Function}processFn - allows the developer to overwrite the default method of what happens to the CSP after it has been created- Parameters are:
builtPolicy: astringcontaining the completed policy;htmlPluginData: theHtmlWebpackPluginobject;$: thecheerioobject of the html file currently being processedcompilation: Internal webpack object to manipulate the build
- Parameters are:
The plugin also adds a new config option onto each HtmlWebpackPlugin instance:
{object}cspPlugin - an object containing the following properties:{boolean}enabled - if false, the CSP tag will be removed from the HTML which this HtmlWebpackPlugin instance is generating.{object}policy - A custom policy which should be applied only to this instance of the HtmlWebpackPlugin{object}hashEnabled - a<string, boolean>entry for which policy rules are allowed to include hashes{object}nonceEnabled - a<string, boolean>entry for which policy rules are allowed to include nonces{Function}processFn - allows the developer to overwrite the default method of what happens to the CSP after it has been created- Parameters are:
builtPolicy: astringcontaining the completed policy;htmlPluginData: theHtmlWebpackPluginobject;$: thecheerioobject of the html file currently being processedcompilation: Internal webpack object to manipulate the build
- Parameters are:
You don't have to include the same policy / hashEnabled / nonceEnabled configuration object in both HtmlWebpackPlugin and CspHtmlWebpackPlugin.
- Config included in
CspHtmlWebpackPluginwill be applied to all instances ofHtmlWebpackPlugin. - Config included in a single
HtmlWebpackPlugininstantiation will only be applied to that instance.
In the case where a config object is defined in multiple places, it will be merged in the order defined below, with former keys overriding latter. This means entries for a specific rule will not be merged; they will be replaced.
> HtmlWebpackPlugin cspPlugin.policy > CspHtmlWebpackPlugin policy > CspHtmlWebpackPlugin defaultPolicy { 'base-uri': "'self'", 'object-src': "'none'", 'script-src': ["'unsafe-inline'", "'self'", "'unsafe-eval'"], 'style-src': ["'unsafe-inline'", "'self'", "'unsafe-eval'"] };{ enabled: true hashingMethod: 'sha256', hashEnabled: { 'script-src': true, 'style-src': true }, nonceEnabled: { 'script-src': true, 'style-src': true }, processFn: defaultProcessFn }new HtmlWebpackPlugin({ cspPlugin: { enabled: true, policy: { 'base-uri': "'self'", 'object-src': "'none'", 'script-src': ["'unsafe-inline'", "'self'", "'unsafe-eval'"], 'style-src': ["'unsafe-inline'", "'self'", "'unsafe-eval'"] }, hashEnabled: { 'script-src': true, 'style-src': true }, nonceEnabled: { 'script-src': true, 'style-src': true }, processFn: defaultProcessFn // defined in the plugin itself } }); new CspHtmlWebpackPlugin({ 'base-uri': "'self'", 'object-src': "'none'", 'script-src': ["'unsafe-inline'", "'self'", "'unsafe-eval'"], 'style-src': ["'unsafe-inline'", "'self'", "'unsafe-eval'"] }, { enabled: true, hashingMethod: 'sha256', hashEnabled: { 'script-src': true, 'style-src': true }, nonceEnabled: { 'script-src': true, 'style-src': true }, processFn: defaultProcessFn // defined in the plugin itself })Some specific directives require the CSP to be sent to the client via a response header (e.g. report-uri and report-to) You can set your own processFn callback to make this happen.
In your webpack config:
const RawSource = require('webpack-sources').RawSource; function generateNginxHeaderFile( builtPolicy, _htmlPluginData, _obj, compilation ) { const header = 'add_header Content-Security-Policy "' + builtPolicy + '; report-uri /csp-report/ ";'; compilation.emitAsset('nginx-csp-header.conf', new RawSource(header)); } module.exports = { {...}, plugins: [ new CspHtmlWebpackPlugin( {...}, { processFn: generateNginxHeaderFile }) ] };In your nginx config:
location / { ... include /path/to/webpack/output/nginx-csp-header.conf }Contributions are most welcome! Please see the included contributing file for more information.
This project is licensed under MIT. Please see the included license file for more information.