Implementing CSP and Subresource Integrity for Unbreakable Frontend Security in 2025
In today's rapidly evolving web security landscape, traditional security measures are no longer sufficient to protect against sophisticated attacks. Content Security Policy (CSP) and Subresource Integrity (SRI) have emerged as critical front-line defenses against XSS, code injection, and supply chain attacks. This comprehensive guide will walk you through implementing these powerful security headers and integrity checks to create an virtually unbreakable frontend security posture for your web applications in 2025.
🚀 Why CSP and SRI Matter in 2025
With the increasing sophistication of cyber attacks and the growing reliance on third-party dependencies, frontend security has become paramount. Content Security Policy acts as a whitelist mechanism that controls which resources can be loaded and executed, while Subresource Integrity ensures that externally loaded resources haven't been tampered with.
According to recent security reports, XSS attacks account for approximately 40% of all web application vulnerabilities, while supply chain attacks have increased by 300% since 2020. Implementing CSP and SRI can mitigate up to 90% of these attack vectors.
- Prevent XSS Attacks: CSP blocks unauthorized script execution
- Stop Data Exfiltration: Control which domains can receive data
- Mitigate Supply Chain Risks: SRI verifies third-party code integrity
- Compliance Requirements: Meet GDPR, PCI-DSS, and other regulatory standards
- Performance Benefits: Block malicious resource loading that slows down your site
🔧 Understanding Content Security Policy (CSP)
Content Security Policy is a security standard that helps prevent cross-site scripting (XSS), clickjacking, and other code injection attacks. It works by allowing you to create a whitelist of trusted content sources, blocking everything else by default.
The CSP header specifies which domains are approved for executing scripts, loading images, fonts, stylesheets, and other resources. When a browser encounters a CSP header, it will only execute or render resources from those specified sources.
💻 Basic CSP Implementation Example
<!-- Example CSP Header Implementation -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' https://trusted-cdn.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self';
object-src 'none';
base-uri 'self';">
<!-- Equivalent HTTP Header -->
Content-Security-Policy: default-src 'self';
script-src 'self' https://trusted-cdn.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self';
object-src 'none';
base-uri 'self';
🛡️ Advanced CSP Directives for 2025
Modern CSP implementations include several advanced directives that provide enhanced security. Here are the most critical ones you should implement:
- frame-ancestors: Prevents clickjacking by controlling which sites can embed your content
- form-action: Restricts where forms can submit data
- upgrade-insecure-requests: Automatically upgrades HTTP to HTTPS
- block-all-mixed-content: Prevents loading mixed HTTP/HTTPS content
- require-trusted-types-for: Enforces Trusted Types for DOM XSS prevention
💻 Advanced CSP Configuration
// Advanced CSP with reporting and modern directives
const advancedCSP = `
default-src 'self';
script-src 'self' 'wasm-unsafe-eval' 'strict-dynamic'
https: 'nonce-${generateNonce()}';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.yourapp.com;
frame-src 'none';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requests;
block-all-mixed-content;
require-trusted-types-for 'script';
`.replace(/\n/g, ' ').trim();
// Function to generate cryptographic nonce
function generateNonce() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return btoa(String.fromCharCode(...array));
}
🔍 Implementing Subresource Integrity (SRI)
Subresource Integrity is a security feature that enables browsers to verify that resources they fetch are delivered without unexpected manipulation. It works by comparing the cryptographic hash of the fetched resource against a known expected hash.
SRI is particularly important for CDN-hosted resources where the risk of supply chain attacks is high. If the hash doesn't match, the browser will refuse to execute or apply the resource.
💻 SRI Implementation Examples
<!-- SRI for JavaScript -->
<script
src="https://cdn.example.com/jquery-3.6.0.min.js"
integrity="sha384-vtXRMe3mGCbOeY7l30aIg8H9p3GdeSe4IFlP6G8JMa7o7lXvnz3GFKzPxzJdPfGK"
crossorigin="anonymous">
</script>
<!-- SRI for CSS -->
<link
rel="stylesheet"
href="https://cdn.example.com/bootstrap-5.1.3.css"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
crossorigin="anonymous">
<!-- Generating SRI hashes with Node.js -->
const crypto = require('crypto');
const fs = require('fs');
function generateIntegrityHash(filePath) {
const fileContent = fs.readFileSync(filePath);
const hash = crypto.createHash('sha384');
hash.update(fileContent);
return `sha384-${hash.digest('base64')}`;
}
console.log(generateIntegrityHash('./jquery-3.6.0.min.js'));
⚡ Real-World Implementation Strategy
Implementing CSP and SRI requires careful planning to avoid breaking your application. Follow this phased approach:
- Audit Current Resources: Map all external dependencies and internal scripts
- Start with Report-Only Mode: Use Content-Security-Policy-Report-Only to test policies
- Generate SRI Hashes: Create integrity hashes for all third-party resources
- Implement Gradually: Start with the most critical directives and expand coverage
- Monitor and Iterate: Use reporting endpoints to catch policy violations
💻 Complete Security Headers Configuration
// Express.js security headers middleware
const helmet = require('helmet');
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: [
"'self'",
"'strict-dynamic'",
"https://cdn.yourapp.com"
],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
fontSrc: ["'self'", "https://fonts.gstatic.com"],
connectSrc: ["'self'", "https://api.yourapp.com"],
frameSrc: ["'none'"],
objectSrc: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"],
upgradeInsecureRequests: [],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
},
referrerPolicy: { policy: "strict-origin-when-cross-origin" }
}));
// Nginx configuration for security headers
server {
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://trusted-cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;";
add_header X-Frame-Options "DENY";
add_header X-Content-Type-Options "nosniff";
add_header Referrer-Policy "strict-origin-when-cross-origin";
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()";
}
🔧 Automated SRI Hash Generation
Manually generating SRI hashes can be tedious. Here's how to automate the process in your build pipeline:
💻 Webpack Plugin for SRI Automation
// webpack.config.js with SRI support
const { SubresourceIntegrityPlugin } = require('webpack-subresource-integrity');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: '[name].[contenthash].js',
crossOriginLoading: 'anonymous'
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: true
}),
new SubresourceIntegrityPlugin({
hashFuncNames: ['sha384'],
enabled: process.env.NODE_ENV === 'production'
})
]
};
// Custom SRI script for non-Webpack setups
const fs = require('fs');
const crypto = require('crypto');
const cheerio = require('cheerio');
function addSRItoHTML(htmlPath) {
const html = fs.readFileSync(htmlPath, 'utf8');
const $ = cheerio.load(html);
$('script[src]').each((i, elem) => {
const src = $(elem).attr('src');
if (src.startsWith('http')) {
// In real implementation, you'd fetch and hash the resource
const integrity = generateRemoteIntegrity(src);
$(elem).attr('integrity', integrity);
$(elem).attr('crossorigin', 'anonymous');
}
});
fs.writeFileSync(htmlPath, $.html());
}
function generateRemoteIntegrity(url) {
// Implementation for fetching and hashing remote resources
// This is a simplified example
return 'sha384-generated-hash-here';
}
📊 Monitoring and Reporting
Effective CSP implementation requires continuous monitoring. Set up reporting endpoints to catch policy violations and potential attacks:
💻 CSP Reporting Endpoint
// Express.js CSP report endpoint
app.post('/csp-report', express.json({type: 'application/csp-report'}), (req, res) => {
const report = req.body['csp-report'];
// Log violation for monitoring
console.warn('CSP Violation:', {
violatedDirective: report['violated-directive'],
blockedURI: report['blocked-uri'],
originalPolicy: report['original-policy'],
referrer: report['referrer'],
userAgent: req.get('User-Agent'),
timestamp: new Date().toISOString()
});
// Send to security monitoring service
sendToSecurityDashboard(report);
res.status(204).end();
});
// CSP header with reporting
const cspWithReporting = `
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
report-uri /csp-report;
report-to csp-endpoint;
`.trim();
// Report-To header for newer browsers
const reportToHeader = {
group: 'csp-endpoint',
max_age: 10886400,
endpoints: [{ url: '/csp-report' }],
include_subdomains: true
};
⚡ Key Takeaways
- Start with Report-Only: Always test CSP policies in report-only mode before enforcement
- Use Nonces and Hashes: Prefer nonces over 'unsafe-inline' for inline scripts
- Automate SRI: Integrate SRI generation into your build process
- Monitor Violations: Set up proper logging and alerting for CSP violations
- Combine with Other Headers: Use CSP alongside other security headers for defense in depth
- Regular Updates: Continuously review and update your policies as your application evolves
❓ Frequently Asked Questions
- What's the difference between CSP Level 2 and Level 3?
- CSP Level 3 introduces several new directives including 'strict-dynamic', which allows trusted scripts to load additional scripts, and Trusted Types for DOM XSS prevention. It also improves the 'report-to' directive for better reporting capabilities.
- Can CSP break my existing web application?
- Yes, if implemented incorrectly. Always start with Content-Security-Policy-Report-Only mode to identify potential issues without blocking resources. Gradually tighten policies while monitoring for violations.
- How do I handle dynamic content with CSP?
- Use nonces or hashes for inline scripts and styles. For highly dynamic applications, consider using 'strict-dynamic' in combination with nonces, which allows trusted scripts to load additional scripts dynamically.
- What hash algorithms are supported for SRI?
- Browsers support SHA-256, SHA-384, and SHA-512. SHA-384 is recommended as it provides a good balance between security and performance. Multiple hashes can be specified for fallback support.
- How does SRI affect performance?
- SRI adds minimal performance overhead as the hash verification happens after resource download. The primary impact is that resources with invalid hashes won't execute, potentially breaking functionality until the issue is resolved.
💬 Found this article helpful? Have you implemented CSP and SRI in your projects? Share your experiences or ask questions in the comments below! Don't forget to share this guide with your team to help improve web security across your organization.
About LK-TECH Academy — Practical tutorials & explainers on software engineering, AI, and infrastructure. Follow for concise, hands-on guides like our recent post on Modern Web Security Headers and AI-Powered Security Automation.

No comments:
Post a Comment