Drupal Commerce Security: CSP and Payment Compliance
Content Security Policy is where PCI DSS stops being a hosting concern and becomes an application concern. What CSP has to do on a Drupal Commerce payment page, and how to configure it without breaking checkout.
Key Takeaways
- CSP is how you meet PCI DSS requirements for authorizing scripts and ensuring their integrity on payment pages.
- Use nonces for inline scripts you control, and avoid unsafe-inline and unsafe-eval unless necessary.
- Set connect-src to stop scripts exfiltrating cardholder data to untrusted servers.
- Security Kit adds nonces automatically, defines the directives, and logs violation reports.
The Content Security Policy (CSP) header is a critical component for achieving PCI DSS compliance, particularly for payment pages, as it helps meet requirements for authorizing and ensuring the integrity of scripts. In modern e-commerce environments, especially when using Drupal Commerce, implementing robust CSP rules is not just a best practice. It’s a requirement for maintaining customer trust and meeting security standards.
What is PCI DSS?
PCI DSS (Payment Card Industry Data Security Standard) is a global set of security requirements designed to ensure that all organizations handling credit card data maintain a secure environment. Version 4.0 strengthens requirements around web application security, emphasizing measures to protect against client-side attacks like cross-site scripting (XSS) and unauthorized script execution.
What is CSP?
A Content Security Policy is an HTTP response header that controls which resources (such as JavaScript, CSS, images, or fonts) a web page is allowed to load. By defining strict rules for where scripts and other assets can originate, CSP reduces the risk of malicious content execution in browsers.
Why CSP Matters for Drupal Commerce and PCI DSS?
In a Drupal Commerce site handling online payments, attackers can target checkout or payment pages with injected scripts to capture sensitive payment details. PCI DSS specifically addresses this risk, requiring site owners to: Authorize all scripts running on payment pages.
Ensure the integrity of these scripts through mechanisms like nonces or hashes. Implement policies that prevent unauthorized script execution. A properly configured CSP header ensures only trusted scripts are executed, blocking any unauthorized or tampered scripts. This directly supports PCI DSS requirements for protecting payment page integrity.
Implementing CSP in Drupal with the Security Kit Module
Drupal provides the Security Kit module, which offers a simple way to configure CSP headers directly within your site’s admin interface or via custom module code. This module supports: Adding nonces automatically to scripts. Defining CSP rules (script-src, script-src-elem, etc.). Sending violation reports to a specified endpoint.
Most Important CSP Directives for PCI DSS
script-src: (Critical for PCI DSS)
- Purpose: Controls which sources can run JavaScript on your site.
- PCI DSS relevance: Prevents malicious scripts from executing, protecting cardholder data from injection attacks.
Best practice:
Content-Security-Policy: script-src 'self' https://trusted-payments.example.com 'nonce-abc123';- Use 'nonce' for inline scripts you control.
- Avoid allowing unsafe-inline or unsafe-eval unless necessary.
- Whitelist only trusted payment providers (e.g., PayPal, Stripe, Adyen).
default-src: (Important baseline)
- Purpose: Controls which sites can embed your pages in <iframe>, <frame>, <object>, etc.
- PCI DSS relevance: Protects payment pages from being embedded into malicious overlays.
Best practice:
frame-ancestors 'self' https://trusted-partner.example.com;
frame-ancestors: (Anti-clickjacking, PCI DSS requirement)
- Purpose: Controls which sites can embed your pages in <iframe>, <frame>, <object>, etc.
- PCI DSS relevance: Protects payment pages from being embedded into malicious overlays.
Best practice:
frame-ancestors 'self' https://trusted-partner.example.com;
object-src: (Legacy attack prevention)
- Purpose: Restricts sources for <object>, <embed>, and <applet> elements.
- PCI DSS relevance: Prevents the execution of untrusted plugins, which are a high-risk vector.
Best practice:
object-src 'none';
connect-src: (Protects data transfer)
- Purpose: Controls where scripts can connect via XHR, WebSocket, EventSource.
- PCI DSS relevance: Prevents exfiltration of sensitive cardholder data to untrusted servers.
Best practice:
connect-src 'self' https://api.trusted-payments.example.com;
report-uri: (Monitoring & incident response)
- Purpose: Sends CSP violation reports to a specified endpoint.
- PCI DSS relevance: Enables detection of policy violations and possible attacks.
Best practice:
report-uri /report-csp-violation;- In Drupal, the Security Kit module can log these automatically.
Best Practices for Implementing CSP in Drupal Commerce
- Enable CSP Headers
Explanation: The CSP header should be sent with every page request, particularly on sensitive pages like checkout or payment.
Example:
Need your Drupal Commerce store PCI DSS ready? Talk to Vardot
FAQs
PCI DSS 4.0 does not name CSP by name, but it requires you to authorize every script on payment pages, ensure script integrity, and maintain an inventory of scripts (Requirements 6.4.3 and 11.6.1). A properly configured Content Security Policy header is the most practical way to meet these client-side security requirements, which is why it has become standard for compliant e-commerce sites.
Use Drupal's Security Kit (SecKit) module, which lets you configure CSP headers from the admin interface without custom code. It can add nonces to scripts automatically, define directives such as script-src and frame-ancestors, and send violation reports to an endpoint. For payment pages, apply a stricter policy that whitelists only your payment gateway and blocks object-src.
The critical directives are script-src (controls which scripts can run and protects cardholder data from injection), frame-ancestors (prevents clickjacking by controlling who can embed your page), object-src set to 'none' (blocks legacy plugin attacks), connect-src (stops data exfiltration to untrusted servers), and report-uri (logs violations for monitoring).
A nonce is a random value generated for each page request and attached to trusted inline scripts, so the browser runs only scripts carrying the correct nonce. PCI DSS requires verifying script integrity on payment pages, and nonces (or hashes) provide that assurance while letting you avoid the insecure 'unsafe-inline' setting.
A nonce authorizes specific inline scripts you control. strict-dynamic extends that trust: any script loaded by an already-trusted, nonce-carrying script is allowed to run without its own nonce. Combining 'nonce-{value}' with 'strict-dynamic' keeps payment pages secure while supporting modern scripts that load other scripts dynamically.