Security header adalah header respons HTTP yang memberi tahu browser cara berperilaku dengan konten situs Anda. Salah mengkonfigurasinya (atau menghilangkannya) membuat pengguna Anda terekspos terhadap serangan XSS, clickjacking, serangan MIME type sniffing, dan kebocoran informasi. Setelah bekerja pada aplikasi ERP dan SaaS produksi di mana persyaratan keamanan eksplisit, saya telah mengembangkan konfigurasi security header next.config.ts standar yang saya terapkan ke setiap proyek.
Security header penting untuk aplikasi Next.js adalah: Content-Security-Policy (membatasi sumber daya mana yang dapat dimuat), Strict-Transport-Security (memaksakan HTTPS), X-Frame-Options (mencegah clickjacking melalui iframe), X-Content-Type-Options (mencegah MIME sniffing), Referrer-Policy (mengontrol informasi referrer yang dikirim), dan Permissions-Policy (membatasi API browser seperti kamera, mikrofon, geolokasi). Bersama-sama, mereka mengimplementasikan defense-in-depth.
CSP adalah security header yang paling berdampak dan paling kompleks untuk dikonfigurasi dengan benar. Ini mendefinisikan daftar putih sumber tepercaya untuk setiap jenis sumber daya: scripts, styles, images, fonts, frames, dan API connections. CSP ketat memblokir eksekusi JavaScript inline — vektor utama untuk serangan XSS di mana skrip berbahaya yang disuntikkan berjalan di browser pengguna Anda.
Strict-Transport-Security (HSTS) memberi tahu browser untuk tidak pernah terhubung ke situs Anda melalui HTTP. Nilai `max-age` dalam detik — 63072000 adalah dua tahun. Direktif `includeSubDomains` memperluas kebijakan ke semua subdomain. `preload` mengirimkan domain Anda ke daftar preload HSTS hardcoded browser — browser memaksakan HTTPS bahkan pada kunjungan pertama.
Security Header Stack — Attack Vectors Covered:
────────────────────────────────────────────────────────────
Content-Security-Policy → XSS (inline script injection)
Strict-Transport-Security → MITM (downgrade to HTTP)
X-Frame-Options → Clickjacking (iframe overlay)
X-Content-Type-Options → MIME sniffing attacks
Referrer-Policy → Information leakage
Permissions-Policy → Browser API abuse (camera, mic)
CSP Directive Examples:
default-src 'self' → only load from own domain
script-src 'self' 'nonce-{token}' → only inline scripts with nonce
style-src 'self' 'unsafe-inline' → styles (often needed for Tailwind)
img-src 'self' data: https: → images from self + any HTTPS
connect-src 'self' https://api.example.com → API calls
frame-ancestors 'none' → no iframes anywhere
SecurityHeaders.com grades:
A+: All headers configured correctly
A: Minor issues (e.g., CSP report-only mode)
B: Missing some headers
F: No security headers configuredDari pengalaman saya mengkonfigurasi CSP pada aplikasi Next.js: titik nyeri terbesar adalah persyaratan nonce. Nonce adalah nilai acak yang dihasilkan per-permintaan dan disuntikkan ke dalam header CSP maupun tag skrip inline tepercaya. Rendering statis Next.js (ISR, SSG) tidak dapat menghasilkan nonce baru per permintaan karena HTML sudah pra-dirender. Solusi terbersih: gunakan Vercel Edge Middleware yang menghasilkan nonce, memodifikasi header CSP, dan meneruskan nonce ke halaman melalui request header.
Saya menerapkan security header secara global di next.config.ts menggunakan fungsi headers(). Semua rute mendapatkan stack header penuh. Rute tertentu (Swagger UI di non-prod, misalnya) mendapatkan header yang dilonggarkan. CSP dimulai dalam mode report-only (`Content-Security-Policy-Report-Only`) dengan URI laporan sehingga saya dapat melihat pelanggaran sebelum memaksakan.
Permissions-Policy (sebelumnya Feature-Policy) mengontrol API browser mana yang dapat digunakan situs Anda. Bahkan jika Anda tidak menggunakan kamera atau mikrofon, memblokir mereka di header Permissions-Policy berarti skrip XSS yang disuntikkan ke situs Anda juga tidak dapat mengaksesnya. Saya mengatur: `camera=(), microphone=(), geolocation=(), payment=()` untuk menonaktifkan semua API sensitif.
// next.config.ts — security headers I ship on every project
const securityHeaders = [
{
key: 'X-DNS-Prefetch-Control',
value: 'on',
},
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload',
},
{
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=(), geolocation=(), payment=()',
},
// Start with report-only, switch to enforce after monitoring
{
key: 'Content-Security-Policy-Report-Only',
value: [
"default-src 'self'",
"script-src 'self' 'nonce-{nonce}'", // nonce injected by middleware
"style-src 'self' 'unsafe-inline'", // Tailwind requires this
"img-src 'self' data: https:",
"font-src 'self'",
"connect-src 'self' https://vitals.vercel-insights.com",
"frame-ancestors 'none'",
"report-uri /api/csp-report",
].join('; '),
},
]
const nextConfig: NextConfig = {
async headers() {
return [
{
source: '/(.*)', // apply to all routes
headers: securityHeaders,
},
]
},
}
// middleware.ts — nonce-based CSP for ISR/SSG pages
import { NextResponse } from 'next/server'
import crypto from 'crypto'
export function middleware() {
const nonce = crypto.randomBytes(16).toString('base64')
const response = NextResponse.next()
response.headers.set(
'Content-Security-Policy',
`script-src 'self' 'nonce-${nonce}'; ...`
)
response.headers.set('x-nonce', nonce) // page reads this for script tags
return response
}X-Frame-Options mencegah situs Anda disematkan dalam iframe di domain lain (perlindungan clickjacking). Ekuivalen modern adalah direktif CSP `frame-ancestors`, yang menggantikan X-Frame-Options di browser yang mendukung CSP. Saya mengatur keduanya untuk kompatibilitas maksimum: `X-Frame-Options: DENY` dan `Content-Security-Policy: frame-ancestors 'none'`.
Men-deploy CSP yang memaksakan tanpa mengujinya terlebih dahulu akan merusak aplikasi Anda. CSP ketat yang memblokir skrip inline akan mencegah hidrasi, memblokir analitik, dan merusak widget pihak ketiga. Selalu mulai dengan Content-Security-Policy-Report-Only dan report-uri. Pantau pelanggaran selama seminggu di produksi — setiap pelanggaran adalah sesuatu yang akan diblokir CSP Anda. Perbaiki pelanggaran dengan menyesuaikan kebijakan atau memperbaiki kode, lalu beralih ke mode enforcement.
SecurityHeaders.com (oleh Scott Helme) menilai security header Anda dari A+ hingga F. Jalankan terhadap situs Anda sebelum dan sesudah mengkonfigurasi header untuk mengukur kemajuan. Dalam CI, tambahkan tes Playwright yang mengambil homepage Anda dan memastikan keberadaan dan nilai setiap security header.
Jika CSP Anda mengizinkan sumber skrip eksternal (CDN, analitik), tambahkan hash Subresource Integrity (SRI). SRI memungkinkan Anda menentukan hash kriptografi skrip — browser memverifikasi skrip yang diunduh cocok dengan hash sebelum mengeksekusinya. Di Next.js, komponen Script mendukung prop `integrity` untuk SRI.