Fetch Directives - Controlling Resource Loading
Fetch Directives - Controlling Resource Loading
Fetch directives are the most commonly used CSP directives, controlling from where different types of resources can be loaded. These directives follow inheritance rules, with more specific directives overriding broader ones, and default-src
serving as the ultimate fallback.
default-src: The Master Directive
The default-src
directive serves as the default policy for all resource types that don't have their own specific directive. It's the foundation of most CSP policies and provides a catch-all security net.
Content-Security-Policy: default-src 'self' https://trusted-domain.com;
This policy restricts all resource types to the same origin and the specified trusted domain unless overridden by more specific directives:
<!-- Example showing default-src inheritance -->
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'self' https://cdn.example.com;">
<!-- These will work (allowed by default-src) -->
<script src="/js/app.js"></script>
<script src="https://cdn.example.com/library.js"></script>
<link rel="stylesheet" href="/css/style.css">
<!-- This will be blocked -->
<script src="https://untrusted.com/script.js"></script>
</head>
script-src: JavaScript Security Control
The script-src
directive is arguably the most critical for preventing XSS attacks. It controls which scripts can execute on your page, including inline scripts, external scripts, and JavaScript execution methods like eval()
.
Content-Security-Policy: script-src 'self' 'nonce-2726c7f26c' https://trusted-scripts.com;
Advanced script-src configurations:
// Using nonces for inline scripts
const generateNonce = () => {
const array = new Uint8Array(16);
crypto.getRandomValues(array);
return btoa(String.fromCharCode.apply(null, array));
};
// Express.js middleware
app.use((req, res, next) => {
res.locals.nonce = generateNonce();
res.setHeader('Content-Security-Policy',
`script-src 'self' 'nonce-${res.locals.nonce}' 'strict-dynamic';`
);
next();
});
// In your HTML template
// <script nonce="<%= nonce %>">
// console.log('This script will execute');
// </script>
Using hashes for inline scripts:
<!-- Calculate SHA-256 hash of the script content -->
<!-- Hash: sha256-RFWPLDbv2BY+rCkDzsE+0fr8ylGr2R2faWMhq4lfEQc= -->
<meta http-equiv="Content-Security-Policy"
content="script-src 'self' 'sha256-RFWPLDbv2BY+rCkDzsE+0fr8ylGr2R2faWMhq4lfEQc=';">
<script>
// This exact script content matches the hash
console.log('Hello CSP!');
</script>
style-src: Stylesheet Security
The style-src
directive controls stylesheet sources and inline styles. Like script-src
, it's essential for preventing injection attacks that use CSS.
Content-Security-Policy: style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
Implementing secure styling practices:
// Avoid unsafe-inline by using CSS classes
// Bad practice:
element.style.color = userInput; // Potential security risk
// Good practice:
element.classList.add('user-defined-color');
// Using nonces for necessary inline styles
const styleNonce = generateNonce();
res.setHeader('Content-Security-Policy',
`style-src 'self' 'nonce-${styleNonce}' https://fonts.googleapis.com;`
);
img-src: Image Source Control
The img-src
directive controls where images can be loaded from, including <img>
tags, CSS background images, and SVG <image>
elements.
Content-Security-Policy: img-src 'self' data: https://images.example.com https://*.cdn.com;
Common img-src patterns:
// Allowing different image sources
const imagePolicies = {
// Basic policy for static sites
basic: "img-src 'self' data: https:",
// E-commerce site with product images
ecommerce: "img-src 'self' https://products.cdn.com https://user-uploads.s3.amazonaws.com",
// Blog with various image sources
blog: "img-src 'self' data: https: blob:",
// Strict policy (no external images)
strict: "img-src 'self' data:"
};
connect-src: API and Data Connections
The connect-src
directive is crucial for controlling where your application can send data. It affects XMLHttpRequest, Fetch API, WebSocket connections, EventSource, and more.
Content-Security-Policy: connect-src 'self' https://api.example.com wss://realtime.example.com;
Implementing connect-src for modern applications:
// Configuration for different API endpoints
const apiEndpoints = {
internal: 'https://api.myapp.com',
analytics: 'https://analytics.provider.com',
payment: 'https://payment.gateway.com',
websocket: 'wss://realtime.myapp.com'
};
// Generate connect-src based on features
function generateConnectSrc(enabledFeatures) {
const sources = ["'self'"];
if (enabledFeatures.api) sources.push(apiEndpoints.internal);
if (enabledFeatures.analytics) sources.push(apiEndpoints.analytics);
if (enabledFeatures.payment) sources.push(apiEndpoints.payment);
if (enabledFeatures.realtime) sources.push(apiEndpoints.websocket);
return `connect-src ${sources.join(' ')}`;
}
font-src: Web Font Security
The font-src
directive controls where fonts can be loaded from, affecting @font-face
rules in CSS.
Content-Security-Policy: font-src 'self' https://fonts.gstatic.com data:;
Managing font sources securely:
/* CSS with CSP-compliant font loading */
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom.woff2') format('woff2'),
url('/fonts/custom.woff') format('woff');
/* These fonts must be from allowed sources */
}
/* Using Google Fonts with CSP */
/* Requires: font-src https://fonts.gstatic.com */
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');