#1 Data Analytics Program in India
₹2,499₹1,499Enroll Now
11 min read
•Question 38 of 47hard

Next.js Security Best Practices

Implementing security measures in Next.js.

Security Best Practices

Content Security Policy

code.txtTSX
// middleware.ts
import { NextResponse } from 'next/server';

export function middleware(request) {
  const nonce = Buffer.from(crypto.randomUUID()).toString('base64');

  const cspHeader = `
    default-src 'self';
    script-src 'self' 'nonce-${nonce}' 'strict-dynamic';
    style-src 'self' 'nonce-${nonce}';
    img-src 'self' blob: data:;
    font-src 'self';
    connect-src 'self';
    frame-ancestors 'none';
  `.replace(/\s{2,}/g, ' ').trim();

  const response = NextResponse.next();
  response.headers.set('Content-Security-Policy', cspHeader);
  response.headers.set('x-nonce', nonce);

  return response;
}

CSRF Protection

code.txtTSX
// Server Action with CSRF check
'use server';

import { cookies, headers } from 'next/headers';

export async function updateProfile(formData: FormData) {
  const origin = headers().get('origin');
  const host = headers().get('host');

  // Verify same origin
  if (origin !== `https://${host}`) {
    throw new Error('Invalid origin');
  }

  // Verify CSRF token
  const token = formData.get('csrf');
  const storedToken = cookies().get('csrf')?.value;

  if (token !== storedToken) {
    throw new Error('Invalid CSRF token');
  }

  // Proceed with update
}

Input Sanitization

code.txtTSX
import DOMPurify from 'isomorphic-dompurify';

// Sanitize user HTML input
function SafeHTML({ html }: { html: string }) {
  const clean = DOMPurify.sanitize(html, {
    ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p'],
    ALLOWED_ATTR: ['href'],
  });

  return <div dangerouslySetInnerHTML={{ __html: clean }} />;
}

Security Headers

code.txtTSX
// next.config.js
const securityHeaders = [
  { key: 'X-DNS-Prefetch-Control', value: 'on' },
  { key: 'X-Frame-Options', value: 'DENY' },
  { key: 'X-Content-Type-Options', value: 'nosniff' },
  { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
  { key: 'Permissions-Policy', value: 'camera=(), microphone=()' },
];

module.exports = {
  async headers() {
    return [{ source: '/:path*', headers: securityHeaders }];
  },
};