Skip to main content

Content Security Policy (CSP) Configuration

Content Security Policy (CSP) is a security feature that helps prevent cross-site scripting (XSS) attacks. When integrating FramePay, you need to configure your CSP to allow the necessary domains.

Overview

FramePay loads payment fields via secure iframes and requires specific CSP directives to function properly. This guide covers:

  • 🔒 Required CSP directives
  • 🌐 Allowed domains
  • ⚙️ Configuration methods
  • 🎯 Best practices

Required CSP Directives

Minimum Configuration

To use FramePay with card payments only, include these directives:

<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' 'unsafe-inline' framepay.payments.ai;
connect-src 'self' framepay.payments.ai *.payments.ai;
style-src 'self' 'unsafe-inline' framepay.payments.ai;
frame-src 'self' framepay.payments.ai;
img-src 'self' data: framepay.payments.ai;
font-src 'self';
">

Full Configuration (with Digital Wallets)

If you're using Apple Pay, Google Pay, or PayPal, add their domains:

<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' 'unsafe-inline'
framepay.payments.ai
*.paypal.com
*.google.com
*.cdn-apple.com;
connect-src 'self'
framepay.payments.ai
*.payments.ai
*.paypal.com
*.google.com
*.apple.com;
style-src 'self' 'unsafe-inline'
framepay.payments.ai
fonts.googleapis.com;
frame-src 'self'
framepay.payments.ai
*.paypal.com
*.google.com;
img-src 'self' data:
framepay.payments.ai
*.paypal.com
*.google.com;
font-src 'self'
fonts.gstatic.com;
">

Configuration Methods

Method 1: HTML Meta Tag

Add the CSP meta tag in your HTML <head> section:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' 'unsafe-inline' framepay.payments.ai *.paypal.com *.google.com *.cdn-apple.com;
connect-src 'self' framepay.payments.ai *.payments.ai *.paypal.com *.google.com;
style-src 'self' 'unsafe-inline' framepay.payments.ai fonts.googleapis.com;
frame-src 'self' framepay.payments.ai *.paypal.com *.google.com;
img-src 'self' data: framepay.payments.ai *.paypal.com *.google.com;
font-src 'self' fonts.gstatic.com;
">
<title>Checkout</title>
</head>
<body>
<!-- Your content here -->
</body>
</html>

Configure CSP via HTTP headers on your server. This is the recommended approach for production.

Node.js/Express

const express = require('express');
const app = express();

app.use((req, res, next) => {
res.setHeader(
'Content-Security-Policy',
"default-src 'self'; " +
"script-src 'self' 'unsafe-inline' framepay.payments.ai *.paypal.com *.google.com *.cdn-apple.com; " +
"connect-src 'self' framepay.payments.ai *.payments.ai *.paypal.com *.google.com; " +
"style-src 'self' 'unsafe-inline' framepay.payments.ai fonts.googleapis.com; " +
"frame-src 'self' framepay.payments.ai *.paypal.com *.google.com; " +
"img-src 'self' data: framepay.payments.ai *.paypal.com *.google.com; " +
"font-src 'self' fonts.gstatic.com;"
);
next();
});

Nginx

location / {
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' framepay.payments.ai *.paypal.com *.google.com *.cdn-apple.com; connect-src 'self' framepay.payments.ai *.payments.ai *.paypal.com *.google.com; style-src 'self' 'unsafe-inline' framepay.payments.ai fonts.googleapis.com; frame-src 'self' framepay.payments.ai *.paypal.com *.google.com; img-src 'self' data: framepay.payments.ai *.paypal.com *.google.com; font-src 'self' fonts.gstatic.com;";
}

Apache

<IfModule mod_headers.c>
Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' framepay.payments.ai *.paypal.com *.google.com *.cdn-apple.com; connect-src 'self' framepay.payments.ai *.payments.ai *.paypal.com *.google.com; style-src 'self' 'unsafe-inline' framepay.payments.ai fonts.googleapis.com; frame-src 'self' framepay.payments.ai *.paypal.com *.google.com; img-src 'self' data: framepay.payments.ai *.paypal.com *.google.com; font-src 'self' fonts.gstatic.com;"
</IfModule>

Next.js

// next.config.js
module.exports = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'Content-Security-Policy',
value: [
"default-src 'self'",
"script-src 'self' 'unsafe-inline' framepay.payments.ai *.paypal.com *.google.com *.cdn-apple.com",
"connect-src 'self' framepay.payments.ai *.payments.ai *.paypal.com *.google.com",
"style-src 'self' 'unsafe-inline' framepay.payments.ai fonts.googleapis.com",
"frame-src 'self' framepay.payments.ai *.paypal.com *.google.com",
"img-src 'self' data: framepay.payments.ai *.paypal.com *.google.com",
"font-src 'self' fonts.gstatic.com"
].join('; ')
}
]
}
]
}
}

CSP Directive Breakdown

default-src 'self'

Sets the default policy for all content types. 'self' allows content only from your own domain.

script-src

Controls which JavaScript sources are allowed:

  • 'self' - Your own domain
  • 'unsafe-inline' - Required for FramePay inline scripts
  • framepay.payments.ai - FramePay CDN
  • *.paypal.com - PayPal SDK (if using PayPal)
  • *.google.com - Google Pay SDK (if using Google Pay)
  • *.cdn-apple.com - Apple Pay SDK (if using Apple Pay)

⚠️ Security Note: 'unsafe-inline' reduces CSP protection. For production, consider using nonces for better security.

connect-src

Controls which domains can be contacted via XHR, WebSocket, or EventSource:

  • 'self' - Your own domain
  • framepay.payments.ai - FramePay API
  • *.payments.ai - Payments AI API
  • *.paypal.com - PayPal API
  • *.google.com - Google Pay API

style-src

Controls stylesheet sources:

  • 'self' - Your own stylesheets
  • 'unsafe-inline' - Required for inline styles
  • framepay.payments.ai - FramePay CSS
  • fonts.googleapis.com - Google Fonts (if used)

frame-src

Controls which sources can be loaded in iframes (crucial for FramePay):

  • 'self' - Your own domain
  • framepay.payments.ai - FramePay payment fields
  • *.paypal.com - PayPal iframe
  • *.google.com - Google Pay iframe

img-src

Controls image sources:

  • 'self' - Your own images
  • data: - Required for data URIs (card brand icons)
  • framepay.payments.ai - FramePay images
  • *.paypal.com - PayPal logos
  • *.google.com - Google Pay logos

font-src

Controls font sources:

  • 'self' - Your own fonts
  • fonts.gstatic.com - Google Fonts (if used)

Payment Method Specific Configuration

Card Payments Only

<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' 'unsafe-inline' framepay.payments.ai;
connect-src 'self' framepay.payments.ai *.payments.ai;
style-src 'self' 'unsafe-inline' framepay.payments.ai;
frame-src 'self' framepay.payments.ai;
img-src 'self' data: framepay.payments.ai;
">

Apple Pay

Add these domains for Apple Pay:

script-src: *.cdn-apple.com
connect-src: *.apple.com

Google Pay

Add these domains for Google Pay:

script-src: *.google.com
connect-src: *.google.com
frame-src: *.google.com
img-src: *.google.com

PayPal

Add these domains for PayPal:

script-src: *.paypal.com
connect-src: *.paypal.com
frame-src: *.paypal.com
img-src: *.paypal.com

Using Nonces (Production)

For better security, use nonces instead of 'unsafe-inline':

Backend (Node.js/Express)

const crypto = require('crypto');

app.use((req, res, next) => {
// Generate nonce for this request
const nonce = crypto.randomBytes(16).toString('base64');
res.locals.nonce = nonce;

res.setHeader(
'Content-Security-Policy',
`default-src 'self'; ` +
`script-src 'self' 'nonce-${nonce}' framepay.payments.ai; ` +
`style-src 'self' 'nonce-${nonce}' framepay.payments.ai;`
);
next();
});

Frontend

<!-- Use the nonce in your script tags -->
<script nonce="<%= nonce %>">
Framepay.initialize({
publishableKey: 'pk_sandbox_xxx',
// ... config
});
</script>

Testing CSP Configuration

Browser Console

Open your browser's developer console (F12) and look for CSP violations:

Refused to load the script 'https://example.com/script.js' because it 
violates the following Content Security Policy directive...

CSP Report Mode

Test your CSP without blocking resources using Content-Security-Policy-Report-Only:

<meta http-equiv="Content-Security-Policy-Report-Only" content="
default-src 'self';
script-src 'self' 'unsafe-inline' framepay.payments.ai;
report-uri /csp-violation-report-endpoint;
">

This will report violations without blocking them, allowing you to test safely.

Online Tools

Use these tools to validate your CSP:

Common Issues

Issue: FramePay not loading

Symptom: FramePay fields don't appear

Solution: Ensure script-src includes framepay.payments.ai and frame-src allows framepay.payments.ai

script-src 'self' 'unsafe-inline' framepay.payments.ai;
frame-src 'self' framepay.payments.ai;

Issue: Card brand icons not showing

Symptom: Visa, Mastercard logos don't appear

Solution: Add data: to img-src:

img-src 'self' data: framepay.payments.ai;

Issue: Wallet buttons not working

Symptom: Apple Pay/Google Pay/PayPal buttons don't respond

Solution: Add wallet provider domains to all relevant directives:

script-src 'self' 'unsafe-inline' framepay.payments.ai *.paypal.com *.google.com;
connect-src 'self' framepay.payments.ai *.payments.ai *.paypal.com *.google.com;
frame-src 'self' framepay.payments.ai *.paypal.com *.google.com;

Issue: HTTPS mixed content

Symptom: Console shows mixed content warnings

Solution: Ensure your page is served over HTTPS in production. CSP cannot fix HTTP served over HTTPS.

Best Practices

✅ Do

  • Use HTTP headers over meta tags when possible
  • Start with Content-Security-Policy-Report-Only for testing
  • Be as restrictive as possible while allowing necessary domains
  • Use nonces or hashes instead of 'unsafe-inline' in production
  • Document your CSP configuration
  • Monitor CSP violation reports

❌ Don't

  • Use 'unsafe-eval' - it's not required for FramePay
  • Allow * wildcards - they defeat the purpose of CSP
  • Forget to test on all payment methods you support
  • Mix HTTP and HTTPS content
  • Skip CSP validation in staging environments

Environment-Specific Configuration

Development

Content-Security-Policy-Report-Only: ...

Use report-only mode to identify issues without breaking functionality.

Staging

Content-Security-Policy: ...

Enforce CSP but with more permissive settings for testing.

Production

Content-Security-Policy: ... (strict configuration)

Use the strictest possible CSP with nonces and minimal wildcards.

Additional Security Headers

Consider adding these headers alongside CSP:

X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Strict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin

Resources

Next Steps