-
-
Notifications
You must be signed in to change notification settings - Fork 15
Description
We are loading many resources dynamically via Webpack module federation and async imports.
This is done via inline style/scripts.
This is in direct conflict with CSP:
Some Info
To use Webpack Module Federation and dynamic imports (for both JavaScript and CSS) with a strong Content Security Policy (CSP) that does not allow unsafe-inline, and still benefit from production-grade “Static CSS Only” deployment, you need to take several coordinated steps.
1. JavaScript: Dynamic Imports & CSP
-
Webpack CSP Support: Webpack supports CSP by allowing you to specify a nonce on your script tags. This means dynamic chunks (JS loaded via
import()or module federation) are loaded using ``. To use this: -
Module Federation Considerations: Module federation’s dynamic loading of remote JS depends on runtime evaluation and dynamic `` injection. This is compatible with nonce-based CSP as long as all dynamically created scripts have the right nonce[3][2].
-
Strict Mode Caveats: Avoid development tools like
'eval'for chunk loading, as those requireunsafe-eval(incompatible with strict CSP). Usedevtool: 'source-map'or similar in production builds[3][4]. -
Trusted Types (optional): Webpack can also be used with Trusted Types for even stricter CSP environments, avoiding common DOM-based XSS vectors[1].
2. CSS: Static Extraction, Dynamic Loading, and CSP
-
Static CSS in Production: Use
MiniCssExtractPluginto extract CSS, which generates static.cssfiles loaded via. These are fully compatible with CSP, astags do not requireunsafe-inline[5]. -
Dynamic CSS Loading:
- If you must load CSS dynamically, use
style-loaderwithinjectType: 'lazyStyleTag'in development, but this injects `` tags and requiresunsafe-inline. - The production best practice (and what you seem to like): Only use extracted
.cssfiles (via `` tags) in production, so you never need dynamic CSS insertion. With this approach, you only need to allow loading CSS from authorized domains, neverunsafe-inline[5]. - If you must occasionally load additional CSS on demand: use JS to inject `` elements—this is allowed under CSP (as long as loading from approved sources, and not using
styletags with inline rules).
- If you must load CSS dynamically, use
3. Putting It Together (Recipe)
-
CSP Policy example:
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-XYZ' https://your-remotes.example.com; style-src 'self' https://your-cdn.example.com; object-src 'none'; base-uri 'self'; -
HTML Template Setup (nonce injection):
window.__webpack_nonce__ = 'XYZ';
And ensure that all dynamic `` tags (loaded by Webpack runtime) have
nonce="XYZ"[2]. -
Webpack config hints:
- For JS: Use
output.chunkLoadingGlobaland configure the runtime or HTML plugins to include your nonce. - For CSS: Use
MiniCssExtractPluginand only serve extracted CSS in production. Avoid dynamic style-tag injection except in development[5].
- For JS: Use
-
Module Federation Remotes:
- For federated dynamic imports, make sure remote URLs are whitelisted in
script-src. - Use a nonce for dynamic script tags, by customizing the runtime loading mechanism if needed (some plugins or runtime hooks may let you do this[3][2]).
- For federated dynamic imports, make sure remote URLs are whitelisted in
4. Caveats
- No support for
unsafe-inlineorunsafe-eval: Do not use loaders, plugins, or dev configurations that inject inline JS or rely oneval. - CSS Injection: Only use `` based loading for CSS in production to avoid running afoul of CSP.
- Third-party modules: Any third-party library/module federation remote must comply with these CSP and nonce rules as well.
In summary:
- Use nonce-based CSP for all JS, inject the nonce for both Webpack and federation-loaded JS.
- Extract all CSS to real files, loaded via ``, not dynamically via style-loader except in dev.
- Federated/dynamically loaded JS modules work as long as runtime script tags receive your nonce.
- You never need
unsafe-inlinefor this setup, either for JS or CSS, in production[1][2][5].
References used in answer:
[1][2][5]
[1] https://webpack.js.org/guides/csp/
[2] https://towardsdatascience.com/content-security-policy-how-to-create-an-iron-clad-nonce-based-csp3-policy-with-webpack-and-nginx-ce5a4605db90/
[3] module-federation/core#2631
[4] https://github.com/webpack/webpack/issues/[5](https://webpack.js.org/loaders/style-loader/)627
[5] https://webpack.js.org/loaders/style-loader/
[6] https://stackoverflow.com/questions/31211359/refused-to-load-the-script-because-it-violates-the-following-content-security-po
[7] https://stackoverflow.com/questions/41259838/is-there-any-way-to-dynamically-load-css-file-with-webpack
[8] https://module-federation.io/practice/frameworks/modern/dynamic-remote.html
[9] https://dev.to/omher/lets-dynamic-remote-modules-with-webpack-module-federation-2b9m
[10] https://stackoverflow.com/questions/69179460/code-structure-when-dynamically-load-a-micro-frontend-via-module-federation
[11] https://nextjs.org/docs/pages/guides/content-security-policy
[12] https://content-security-policy.com/strict-dynamic/
[13] https://www.fabrizioduroni.it/blog/post/[2](https://towardsdatascience.com/content-security-policy-how-to-create-an-iron-clad-nonce-based-csp3-policy-with-webpack-and-nginx-ce5a4605db90/)022/06/06/microfrontend-module-federation-dynamic-configuration
[14] https://webpack.js.org/concepts/module-federation/
[15] cssinjs/jss#559
[16] https://rsbuild.rs/guide/advanced/module-federation
[17] webpack/webpack#118
[18] module-federation/core#3550
[19] https://lawrencewhiteside.com/courses/webpack-beyond-the-basics/dynamic-css-chunk-loading/
[20] https://blog.logrocket.com/solving-micro-frontend-challenges-module-federation/