Content Security Policy
Enabled Prevent unwanted content from being injected in your app.
Content Security Policy (CSP) helps prevent unwanted content from being injected/loaded into your webpages. This can mitigate cross-site scripting (XSS) vulnerabilities, clickjacking, formjacking, malicious frames, unwanted trackers, and other web client-side attacks.
Usage
This header is enabled by default but you can change its behavior like following.
export default defineNuxtConfig({ // Global security: { headers: { contentSecurityPolicy: <OPTIONS>, }, }, // Per route routeRules: { '/custom-route': { security: { headers: { contentSecurityPolicy: <OPTIONS>, }, }, } }})
You can also disable this header by contentSecurityPolicy: false
.
Default value
By default, Nuxt Security will set following value for this header:
Content-Security-Policy: base-uri 'none'; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; img-src 'self' data:; object-src 'none'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'strict-dynamic' 'nonce-{{nonce}}'; upgrade-insecure-requests;
Available values
The contentSecurityPolicy
header can be configured with following values.
contentSecurityPolicy: { 'child-src'?: CSPSourceValue[] | string | false; 'connect-src'?: CSPSourceValue[] | string | false; 'default-src'?: CSPSourceValue[] | string | false; 'font-src'?: CSPSourceValue[] | string | false; 'frame-src'?: CSPSourceValue[] | string | false; 'img-src'?: CSPSourceValue[] | string | false; 'manifest-src'?: CSPSourceValue[] | string | false; 'media-src'?: CSPSourceValue[] | string | false; 'object-src'?: CSPSourceValue[] | string | false; 'prefetch-src'?: CSPSourceValue[] | string | false; 'script-src'?: CSPSourceValue[] | string | false; 'script-src-elem'?: CSPSourceValue[] | string | false; 'script-src-attr'?: CSPSourceValue[] | string | false; 'style-src'?: CSPSourceValue[] | string | false; 'style-src-elem'?: CSPSourceValue[] | string | false; 'style-src-attr'?: CSPSourceValue[] | string | false; 'worker-src'?: CSPSourceValue[] | string | false; 'base-uri'?: CSPSourceValue[] | string | false; 'sandbox'?: CSPSandboxValue[] | string | false; 'form-action'?: CSPSourceValue[] | string | false; 'frame-ancestors'?: ("'self'" | "'none'" | string)[] | string | false; 'navigate-to'?: ("'self'" | "'none'" | "'unsafe-allow-redirects'" | string)[] | string | false; 'report-uri'?: string[] | string | false; 'report-to'?: string | false; 'upgrade-insecure-requests'?: boolean;} | false
Array and String syntaxes
CSPSourceValue type
CSPSandboxValue type
Strict CSP
Nuxt Security helps you increase the security of your site by enabling Strict CSP support for both SSR and SSG applications.
For further reading about Strict CSP and how to handle specific cases, please consult our Adanced Section about Strict CSP
- For SSR applications, Nuxt Security implements strict CSP via nonces. A one-time cryptographically-generated random nonce is generated at runtime by the server for each request of a page.
- For SSG applications, Nuxt Security implements strict CSP via hashes. At static build-time, Nuxt Security computes the SHA hashes of the elements that are allowed to execute on your site.
By default, Strict CSP will be enabled on your site. The following default configuration options are used:
export default defineNuxtConfig({ security: { nonce: true, // Enables HTML nonce support in SSR mode ssg: { hashScripts: true, // Enables CSP hash support for scripts in SSG mode hashStyles: false // Disables CSP hash support for styles in SSG mode (recommended) }, headers: { contentSecurityPolicy: { 'script-src': [ "'self'", // Fallback value, will be ignored by most modern browsers (level 3) "https:", // Fallback value, will be ignored by most modern browsers (level 3) "'unsafe-inline'", // Fallback value, will be ignored by almost any browser (level 2) "'strict-dynamic'", // Strict CSP via 'strict-dynamic', supported by most modern browsers (level 3) "'nonce-{{nonce}}'" // Enables CSP nonce support for scripts in SSR mode, supported by almost any browser (level 2) ], 'style-src': [ "'self'", // Enables loading of stylesheets hosted on same origin "https:", // For increased security, replace by the specific hosting domain or file name of your external stylesheets "'unsafe-inline'" // Recommended default for most Nuxt apps ], 'img-src': ["'self'", "data:"], // Add relevant https://... sources if you load images from external sources 'font-src': ["'self'", "https:", "data:"], // For increased security, replace by the specific sources for fonts 'base-uri': ["'none'"], 'object-src': ["'none'"], 'script-src-attr': ["'none'"], 'form-action': ["'self'"], 'frame-ancestors': ["'self'"], 'upgrade-insecure-requests': true } }, sri: true }})
Server Side Rendering (SSR)
Nuxt Security provides first-class support of SSR apps via 'strict-dynamic' and nonces.
In SSR mode, Strict CSP is enabled when you set the nonce
option and the "'nonce-{{nonce}}'"
placeholders:
export default defineNuxtConfig({ // Global security: { nonce: true, // Enables HTML nonce support in SSR mode }, headers: { contentSecurityPolicy: { 'script-src': [ "'strict-dynamic'", // Modify with your custom CSP sources "'nonce-{{nonce}}'" // Enables CSP nonce support for scripts in SSR mode, supported by almost any browser (level 2) ] } }, // Per route routeRules: { '/custom-route': { security: { nonce: false, headers: { contentSecurityPolicy: { 'script-src': "self 'unsafe-inline'" }, }, }, } }})
nonce
: Set this option totrue
to parse all<script>
,<link>
and<style>
tags in your application and add the nonce value to these. The module parses all inline elements as well as all external resources."'nonce-{{nonce}}'"
placeholder: Include this value in any individual policy that you want to be governed by nonce.
"'nonce-{{nonce}}'"
placeholder on style-src
policy.
⚠ This is because Nuxt's mechanism for Client-Side hydration of styles could be blocked by CSP in that case.
For further discussion and alternatives, please refer to our Advanced Section on Strict CSP.
Note: Nonce only works for SSR. The nonce
option and the "'nonce-{{nonce}}'"
placeholders are ignored when you build your app for SSG via nuxi generate
.
Static Site Generation (SSG)
This module is meant to work with SSR apps, but you can also use this module in SSG apps where you will get a Content Security Policy (CSP) support via <meta http-equiv>
tag.
This will result in following code being added to your static app <head>
tag:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
For SSG apps, Strict CSP is enabled when you set the ssg
and sri
options:
export default defineNuxtConfig({ // Global security: { ssg: { hashScripts: true, // Enables CSP hash support for scripts in SSG mode hashStyles: false // Disables CSP hash support for styles in SSG mode (recommended) }, sri: true, headers: { contentSecurityPolicy: { 'script-src': [ "'strict-dynamic'", // Modify with your custom CSP sources // The nonce-{{nonce}} placeholder is not required and will be ignored in SSG mode ] } } }, // Per route routeRules: { '/custom-route': { security: { ssg: false, sri: false, headers: { contentSecurityPolicy: { 'script-src': "self 'unsafe-inline'" }, }, }, } }})
Nuxt Security will generate script hashes and style hashes for you according to the ssg
option:
hashScripts
: Set this option totrue
to parse all inline scripts as well as all external scripts. Nuxt-Security will compute the hashes of inline scripts and find theintegrity
attributes of external scripts, and will add them to yourscript-src
policy.hashStyles
: Set this option totrue
to parse all inline styles as well as all external styles. Nuxt-Security will compute the hashes of inline styles and find theintegrity
attributes of external styles, and will add them to yourstyle-src
policy.
ssg: hashStyles
option to true
.
⚠ This is because Nuxt's mechanism for Client-Side hydration of styles could be blocked by CSP in that case.
For further discussion and alternatives, please refer to our Advanced Section on CSP.
integrity
attributes of all your bundled assets if you set the sri
option to true
. For unbundled assets, you may need to set the integrity
attribute manually.
Please see below our section on Integrity Hashes For SSG
Note: Hashes only work for SSG. The ssg
options are ignored when you build your app for SSR via nuxi build
.
Hot reloading during development
If you have enabled nonce-{{nonce}}
on style-src
, you will need to disable it in order to allow hot reloading during development.
export default defineNuxtConfig({ security: { nonce: true, headers: { contentSecurityPolicy: { 'style-src': process.env.NODE_ENV = 'development' ? ["'self'", "'unsafe-inline'"] : ["'self'", "'unsafe-inline'", "nonce-{{nonce}}"] } } }})
Note that this is not necessary if you use our default configuration settings.
Per-route configuration
All Content Security Policy options can be defined on a per-route level.
export default defineNuxtConfig({ // Global security: { headers: { contentSecurityPolicy: { 'img-src': false // By default, no images can be loaded } } } // Per route routeRules: { '/some-prefix/**': { security: { headers: { contentSecurityPolicy: { 'img-src': ["'self'"] // Self-hosted images can be loaded for routes beginning with /some-prefix/ } } } }, '/some-prefix/some-route/**': { security: { headers: { contentSecurityPolicy: { // With array syntax : additive 'img-src': ["https:"] // Self-hosted AND https: images can be loaded for routes beginning with /some-prefix/some-route/ } } } }, '/some-prefix/some-route/some-page': { security: { headers: { contentSecurityPolicy: { // With string syntax : substitutive 'img-src': 'self' // ONLY self-hosted images can be loaded on /some-prefix/some-route/some-page } } } } }})
Nuxt Security resolves the contentSecurityPolicy
options using the native Nitro router strategy:
- Additive merging with the array syntax: If you write your rules with the array syntax (e.g.
"img-src": ["'self'", "https:"]
), the new route policies will be added to the policies defined for higher-level routes. Use this strategy if you need to add specific policy values to your route without deleting the existing ones. - Substitutive merging with the string syntax: If you write your rules with the string syntax (e.g.
"img-src": "'self' https:"
), the new route policies will be substituted to the policies defined for higher-level routes. Use this strategy if you need to delete existing policies before setting your specific route policies.
Nonces for SSR
For SSR apps, if you use 'strict-dynamic'
in your script-src
policy, each of your external scripts will need to be whitelisted by nonce.
Fortunately, Nuxt Security will include the nonce in all your relevant HTML resources by default.
You can easily add your external scripts to your HTML document with the useHead
composable:
useHead({ script: [ { src: 'https://example.com/script.js' } ] }, { mode: 'server' // Set the mode to 'server' if you want to avoid re-loading the script on the client // Set the mode to 'client' if you want client-side only loading // see: https://github.com/unjs/unhead/issues/136 })
If you are unwilling or unable to use useHead
, you can also directly insert tags into the DOM via document.createElement()
:
<script setup>onMounted(() => { const script = document.createElement('script') script.src = 'loader.js' document.head.appendChild(script)})</script>
Integrity Hashes For SSG
For SSG apps, if you use 'strict-dynamic'
in your script-src
policy, each of your external scripts will need to carry an integrity attribute.
This is a mandatory requirement of CSP Level 3.
You can easily add integrity values to your scripts with the useHead
composable:
useHead({ script: [ { src: 'https://example.com/script.js', crossorigin: 'anonymous', integrity: 'sha384-.....' // Insert the integrity hash here } ] })
If you insert scripts manually in your app, you can also include their integrity attribute manually
<script src="https://example.com/script.js" integrity="sha384-....." crossorigin="anonymous" />