Configuring Content Security Policy Headers
Modern browsers use Content Security Policy HTTP response headers to enhance web pages’ security to mitigate certain types of attacks (like Cross-Site Scripting or data injection). You can enable CSP on Liferay to send the configured headers on each HTTP request.
CSP policies have many options. It is best to understand your users’ needs and come up with a policy to suit their requirements. After enabling CSP headers, they’re enforced by the browsers. Visit the links below to learn more about how browsers handle CSP headers:
This feature is currently behind a beta feature flag. See Beta Feature Flags for more information. Configuring an unsupported content security policy can cause your instance to malfunction.
Content Security Policy Directives and Values
Content Security Policies take the form of key-value pairs. The keys are directives, and they can have values. Using directives and values, you can form a robust policy to protect web applications against a variety of threats.
Directives: Directives specify the resources (scripts, stylesheets, images, etc.) a browser can load or execute on a web page. Below are examples of some commonly used directives, and the most restrictive values supported by Liferay.
Directive | Minimum Supported Value | Description |
---|---|---|
default-src | N/A | Specifies the default source for content types not explicitly defined by other directives. |
base-uri | N/A | Specifies the base URL for resolving relative URLs. |
connect-src | self | Specifies the sources to which you can make network requests. |
frame-ancestors | none | Specifies which parent pages can embed resources in frames, IFrames, or other embed elements. |
frame-src | self | Specifies the domains from where you can embed pages or applications into a frame or IFrame. |
img-src | self | Specifies the sources from where you can load images. |
script-src | self unsafe-inline | Specifies the sources from where you can load and execute JavaScript. |
script-src-attr | none | Specifies the sources from where you can load inline script event handlers like onClick . |
style-src | self unsafe-inline | Specifies the sources from where you can load stylesheets. Acts as the default for style-src-attr and style-src-elem if they’re not defined. |
style-src-attr | unsafe-inline | Specifies the valid sources for inline styles applied to DOM elements in your stylesheets. |
style-src-elem | self unsafe-inline | Specifies the valid sources for style elements. |
Values: Values specify the approved origins to load resources from. Below are examples of some commonly used values. In addition to these, you can also specify URLs.
Value | Description |
---|---|
self | Allows loading and execution of resources from the same origin. |
unsafe-eval | Allows execution of code generated by eval() and other unsafe methods. |
unsafe-inline | Allows the inclusion of inline stylesheets, scripts, inline event handlers, etc. |
[$NONCE$] | Allows execution of scripts or loading of stylesheets with a specific nonce value generated by the server. |
strict-dynamic | Allows execution of scripts from trusted sources. Scripts included by loaders from a trusted script are not blocked. |
none | Blocks execution of the specified directive from all sources. |
It’s important to note that while unsafe-eval
and unsafe-inline
provide flexibility in terms of code execution and styling, they come with increased security risks.
In general, you should set your CSP headers to be as restrictive as your required sources allow to minimize the risk of possible security threats. However, Liferay currently cannot support a fully unsafe-
free CSP due to existing limitations. See Current Limitations of CSP for more information.
While strict-dynamic
simplifies CSP configuration and reduces the need for nonce propagation, it may enlarge the attack surface by allowing any script loaded by trusted scripts to execute.
Alternatively, you can send nonces from the server to the client, ensuring that dynamically loaded scripts have the necessary nonce attribute for compliance with CSP. This approach involves proprietary mechanisms, managed by Liferay, to propagate nonces from the server to the client.
This approach provides more granular control over script loading and may be preferable in scenarios where strict control over script execution is essential. However, it requires proprietary mechanisms for nonce propagation, which may be more complex.
The choice between strict-dynamic
and nonce propagation depends on factors such as the specific threat model, risk tolerance, and operational requirements. Consider the pros and cons before implementing it in your CSP.
Configuring a Sample Content Security Policy
-
Open the Global Menu () and navigate to Control Panel → Instance Settings → Security → Content Security Policy.
-
To enable CSP headers, check the Enabled checkbox. You can enter your policy in the Content Security Policy input field and specify a number of paths to exclude (see below).
-
Enter the following policy in the Content Security Policy input field.
default-src 'self'; script-src 'self' https://trusted-cdn.example.com '[$NONCE$]'; style-src 'self' https://trusted-cdn.example.com '[$NONCE$]' base-uri 'self';
This sample content security policy allows resources to load only from the same origin self
and from the trusted content delivery network https://trusted-cdn.example.com
. It also includes the nonce '[$NONCE$]'
for scripts and stylesheets to secure their integrity and prevent unauthorized script execution. The base-url 'self'
value instructs the browser to allow loading resources only from the same origin as the document.
- Click Update.
Content Security Policy: Specify the content security policy to enforce. The value entered here appears as the value for the Content-Security-Policy
HTTP header. You can add a nonce by using the placeholder '[$NONCE$]'
in your content security policy. The placeholder is replaced with a generated nonce for the tags you specify.
Excluded Paths: Paths that start with the value added here are excluded from the content security policy. You can add multiple paths to exclude by clicking the button or remove them using the button.
CSP configuration is available at all scopes. For the system scope, go to Control Panel → System Settings → Security → Content Security Policy. For the site scope, open the site menu and go to Configuration → Site Settings → Security → Content Security Policy.
Current CSP Limitations and Recommendations
CSP headers are a beta feature with these limitations:
-
Your
script-src
directive must have theunsafe-inline
value defined to support CKEditor 4. CKEditor is the only supported WYSIWYG editor. -
Your
style-src
directive must have theunsafe-inline
value, because Liferay both has inline style attributes and adds stylesheets to the<head>
tag using scripts.
In a future version of Liferay, CKEditor 5 and the removal of inline styles will address these limitations.
Content Security Policies work best with SPA disabled. To disable it, add javascript.single.page.application.enabled=false
to your portal-ext.properties file.
Site level configuration panel and common pages (such as the 404 page) belong to the instance, so they use the instance level CSP headers.
Because of these limitations, you cannot fully restrict these attributes to the (otherwise minimal) self
attribute.
However, you can split your style-src
directive into the style-src-attr
and style-src-elem
directives to further minimize risk. Then, set the style-src-elem
directive using nonce
values instead, for any style elements you need.
Using specific nonce
values for your styles, you can set these more restrictive directives like this:
style-src-attr 'unsafe-inline';
style-src-elem '[$NONCE$]';
So the most restrictive supported policy is:
script-src '[$NONCE$]';
script-src-attr 'none';
style-src-elem '[$NONCE$]';
style-src-attr 'unsafe-inline';
connect-src 'self';
img-src 'self';
frame-ancestors 'none';
frame-src 'self';
This strict configuration is recommended where possible for your site. If a page on your site does not work with your configuration (for example, because the page uses CKEditor 4), you can exclude those pages from the path by adding them under Excluded Paths.
Extra CSP Limitations Before Liferay 2025.Q1+
These extra limitations are in place for Liferay versions before 2025.Q1:
-
Your
script-src
directive must have theunsafe-eval
value defined for Liferay to properly bundle code. -
Your
script-src-attr
directive must have theunsafe-inline
value for inline event listeners within HTML elements within Liferay.