Using Next.js Security Headers

Implement Content Security Policy and essential security headers to protect your Next.js applications from XSS, clickjacking, and common web vulnerabilities.

Why Security Headers Matter for Next.js Applications

Web applications face constant security threats, from cross-site scripting (XSS) attacks to clickjacking attempts. Next.js provides powerful built-in features for implementing security headers that defend against these vulnerabilities. Security headers act as a first line of defense, instructing browsers on how to handle content and requests.

Unlike traditional web frameworks requiring external middleware for security configuration, Next.js offers native support through its middleware architecture and built-in configuration options. This integration means you can implement comprehensive security without sacrificing the developer experience or performance. When building production-ready web applications, proper security headers are essential for protecting both your users and your application infrastructure.

Key protections provided by security headers:

  • XSS prevention through Content Security Policy
  • Clickjacking protection with X-Frame-Options
  • MIME type sniffing prevention
  • HTTPS enforcement with HSTS
  • Granular browser feature control

For teams looking to understand the broader landscape of modern web development practices, exploring how Next.js integrates with other JavaScript frameworks like React provides valuable context for making informed architectural decisions.

73%

of security breaches target web applications

90%+

reduction in XSS risk with proper CSP

4.5M+

average cost of a data breach in 2025

Content Security Policy Implementation

Content Security Policy (CSP) represents the most comprehensive security header for web applications. CSP works by defining a whitelist of trusted content sources, allowing browsers to reject anything that doesn't match the defined policy. This approach dramatically reduces XSS attack surfaces.

How CSP Works

CSP communicates through the Content-Security-Policy HTTP header, which browsers parse and enforce for all page content. The policy specifies directives controlling different content types:

  • default-src: Fallback for other directives
  • script-src: JavaScript files and inline scripts
  • style-src: CSS stylesheets and inline styles
  • img-src: Image sources
  • connect-src: Fetch, XHR, and WebSocket connections
// next.config.js - Basic CSP configuration
module.exports = {
 async headers() {
 return [
 {
 source: '/:path*',
 headers: [
 {
 key: 'Content-Security-Policy',
 value: "default-src 'self'; script-src 'self' 'unsafe-inline' https://trusted-cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;"
 }
 ]
 }
 ]
 }
}

Nonce-Based CSP for Dynamic Applications

Modern applications often need dynamic CSP approaches for inline scripts. Nonce-based CSP generates a unique token for each page request, allowing inline scripts with matching nonces while blocking others. This approach is particularly valuable when integrating with third-party libraries that require inline script execution.

// middleware.ts - Nonce-based CSP
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
 const nonce = crypto.randomUUID()
 
 const response = NextResponse.next()
 response.headers.set(
 'Content-Security-Policy',
 `default-src 'self'; script-src 'self' 'nonce-${nonce}'`
 )
 
 return response
}

Understanding CSP implementation pairs well with learning about optimizing Next.js application performance, as both involve thoughtful configuration and testing practices.

Essential Security Headers

Beyond CSP, several headers provide important protections for Next.js applications.

X-Content-Type-Options

Prevents MIME-sniffing attacks where browsers misinterpret content types:

{
 key: 'X-Content-Type-Options',
 value: 'nosniff'
}

X-Frame-Options

Prevents clickjacking by controlling iframe embedding:

{
 key: 'X-Frame-Options',
 value: 'DENY' // or 'SAMEORIGIN' for same-site embedding
}

HTTP Strict Transport Security (HSTS)

Enforces HTTPS connections to prevent downgrade attacks:

{
 key: 'Strict-Transport-Security',
 value: 'max-age=31536000; includeSubDomains; preload'
}

Referrer Policy

Controls referrer information sent to other sites:

{
 key: 'Referrer-Policy',
 value: 'strict-origin-when-cross-origin'
}

Permissions Policy

Controls browser features accessible to your site:

{
 key: 'Permissions-Policy',
 value: 'camera=(), microphone=(), geolocation=()'
}

These headers form the foundation of a robust web application security strategy, working together to provide comprehensive protection against common attack vectors.

Security Headers in Next.js

XSS Prevention

Content Security Policy blocks unauthorized script execution, preventing cross-site scripting attacks.

Clickjacking Protection

X-Frame-Options prevents your pages from being embedded in malicious iframes.

HTTPS Enforcement

HSTS ensures all connections use encryption, protecting data in transit.

MIME Type Protection

X-Content-Type-Options prevents browsers from misinterpreting file types.

Granular Control

Permissions Policy limits browser features accessible to your application.

Privacy Controls

Referrer Policy manages information shared when users navigate away.

Configuring Security Headers in Next.js

Next.js provides multiple approaches for configuring security headers, suited to different requirements.

Approach 1: next.config.js Configuration

Best for static policies that don't change based on request characteristics:

// next.config.js
module.exports = {
 async headers() {
 return [
 {
 source: '/:path*',
 headers: [
 { key: 'X-Content-Type-Options', value: 'nosniff' },
 { key: 'X-Frame-Options', value: 'SAMEORIGIN' },
 { key: 'X-XSS-Protection', value: '1; mode=block' },
 {
 key: 'Content-Security-Policy',
 value: "default-src 'self'; img-src 'self' data: https:;"
 }
 ]
 },
 // Stricter policy for admin routes
 {
 source: '/admin/:path*',
 headers: [
 { key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains' }
 ]
 }
 ]
 }
}

Approach 2: Middleware Configuration

Best for dynamic policies, nonce generation, and conditional security rules:

// middleware.ts
export function middleware(request: NextRequest) {
 const response = NextResponse.next()
 
 // Apply security headers to all responses
 response.headers.set('X-Content-Type-Options', 'nosniff')
 response.headers.set('X-Frame-Options', 'DENY')
 response.headers.set('X-XSS-Protection', '1; mode=block')
 
 // Dynamic CSP based on route sensitivity
 if (request.nextUrl.pathname.startsWith('/admin')) {
 response.headers.set(
 'Strict-Transport-Security',
 'max-age=31536000; includeSubDomains; preload'
 )
 }
 
 return response
}

For teams building modern web applications, understanding how to configure these headers is as important as learning about Vue.js file-based routing or other framework-specific features--both represent fundamental architectural decisions that impact application security and maintainability.

Best Practices for Next.js Security Headers

Start with Monitoring

Use Content-Security-Policy-Report-Only to monitor violations before enforcing policies:

{
 key: 'Content-Security-Policy-Report-Only',
 value: "default-src 'self'; report-uri /api/csp-report"
}

Incremental Policy Development

  1. Start with a permissive policy in report-only mode
  2. Collect violation reports to understand actual content sources
  3. Refine policy to allow legitimate sources
  4. Transition to enforcing mode when stable
  5. Set up continuous monitoring for new violations

Testing Strategies

  • Test CSP with Browser DevTools (Console shows violations)
  • Use report-only mode before enforcing
  • Test across multiple browsers (behavior varies)
  • Monitor production for unexpected violations
  • Include security headers in CI/CD testing

Common Pitfalls to Avoid

  • Overly restrictive policies: Break functionality and frustrate users
  • Missing 'self' directive: Block your own scripts and styles
  • Inconsistent enforcement: Apply policies selectively based on routes
  • No monitoring: Blind to violations and potential attacks
  • Forgetting report-uri: Lose visibility into CSP effectiveness

Production Checklist

  • CSP configured with appropriate directives
  • X-Content-Type-Options set to 'nosniff'
  • X-Frame-Options configured
  • HSTS enabled with reasonable max-age
  • Referrer-Policy set appropriately
  • Permissions-Policy for unused browser features
  • Monitoring set up for CSP violations
  • Documentation of security header configuration
  • Regular review and updates as application evolves

Security header best practices align closely with broader React development patterns and modern JavaScript practices--both require thoughtful configuration and ongoing attention to maintain quality over time.

Frequently Asked Questions

Secure Your Next.js Application

Need help implementing comprehensive security headers or auditing your application's security posture? Our team can help you build robust, secure applications.