We use cookies to make your viewing experience better. By accepting you consent, you agree to our Cookie policy

Accept
Improve your Craft CMS skills

How To Set Your Content Security Policy In Craft CMS

10 min read
Shape April 2022 HR 189

Web security threats are growing exponentially. Cross-site scripting (XSS), data injection and other attacks put Craft CMS sites at serious risk. This article highlights how implementing robust Content Security Policies (CSP) provides enhanced protection against these threats by restricting resource loading to trusted sources only. Read on to explore how Craft’s native CSP module enables precise control over your site’s attack surface with configurable directives, reporting tools, and advanced techniques tailored specifically for Craft’s architecture.

Enable Craft's native CSP module in Settings → General. Customize allowed sources in config/csp.php directives. Set to report-only mode initially. Analyze violations, then enforce by removing "Report-Only" in header. Monitor errors, tweak directives incrementally to balance security and functionality for your specific site.

Understanding Content Security Policies

What are Content Security Policies?

Content Security Policies (CSPs) are an added layer of security that help mitigate cross-site scripting (XSS) and data injection attacks. The primary purpose of CSPs is to whitelist sources of content that a web page can load resources from, blocking anything not on the approved list.

At a high level, CSPs allow web developers to create a whitelist of domains, IP addresses, and content delivery networks that are permitted to load resources like JavaScript, CSS, images, and more on a web page. Any resources that are requested from sources not on the whitelist will simply not load. This prevents the website from accidentally executing malicious scripts injected into the page by an attacker.

A Content Security Policy is an HTTP header that tells the browser exactly where approved content can be loaded from. Everything else is blocked. This allows precise control over what is allowed to load and execute, locking down the website against code injection attacks.

Some key concepts and terminology around CSPs include:

  • Directives - These define the content sources that are allowed for different resource types like scripts, styles, images, etc.

  • Whitelist - The list of trusted source origins that directives point to.

  • Report-only mode - CSPs can run in a report-only mode which monitors violations but doesn't enforce the policy.

  • Policy - The collection of directives that make up the CSP. Typically set as an HTTP header.

By locking down the origins that browsers can load resources from, CSP serves as an important defence against XSS by preventing untrusted sources from injecting unapproved scripts into a page. Even if an attacker can insert JavaScript, the CSP will block its execution.


How CSPs Work in Craft CMS

Craft CMS has native support for Content Security Policies through its CSP module. This provides an easy way to configure and enable a strict CSP for a Craft site.

By default, the CSP module sets up a policy with fairly restrictive directives that aim to block unsafe inline scripts and styles while allowing the core functionality of Craft to work properly.

Some key defaults include:

  • Blocking 'unsafe-inline' which prevents inline JavaScript and CSS.

  • Allowing 'self', 'data:' and 'blob:' sources to permit Craft UI functionality.

  • Allowing 'unsafe-eval' for front-end Vue components.

  • Setting a hash-based script directive to only allow specific Craft core JS files.

The policy is enabled by default in report-only mode on fresh Craft installs. This allows any violations to be monitored before fully enforcing the policy.

To customise the policy, developers can tweak the directives within the module’s config file. Additional source origins can be added to directives like script-src, style-src, img-src etc to expand what's allowed.

The Craft docs provide details on adapting directives to whitelist specific domains, enable unsafe-inline for styles, add nonces, and more. So the module is very flexible.

Overall, the native CSP support makes properly configuring and hardening security in Craft CMS simple and straightforward. The strict default policy and ability to tweak directives is a big benefit.


CSP Security Benefits

Using Content Security Policies provides some important security and privacy advantages beyond just mitigating XSS attacks.

Firstly, CSP helps prevent sensitive data exfiltration by restricting what domains resources can be loaded from. Attackers often use injected scripts to send data cross-domain. But directives like connect-src thwart this.

CSP also defends against clickjacking by allowing sites to require frame ancestors to be from the same origin. This forbids a page from being iframed by untrusted sites.

Another benefit is preventing browser fingerprinting - where scripts collect info to track users. The strict blocking of unsafe inline scripts shuts this down.

Signed exchanges, mixed content, unsanctioned protocols, and other advanced threats are also mitigated by CSP directives. For example, policies can block loading resources over unprotected HTTP or non-web protocols like tel:, ftp: etc.

CSP can also help defend against Spectre-type vulnerabilities by enabling browsers to only allow scripts from trusted sources to compile. Untrusted code is blocked from compiling.

Content Security Policies provide many advantages beyond XSS protection, including:

  • Blocking sensitive data exfiltration

  • Mitigating clickjacking attacks

  • Preventing browser fingerprinting

  • Forbidding unsafe URL schemes

  • Defending against Spectre-type attacks

The extensive control over resource loading afforded by CSP delivers wide-ranging security and privacy benefits to sites. Craft CMS sites can leverage these protections using the built-in module.

Configuring CSP in Craft CMS

Enabling & Initial Setup

To enable and configure Content Security Policies in Craft CMS, first go to Settings → General and check the “Enable CSP support” box. This will activate the native CSP module and apply the default policy.

The default directives aim to balance security and functionality for a fresh Craft site. To view and customise the policy, go to config/csp.php.

Some key initial steps when setting up CSP include:

  • Start in report-only mode - This logs violations without blocking content so you can monitor issues before fully enforcing the policy.

  • Allow critical domains - Add any external APIs, CDNs or servers that provide templates, JS, CSS, images etc to the appropriate directives like script-src, style-src.

  • Adjust script hashes - The script-src directive allows specific script files through a hash whitelist. Update this list to include any custom JS files.

  • Add plugin domains - Review installed plugins and whitelist any external domains they might load resources from.

  • Allow inline styles - If any inline styles are required, add 'unsafe-inline' to the style-src directive.

  • Set report endpoints - Configure the reporting section to send violation reports to your dashboard or log files.

It's recommended to take a gradual approach when enabling CSP. Turn on reporting first and analyze any violations before setting the header to active. This ensures the policy blocks only harmful content while allowing the site to function.

Some other tips include:

  • Use nonces for inline scripts - Nonces allow specific inline scripts to execute without 'unsafe-inline'.

  • Limit directives like 'self' - Avoid wide open directives and be as restrictive as possible for security.

  • Enable Strict Dynamic for scripts - This ensures only specifically allowed scripts can execute.

Overall the key is balancing security with functionality. Craft's CSP defaults provide a solid starting point that can be tightened down over time.


Logging & Reporting

To monitor Content Security Policy violations in Craft, the CSP module provides both frontend and backend logging options.

Frontend violation reporting sends details about blocked requests directly to your browser console or server logs. This is enabled in config/csp.php:

'report-uri' => [

'endpoint' => '/csp-report',

'logs' => 'storage/logs/csp-report.log',

],

The 'endpoint' specifies a URL to send JSON report data to via POST. The 'logs' option writes violation details to a log file.

For dashboard visibility, the CSP Report plugin is recommended. It surfaces violation details right within Craft's UI. The reports show the directive, blocked URL, document URL and more.

Some key benefits of CSP violation reporting:

  • Identifies unintended script or resource loading issues

  • Helps debug policy configuration problems

  • Logs attack attempts for security analysis

  • Provides visibility into policy effectiveness

To analyze reports:

  • Review to distinguish malicious vs legitimate violations

  • Tighten directives to reduce false positives

  • Whitelist additional domains/scripts as needed

  • Watch for any attack patterns in the logs

Enabling reporting is critical when rolling out CSP. Continuously monitoring violations allows policies to be iterated on over time to achieve maximum security.


Directive Optimization

Optimizing the Content Security Policy directives is an iterative process of balancing security with functionality. Here are some tips for tightening directives while avoiding site breakage:

Script Directives

  • Remove 'unsafe-inline' once nonces are setup for any required inline scripts.

  • Limit 'self' and 'unsafe-eval' to reduce the scripts allowed to execute.

  • Enable 'strict-dynamic' so only specifically allowed scripts can run.

  • Narrow the script-src hosts to the minimum required.

Style Directives

  • Remove 'unsafe-inline' and use nonces for necessary inline CSS.

  • Avoid allowing 'unsafe-eval' which enables insecure dynamic CSS generation.

  • Restrict style-src origins to only what's absolutely necessary.

Resource Directives

  • Lock down image-src, media-src, object-src etc to minimal required sources.

  • Set connect-src to restrict outgoing requests to only allowed destinations.

  • Forbid unsafe URL schemes like 'ftp:', 'tel:' in default-src.

An iterative approach is recommended, tightening directives incrementally and monitoring for issues. Some trial and error may be required to find the right balance.

The goal is minimizing attack surface while maintaining functionality. Craft's granular policy configuration allows directives to be tuned over time to optimize security and block more threats.

Whitelisting Trusted Sources

Allowing Domains & Hosts

To whitelist permitted sources in a Content Security Policy, you can specify valid domains, hosts, or 'self' directly in directives like script-src and style-src.

For example, to allow scripts or styles from a CDN:

Copy code

script-src 'self' cdn.example.com;

style-src 'self' cdn.example.com;

To allow multiple subdomains:

script-src 'self' *.trustedscripts.com;

Using wildcards e.g. *.domain.com allows all subdomains.

To whitelist a specific external host:

script-src 'self' assets.example.com;

And to allow the current origin only:

script-src 'self';

When adding sources, be as restrictive as possible for security. Avoid wide open directives like *.com which allow any subdomain.


It's also recommended to separate directives, e.g.:

script-src 'self' js.example.com

script-src 'self' apis.example.com

This increases granularity in whitelisting origins.

Overall, only add the minimum domains and hosts required for site functionality. Every whitelisted source expands the attack surface. Audit directives regularly to tighten policies.

Inline Script Strategies

To safely enable inline scripts, CSP provides two options - nonces and hashes.

Nonces are random tokens generated on the server and injected into inline scripts. For example:

<script nonce=RANDOM-TOKEN>

//script

</script>

The token acts as a whitelist allowing that specific script to execute.


Hashes involve generating a checksum of the inline script and whitelisting it in the policy:

script-src 'sha256-SCRIPT-HASH'

Nonces

Pros:

  • Specific scripts allowed

  • Rotated frequently

Cons:

  • Added complexity on server

  • Script changes break nonce

Hashes

Pros:

  • Simpler to implement

  • Changes don't break whitelisting

Cons:

  • Not as targeted as nonces

  • Security risks if compromised

In general, nonces provide better security for dynamic scripts. Hashes work for static code like templates.

Handling CDNs & External Libraries

When including popular JS libraries from CDNs, take steps to maintain security:

  • Subresource Integrity (SRI) checks - Add SRI hashes to verify file integrity. Mitigates compromised CDNs.

  • Specify precise file versions - Don't rely on wildcard hosts like *.googleapis.com. Allow just the JS file needed.

  • Use nonces - Even with SRI, additional protections help. Nonces whitelist specific script inclusions only.

For example, safely allow jQuery from Google CDN:

<script

nonce=RANDOMTOKEN

src=""

integrity="SRI-HASH"

></script>

This specifies the version precisely, adds SRI for tamperproofing, and a nonce to allow only this script.


Similarly for popular CSS libraries:

<link

rel="stylesheet"

href=""

integrity="SRI-HASH"

nonce=RANDOMTOKEN>

Follow this pattern for any external resources. Whitelist specific files only after verifying integrity. Use short-lived nonces for runtime allowance.

This balances security while enabling the use of common external libraries - a best practice approach for CSP policies.

CSP Testing & Debugging

Report-Only Mode

Before fully enforcing a Content Security Policy, it's critical to test it in report-only mode first.

Report-only mode logs all violations but doesn't block content. This allows you to identify issues with directives before going live.

To enable report-only mode in Craft:

  1. Set the 'reportOnly' config to true.

  2. Specify 'report-uri' logging endpoints.

  3. Review violation reports.

  4. Refine directives to fix violations.

  5. Switch 'reportOnly' to false when ready.

Some key things to analyze in violation reports:

  • Skim for any critical JS/CSS that's blocked. These likely need whitelisting.

  • Review if violations match expected policy issues vs suspicious activity.

  • Identify unnecessary 'self' or 'unsafe-inline' usage to tighten.

  • Check if external domain usage matches expectations or if rogue content is loading.

  • Watch for any mixed content issues.

Iteratively tweaking directives during the report-only stage helps build a robust policy that avoids site breakage. Be sure to test all site functionality before enforcing.

Aim to eliminate as many violations as possible, only keeping what's essential for the site to work. This results in maximal security from the CSP.

Enforcing Policies

Once a CSP policy is refined in report-only mode, you can enforce it by:

  1. Setting 'reportOnly' to false in the config.

  2. Removing any 'Report-Only' prefix on the header.

  3. Deploying the changes live.

The policy will now block any violations from loading content.

It's recommended to closely monitor the site after going live. Log any errors and be prepared to quickly fix directives if needed.

Some tips:

  • Have a rollback plan ready in case of breakage.

  • Temporarily use nonces for urgent inline scripts.

  • Add specific file hashes for broken JS/CSS.

  • Check reports for any new violations appearing.

Take an incremental approach to enforcement. Consider enabling protection for specific directives first, rather than the entire policy.

Handling errors gracefully is key for a smooth CSP activation. Leverage short-term workarounds while iteratively hardening directives.

Troubleshooting Issues

Debugging CSP issues involves using browser dev tools and reviewing violation reports:

Inspect Errors

  • Check the console for any CSP-related errors.

  • Inspect network requests blocked by the policy.

  • Identify the problematic directives.

Diagnose Mixed Content

  • Load pages over HTTPS to identify mixed resources.

  • Update directives like connect-src to allow secure origins only.

Review Reports

  • Analyze patterns in violation sources and directives triggering issues.

  • Add to whitelists or tighten directives accordingly.

Enable Logging

  • Use the report-uri endpoint to log verbose violation data.

  • Search logs for request details like URLs and user agents.

Test in Staging

  • Recreate issues in a staging environment for debugging.

  • Confirm fixes work before deploying to production.

Temporarily Roll Back

  • Disable enforcement if needed by setting reportOnly temporarily.

  • Analyze cause of errors and refine directives.

Combining inspection of errors and violation reports allows systematic debugging of CSP issues. An iterative approach helps build a robust policy that maximizes security and functionality.

Advanced CSP Techniques

HTTP Headers

While Craft's CSP module configures policies in system settings, you can also deliver them directly via HTTP headers for more control.

To set the CSP header in Craft:

  1. Create a middleware class

  2. Add logic to attach the header


For example:


public function handle($request, $next) {


$response = $next($request);

$response->headers->set(

'Content-Security-Policy',

"script-src 'self'; object-src 'none';"

);


return $response;


}

This provides greater flexibility than Craft's settings:

  • Set policies for specific sections or templates only

  • Vary directives based on user, context etc

  • Integrate with security services to inject dynamic headers

  • Avoid caching issues with changing settings

The main downside is added complexity vs using the system settings.

Header syntax is the same, just as a string value. Separate directives with ';' and enforce with 'Content-Security-Policy'. Use 'Content-Security-Policy-Report-Only' for report mode.

Nonce Management

To improve CSP nonce security:

  • Set short expiration times - Nonces should be single-use only. Don't persist across requests.

  • Generate with secure random values - Use Craft's StringHelper::UUID() or openssl for high entropy.

  • Limit number of valid nonces - Store a small allowlist vs infinite reuse.

  • Bind nonces to user context - Ensure stolen nonces can't execute in other users' contexts.

  • Revoke issued nonces after use - Delete from allowlist once the script executes.

  • Rotate nonce secrets regularly - Change the random seed to invalidate stolen nonces.

Proper nonce hygiene limits the attack surface. Follow these best practices to prevent nonce replay and abuse.

Transitioning Legacy Inline Code

For sites with existing inline scripts and styles, take a gradual approach to deprecating 'unsafe-inline':

  1. Inventory usage - Document all inline code instances across templates and assets.

  2. Prioritize moving scripts to external files - Replace inline JS with <script src=""> tags to the greatest extent possible.

  3. Use nonces or hashes temporarily - Whitelist necessary inline code during transition period.

  4. Monitor violations - Analyze reports for unsafe inline usage to remove.

  5. Set timeline for removal - Plan to fully replace or remove all inline code within 6-12 months.

  6. Remove 'unsafe-inline' directives - Once code is externalized or whitelisted, disable inline executes.

An incremental strategy prevents business disruption while working towards an ideal fully-external CSP.

Transitioning large codebases requires planning, resources, and an iterative approach over time. But the end result is greatly improved security and quality.

Comparison to Other Security Headers

While Content Security Policy provides powerful protection against cross-site scripting, cross-site request forgery, and data injection attacks, it's most effective when combined with other defensive HTTP headers as part of a defense-in-depth strategy.

CSP + HSTS

Using CSP in conjunction with HTTP Strict Transport Security (HSTS) headers offers comprehensive security for Craft sites.

HSTS forces browsers to only interact with the site over HTTPS, preventing downgrade attacks to HTTP and securing the connection.

CSP locks down the resources that can be loaded once connected over HTTPS.

Together, these two headers ensure:

  • Encrypted transport via HTTPS

  • Permitted content loading from trusted sources

This layered approach eliminates entire classes of vulnerabilities.

CSP + X-XSS-Protection

The X-XSS-Protection header is now deprecated in modern browsers. However, it's still useful to include it as a secondary defense in older clients.

This header enables browsers' built-in reflective XSS protections - an added mechanism beyond CSP to block attacks.

Using X-XSS-Protection along with a strict CSP policy provides redundancy:

  • CSP prevents untrusted code from executing

  • X-XSS filters catch any CSP misses

CSP Limitations

While extremely powerful, CSP is not a silver bullet. There are some limitations to be aware of:

  • Doesn't fix underlying code vulnerabilities

  • Bypass techniques like DOM clobbering exist

  • Complex configs can lead to mistakes

  • Potential for business logic disruption

Proper CSP deployment requires rigorous security hygiene - regular testing, monitoring, patching and upgrades.

When combined with other headers like HSTS and X-XSS-Protection, Content Security Policy significantly raises the bar for attackers by requiring multiple bypasses to exploit a site.

But defense in layers is still necessary due to the sophistication of modern threats.

Shape April 2022 HR 202
Andy Golpys
- Author

Andy has scaled multiple businesses and is a big believer in Craft CMS as a tool that benefits both Designer, Developer and Client. 

Share
Feedback
Show us some love
Email Us
We usually reply within 72 hours
Agency Directory
Submit your agency
Affiliate Partners
Let's chat