Mengamankan Aplikasi Next.js dengan Content Security Policy dan Security Headers

Lhuqita Fazry
Web Development Next.js Security Headers CSP Keamanan Web
Mengamankan Aplikasi Next.js dengan Content Security Policy dan Security Headers

Security headers adalah garis pertahanan pertama yang tidak boleh kita lewatkan saat mendeploy aplikasi Next.js ke production. Cross-Site Scripting (XSS), clickjacking, dan MIME-type sniffing adalah tiga ancaman yang masih mendominasi lanskap keamanan web. XSS memungkinkan attacker menyuntikkan script berbahaya ke halaman yang dilihat user. Clickjacking menyembunyikan halaman legitimate di balik iframe transparan. MIME-type sniffing membuat browser salah menginterpretasikan file hasil upload.

Response headers bekerja di level HTTP, sebelum aplikasi kita mengeksekusi logic apapun. Berbeda dengan validasi input yang mencegah serangan di level aplikasi, security headers menginstruksikan browser tentang bagaimana menangani konten yang diterima. Keduanya saling melengkapi, bukan salah satu saja. Next.js sebagai SSR framework punya karakteristik unik: server merender halaman dan mengirimkan HTML beserta inline scripts yang diperlukan untuk hydration. Inline scripts ini sering menjadi target XSS jika tidak dilindungi dengan Content Security Policy yang tepat.

Ancaman Keamanan Web yang Bisa Dicegah dengan Response Headers

Setiap jenis serangan web membutuhkan response header yang berbeda untuk pencegahannya. Serangan XSS terjadi ketika browser mengeksekusi script yang tidak tepercaya dari sumber eksternal. Clickjacking memanfaatkan iframe untuk menyembunyikan halaman asli di bawah lapisan transparan, menipu user agar mengklik elemen yang tidak diinginkan. MIME-type sniffing membuat browser mengabaikan Content-Type yang ditentukan server dan menebak-nebak tipe konten berdasarkan isi file, membuka celah untuk penyisipan script.

Diagram sequence serangan Cross-Site Scripting (XSS)

Gambar: Diagram sequence serangan Cross-Site Scripting (XSS) — Sumber: [Wikimedia Commons](https://commons.wikimedia.org/wiki/File:Cross-site_scripting_attack_sequence_diagram_-_en.png) (CC BY-SA 4.0)

Response headers seperti X-Content-Type-Options dan X-Frame-Options memberikan instruksi tegas ke browser. Header X-Content-Type-Options: nosniff memerintahkan browser untuk mematuhi Content-Type yang ditetapkan server. X-Frame-Options: DENY melarang halaman dimuat di dalam iframe sama sekali.

Keamanan di level HTTP berbeda fundamental dengan keamanan di level aplikasi. Validasi input dan sanitasi data mencegah serangan pada saat data diproses. Security headers mencegah eksploitasi pada saat hasil dipresentasikan ke browser. Kedua lapisan harus berjalan bersamaan, tetapi security headers memberikan perlindungan yang tidak tergantung pada kualitas kode aplikasi.

Implementasi Security Headers Dasar di next.config.js

Next.js menyediakan API headers() di next.config.js untuk menambahkan response headers secara deklaratif. Fungsi ini mengembalikan array objek konfigurasi, di mana setiap objek memiliki properti source untuk menentukan route pattern dan array headers berisi pasangan key-value.

Beberapa header wajib yang perlu kita terapkan sejak awal:

X-Content-Type-Options: nosniff mencegah browser melakukan MIME sniffing. X-Frame-Options: DENY melindungi dari clickjacking. * Referrer-Policy: strict-origin-when-cross-origin mengontrol informasi referrer yang dikirim saat navigasi antar domain.

Header Permissions-Policy berfungsi membatasi akses API browser seperti kamera, mikrofon, dan geolocation. Dengan membatasi API ini sejak awal, kita mengurangi permukaan serangan jika terdapat komponen pihak ketiga yang berbahaya.

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

module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: securityHeaders,
      },
    ];
  },
};
Fullstack Web Development With Next.js
Web App • Beginner

Fullstack Web Development With Next.js

A practical, beginner-friendly, and project-based introduction to full-stack web...

Daftar

Konfigurasi di atas menerapkan header ke semua route melalui pattern source: '/:path'. Kita bisa membatasi header ke route tertentu dengan mengganti pattern menjadi /dashboard/:path atau route spesifik lainnya. Header Permissions-Policy dengan nilai () pada setiap direktif berarti semua API tersebut diblokir total. API hanya bisa diaktifkan kembali melalui interaksi user di halaman yang membutuhkannya.

Menyusun Content Security Policy yang Ketat untuk Next.js

Content Security Policy adalah header paling kompleks namun paling efektif untuk mencegah XSS. CSP bekerja melalui directive yang mengontrol resource apa yang boleh dimuat dan dieksekusi oleh browser. Setiap directive mendefinisikan whitelist sumber daya untuk tipe konten tertentu.

Directive utama yang perlu kita konfigurasi meliputi default-src sebagai fallback untuk semua tipe resource, script-src untuk script, style-src untuk stylesheet, img-src untuk gambar, dan connect-src untuk koneksi fetch dan WebSocket. Tantangan terbesar CSP di Next.js adalah menangani inline scripts yang dihasilkan untuk proses hydration. Setiap build Next.js menghasilkan script chunks dengan hash yang berbeda.

Pendekatan modern menggunakan directive strict-dynamic. Directive ini secara otomatis mempercayai script yang dimuat oleh script tepercaya lainnya, sehingga kita tidak perlu mendaftarkan setiap hash chunk secara manual. Kombinasi strict-dynamic dengan unsafe-inline sebagai fallback untuk browser lawas memberikan kompatibilitas maksimal tanpa mengorbankan keamanan.

javascriptjavascript
// next.config.js
const cspConfig = {
  'default-src': ["'self'"],
  'script-src': ["'self'", "'strict-dynamic'", "'unsafe-inline'", 'https:'],
  'style-src': ["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com'],
  'img-src': ["'self'", 'data:', 'https://images.unsplash.com'],
  'font-src': ["'self'", 'https://fonts.gstatic.com'],
  'connect-src': ["'self'", 'https://api.example.com'],
  'base-uri': ["'self'"],
  'form-action': ["'self'"],
};

const cspString = Object.entries(cspConfig)
  .map(([key, values]) => `${key} ${values.join(' ')}`)
  .join('; ');

Kita perlu menambahkan https://fonts.googleapis.com ke style-src dan https://fonts.gstatic.com ke font-src jika menggunakan Google Fonts. Directive connect-src mencakup endpoint API yang dipanggil dari client-side. Nilai cspString yang dihasilkan kemudian ditambahkan ke array securityHeaders sebagai header Content-Security-Policy.

Sebelum menerapkan CSP secara ketat, kita bisa mengujinya terlebih dahulu dengan header Content-Security-Policy-Report-Only. Mode report-only mengirimkan laporan pelanggaran ke endpoint yang kita tentukan tanpa memblokir resource. Strategi ini memungkinkan kita mengidentifikasi false positive sebelum kebijakan benar-benar ditegakkan.

Menambahkan Security Headers untuk API Routes dan Server Actions

API routes dan Server Actions memiliki kebutuhan keamanan yang berbeda dengan halaman. Endpoint API perlu menangani CORS, cache control, dan CSRF protection. Next.js memungkinkan kita mengonfigurasi header spesifik untuk API routes melalui middleware yang berjalan sebelum request mencapai handler.

Middleware di Next.js berjalan di Edge Runtime untuk setiap request yang cocok dengan pattern matcher. Kita bisa memanfaatkannya untuk menyisipkan header tambahan yang tidak tercakup oleh konfigurasi statis di next.config.js, seperti CORS headers dan CSRF token.

typescripttypescript
// middleware.ts
import { NextRequest, NextResponse } from 'next/server';

export function middleware(request: NextRequest) {
  const response = NextResponse.next();

  if (request.nextUrl.pathname.startsWith('/api/')) {
    response.headers.set(
      'Access-Control-Allow-Origin',
      process.env.ALLOWED_ORIGIN || ''
    );
    response.headers.set(
      'Access-Control-Allow-Methods',
      'GET, POST, PUT, DELETE'
    );
    response.headers.set(
      'Access-Control-Allow-Headers',
      'Content-Type, Authorization'
    );
    response.headers.set('X-CSRF-Token', '1');
    response.headers.set('X-Content-Type-Options', 'nosniff');
    response.headers.set('Cache-Control', 'no-store');

    if (request.method === 'OPTIONS') {
      return new NextResponse(null, {
        headers: response.headers,
        status: 204,
      });
    }
  }

  return response;
}

export const config = {
  matcher: '/api/:path*',
};

Middleware ini menambahkan CORS headers dan security headers khusus untuk API routes. Preflight request OPTIONS ditangani dengan response 204 tanpa body. Header Cache-Control: no-store mencegah browser menyimpan cache response API yang mungkin berisi data sensitif. Nilai Access-Control-Allow-Origin sebaiknya diambil dari environment variable, bukan hardcoded, agar mudah diubah antar environment.

Header X-CSRF-Token yang kita sisipkan membantu melindungi Server Actions dari serangan CSRF. Token ini bisa diverifikasi oleh API handler untuk memastikan request berasal dari aplikasi kita sendiri, bukan dari situs eksternal.

Validasi dan Monitoring Security Headers di Production

Setelah konfigurasi selesai, langkah selanjutnya adalah memvalidasi bahwa semua header berfungsi seperti yang diharapkan. Tools seperti Mozilla Observatory dan securityheaders.com memberikan skor berdasarkan header yang terdeteksi, lengkap dengan rekomendasi perbaikan. Lighthouse di Chrome DevTools juga menyertakan audit security headers dalam laporannya.

Monitoring CSP violations sama pentingnya dengan validasi awal. Saat browser memblokir resource yang melanggar CSP, kita perlu tahu resource apa yang diblokir dan dari halaman mana. Kita bisa membuat endpoint API sederhana untuk menerima laporan pelanggaran.

typescripttypescript
// app/api/csp-report/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const report = await request.json();
  const cspReport = report['csp-report'];

  console.log('CSP Violation:', {
    'document-uri': cspReport['document-uri'],
    'blocked-uri': cspReport['blocked-uri'],
    'violated-directive': cspReport['violated-directive'],
    timestamp: new Date().toISOString(),
  });

  // Simpan ke database atau kirim ke logging service
  // await saveCspReport(cspReport);

  return NextResponse.json({ status: 'ok' }, { status: 200 });
}

Endpoint ini menerima POST request dari browser yang melaporkan pelanggaran CSP. Data yang diterima mencakup document-uri (halaman tempat pelanggaran terjadi) dan blocked-uri (resource yang diblokir). Informasi ini membantu kita mengidentifikasi halaman mana yang memuat resource dari domain yang tidak terdaftar di CSP. Di production, laporan sebaiknya disimpan ke database atau dikirim ke service monitoring seperti Sentry.

Proses iterasi yang ideal: deploy dengan mode report-only, kumpulkan laporan pelanggaran selama beberapa hari, sesuaikan kebijakan berdasarkan laporan, lalu aktifkan mode enforcement. Checklist minimum sebelum go-live:

1. Semua security headers dasar terpasang. 2. CSP dalam mode enforcement untuk semua halaman. 3. CORS headers dikonfigurasi hanya untuk domain yang diperlukan. 4. API endpoint diproteksi dengan CSRF token. 5. Mozilla Observatory skor minimal B.

Mau memperdalam skill Web Development secara sistematis? Bergabunglah dengan Web Development Bootcamp di Rumah Coding. Kurikulum praktis dengan proyek real-world dan mentorship dari praktisi industri.

Course Terkait

TechConnect - Modern IT Job Portal
Premium Course Web App

Fullstack Web Development With Next.js

A practical, beginner-friendly, and project-based introduction to full-stack web development. Students will learn to build, secure, and deploy modern web applications from scratch using Next.js (App Router), React, Tailwind CSS, and a relational database. By the end of the course, students will have a fully functional, production-ready application to showcase in their portfolio.

Capstone Project

TechConnect - Modern IT Job Portal

  • Public Job Board: A responsive homepage displaying available job listings with dynamic routing for individual job detail pages.
  • Search & Filter: Basic functionality allowing users to find jobs based on keywords or categories.
  • User Authentication: Secure Sign Up, Log In, and Log Out workflows.
7 Weeks Beginner
Lihat Detail Course

Artikel Terkait