How to Configure Content Security Policy Headers
Content Security Policy (CSP) is a security header that helps prevent cross-site scripting (XSS), clickjacking, and other code injection attacks by controlling which resources a browser is allowed to load. Properly configuring CSP on your Breeze instance's web applications is one of the most effective client-side security measures available.
Understanding CSP Directives
CSP uses directives to control different types of resources:
default-src— fallback for all resource types not explicitly specifiedscript-src— controls JavaScript sourcesstyle-src— controls CSS sourcesimg-src— controls image sourcesfont-src— controls web font sourcesconnect-src— controls fetch, XHR, and WebSocket connectionsframe-src— controls iframe sourcesobject-src— controls plugins like Flash (should always be'none')base-uri— restricts the base element URLform-action— restricts form submission targetsframe-ancestors— controls which sites can embed your page (replaces X-Frame-Options)
Basic CSP Configuration in Nginx
server {
listen 443 ssl;
server_name yourdomain.com;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; frame-ancestors 'self'; base-uri 'self'; form-action 'self';" always;
# ... rest of config
}
Basic CSP Configuration in Apache
<VirtualHost *:443>
ServerName yourdomain.com
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; frame-ancestors 'self'; base-uri 'self'; form-action 'self';"
# ... rest of config
</VirtualHost>
Setting CSP in PHP
You can also set CSP headers directly in your PHP application:
<?php
header("Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self'; object-src 'none'; frame-ancestors 'self'; base-uri 'self'; form-action 'self';");
Using Report-Only Mode
Test your CSP without blocking resources by using Content-Security-Policy-Report-Only:
add_header Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self'; report-uri /csp-report;" always;
Create an endpoint to collect violation reports:
<?php
// /csp-report.php
$data = file_get_contents('php://input');
$report = json_decode($data, true);
if ($report) {
$logEntry = date('Y-m-d H:i:s') . ' ' . json_encode($report) . "\n";
file_put_contents('/var/log/csp-reports.log', $logEntry, FILE_APPEND);
}
http_response_code(204);
Handling Inline Scripts and Styles
Instead of using 'unsafe-inline', use nonces or hashes for better security:
Nonce-Based Approach
<?php
$nonce = base64_encode(random_bytes(16));
header("Content-Security-Policy: script-src 'nonce-{$nonce}'; style-src 'nonce-{$nonce}';");
?>
<script nonce="<?= $nonce ?>">
// This inline script is allowed because the nonce matches
console.log('Allowed by CSP');
</script>
Hash-Based Approach
# Generate the hash of your inline script
echo -n "console.log('hello');" | openssl dgst -sha256 -binary | openssl enc -base64
# Use the hash in your CSP header
Content-Security-Policy: script-src 'sha256-AbCdEf123...=';
Complete Production CSP Example
A real-world CSP for a web application on your Breeze instance:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{random}' https://cdn.jsdelivr.net;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.yourdomain.com wss://yourdomain.com;
media-src 'self';
object-src 'none';
child-src 'self';
frame-ancestors 'self';
base-uri 'self';
form-action 'self';
upgrade-insecure-requests;
Additional Security Headers
CSP works best alongside other security headers:
# Prevent MIME type sniffing
add_header X-Content-Type-Options "nosniff" always;
# Enable XSS filter
add_header X-XSS-Protection "1; mode=block" always;
# Control referrer information
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Restrict browser features
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# Force HTTPS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Best Practices
- Start with report-only mode — deploy CSP in report-only first to identify what will break
- Avoid unsafe-inline and unsafe-eval — use nonces or hashes instead for inline code
- Be as restrictive as possible — only allow the sources your application actually needs
- Monitor violation reports — review reports to detect both policy issues and potential attacks
- Update policies when adding third-party resources — each new CDN or API endpoint needs explicit allowlisting
A well-configured Content Security Policy is a powerful defense against XSS and injection attacks on web applications running on your Breeze instance, significantly reducing the risk of client-side exploitation.