JoviDeCroock / webpack-module-nomodule-plugin

Easily implement a module nomodule index.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to use this alongside CspHtmlWebpackPlugin?

thecontrarycat opened this issue · comments

I have webpack-module-nomodule-plugin configured and working well for my build, but now we want to add a content security policy and have turned to CspHtmlWebpackPlugin to automatically generate the policy and hashes in the generated HTML file.

The problem is that the tags added by this module don't get hashed. Note in the example below how the stylesheet correctly receives a nonce, but the scripts added by webpack-module-nomodule-plugin aren't hashed:

<head>
	<meta http-equiv="Content-Security-Policy" content="base-uri 'self'; object-src 'none'; script-src 'unsafe-inline' 'self' 'unsafe-eval' 'sha256-nbjaHTCvPZmU6ZiLRgVqNzYz409cIY3Rn9XE5hGHMeI=' 'sha256-nbRAlhO1i8u4QabQ5nggX59s9v3tjLo5sWZX+BTFHtI='; style-src 'unsafe-inline' 'self' 'unsafe-eval' 'nonce-lqH2Zrsqc6O6yUT997okUw=='">
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width,initial-scale=1">
	<link href="/app.0d82d688390ad51c2cb4.css" rel="stylesheet" nonce="lqH2Zrsqc6O6yUT997okUw==">
	<link rel="modulepreload" href="/modern.vendors.3be4fa4f9fd56490771e.js">
	<link rel="modulepreload" href="/modern.main.a90abc59fba4a2ae5ece.js">
	<script type="module">self.m=1</script>
	<script>addEventListener('DOMContentLoaded', function() {
	$l("/modern.vendors.3be4fa4f9fd56490771e.js", "/legacy.vendors.51840cb0b0964db95818.js")
	$l("/modern.main.a90abc59fba4a2ae5ece.js", "/legacy.main.3ef3fe9d7d57298324e9.js")
	})
	function $l(e,d,c){c=document.createElement("script"),self.m?(e && (c.src=e,c.type="module")):d && (c.src=d),c.src && document.head.appendChild(c)}</script>
</head>

How can we make these two plugins play nicely together?

Hey,

Thanks for the issue report, I wonder if this is due to us conflicting in when we inject the library into the alterAssetTagGroups. Maybe we should do this synchronously instead, I personally don't really see an issue judging on their implementation, maybe we have to look at the csp-object they inject. Might need to look at other plugins if they do something special 😅

Interestingly, 'minimal' mode works slightly better as we get the nonce on all of the script tags that load resources from src:

<!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="Content-Security-Policy" content="base-uri 'self'; object-src 'none'; script-src 'unsafe-inline' 'self' 'unsafe-eval' 'sha256-TwHagfOUnINCcJxJa+HMc+5nNBIU5lrMfodaDI+K/bQ=' 'nonce-zGudxLCnVG94Sc47r1ol2w==' 'nonce-I1bA1FOBUqK147bb6ptF9A==' 'nonce-dFDNQDSgDNSo0YFxMPmxSg==' 'nonce-yf2RtiC4LLiQk78MX99gyw=='; style-src 'unsafe-inline' 'self' 'unsafe-eval' 'nonce-14iu2xtxFbjQX6bDEqFjNQ=='">
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width,initial-scale=1">
		<link href="/app.0d82d688390ad51c2cb4.css" rel="stylesheet" nonce="14iu2xtxFbjQX6bDEqFjNQ==">
	</head>
	<body>
		<div id="app"/>
		<script src="/modern.main.a90abc59fba4a2ae5ece.js" type="module" nonce="zGudxLCnVG94Sc47r1ol2w=="/>
		<script src="/modern.vendors.3be4fa4f9fd56490771e.js" type="module" nonce="I1bA1FOBUqK147bb6ptF9A=="/>
		<script>(function(){var d=document;var c=d.createElement('script');if(!('noModule' in c)&&'onbeforeload' in c){var s=!1;d.addEventListener('beforeload',function(e){if(e.target===c){s=!0}else if(!e.target.hasAttribute('nomodule')||!s){return}e.preventDefault()},!0);c.type='module';c.src='.';d.head.appendChild(c);c.remove()}}())</script>
		<script src="/legacy.main.3ef3fe9d7d57298324e9.js" nomodule nonce="dFDNQDSgDNSo0YFxMPmxSg=="/>
		<script src="/legacy.vendors.51840cb0b0964db95818.js" nomodule nonce="yf2RtiC4LLiQk78MX99gyw=="/>
	</body>
</html>

It would be great to get a nonce on the dynamically generated script tags that this module creates, though.

I think this is because they are checking for script with src

@thecontrarycat I wonder if you could achieve this by turning on unsafe-inlinehttps://github.com/slackhq/csp-html-webpack-plugin

After doing some further reading it looks like the only thing that might not be working is the <link rel="modulepreload"> and for that I'm not even sure whether it supports CSP at all (preload does, but not sure about modulepreload).

I'll have to do some tests tomorrow and find out.

Just to tidy this off for anyone who comes across this in the future:

  • csp-html-webpack-plugin generates hashes but not nonces for inline scripts, so it is working correctly
  • modulepreload obeys the standard script-src directive in the csp
  • there's nothing wrong with this module and it does work correctly when you configure your csp properly

@thecontrarycat Thanks for the heads up! Could you include what that configuration is? I'm happy it's working well for you!