Use Cases (Diperbarui: 2/6/2026)

Web Security Headers dengan Claude Code: CSP, nonce, HSTS, dan rollout aman untuk iklan

Konfigurasikan CSP, nonce, HSTS, frame-ancestors, dan security headers dengan Claude Code.

Web Security Headers dengan Claude Code: CSP, nonce, HSTS, dan rollout aman untuk iklan

Web security headers sering terlihat seperti detail kecil di response HTTP, padahal dampaknya besar. Header ini mengatur script mana yang boleh berjalan, apakah halaman admin boleh dimasukkan ke iframe situs lain, seberapa banyak referrer dikirim ke domain eksternal, dan apakah fitur browser seperti kamera, mikrofon, geolocation, atau payment boleh dipakai.

Claude Code bisa mempercepat pekerjaan ini karena dapat membaca repository, menemukan script pihak ketiga, mengubah konfigurasi framework, dan menyusun langkah verifikasi. Namun prompt yang terlalu umum juga berbahaya. Jika kamu hanya menulis “perbaiki error CSP”, Claude Code bisa saja menyarankan script-src * 'unsafe-inline' 'unsafe-eval'. Console jadi bersih, tetapi perlindungan CSP ikut hilang.

Pendekatan yang lebih aman adalah inventaris resource, aktifkan Content-Security-Policy-Report-Only, baca report, sesuaikan policy per route, lalu baru enforce. Artikel ini membahas CSP, nonce, HSTS, X-Frame-Options, frame-ancestors, Referrer-Policy, dan Permissions-Policy dengan contoh untuk Next.js, Astro, Express, dan Cloudflare Pages. Kita juga membahas CSP report, Security Headers, CSP Evaluator, serta konflik umum dengan Google Tag Manager, Google Analytics, AdSense, image CDN, dan iframe. Untuk keamanan penggunaan Claude Code secara umum, baca juga Claude Code security best practices dan security audit dengan Claude Code.

Tetap rujuk dokumentasi resmi saat menyesuaikan contoh: MDN Content-Security-Policy, Next.js CSP guide, MDN Strict-Transport-Security, hstspreload.org, Cloudflare Pages Headers, Helmet, Google Tag Manager CSP, dan AdSense CSP guide.

Mulai dari inventaris resource

Jangan mulai dari copy-paste policy. Minta Claude Code mencari dulu apa yang benar-benar dimuat oleh situs.

Rancang Web security headers untuk repository ini.
Aturan:
- Inventaris origin eksternal untuk script, style, image, font, frame, dan connect.
- CSP dimulai dengan Report-Only.
- Hindari * dan unsafe-inline permanen.
- Jika Next.js membutuhkan nonce, jelaskan dampak ke dynamic rendering dan cache.
- Cek konflik Google Analytics, GTM, AdSense, image CDN, dan YouTube iframe.
- Berikan verifikasi dengan curl, Security Headers, dan CSP Evaluator.

Beberapa directive sering tertukar. frame-src berarti halaman kamu boleh memuat iframe dari mana. frame-ancestors berarti siapa yang boleh menaruh halaman kamu di iframe. Masalah GA4 biasanya ada di connect-src; gambar CDN di img-src; clickjacking di frame-ancestors.

HeaderAwal yang amanCatatan produksi
Content-Security-PolicyMulai dengan Content-Security-Policy-Report-OnlyJangan menutup masalah dengan *
Strict-Transport-SecurityMulai max-age=300; includeSubDomainspreload hanya setelah semua subdomain siap HTTPS
X-Frame-OptionsDENY atau SAMEORIGINframe-ancestors lebih granular untuk browser modern
Referrer-Policystrict-origin-when-cross-originJangan taruh token atau data pribadi di URL
Permissions-PolicyMatikan fitur yang tidak dipakaiIzinkan hanya fitur yang dibutuhkan produk
X-Content-Type-OptionsnosniffUmumnya cocok di seluruh situs

HSTS preload perlu hati-hati. Situs preload resmi menyarankan peningkatan max-age bertahap dan mengingatkan bahwa keluar dari preload bisa lama. Satu subdomain lama yang belum HTTPS dapat menjadi gangguan nyata jika includeSubDomains; preload dipasang terlalu cepat.

Alur rollout CSP

Rollout yang sehat adalah observasi, klasifikasi, lalu enforcement.

flowchart LR
  A["Inventaris resource"] --> B["Kirim CSP Report-Only"]
  B --> C["Kumpulkan console dan report"]
  C --> D["Pisahkan ads, analytics, CDN, iframe, dan noise"]
  D --> E["Aktifkan CSP berbasis nonce atau hash"]
  E --> F["Validasi dengan Security Headers dan CSP Evaluator"]

Jangan langsung menambahkan semua domain yang muncul di report. Browser extension, proxy kantor, tag lama, dan percobaan serangan juga bisa memicu report. Claude Code bisa membantu mengelompokkan, tetapi keputusan akhir harus berdasarkan kebutuhan produk.

Next.js dengan nonce

Dokumentasi Next.js App Router saat ini menggunakan proxy.ts untuk membuat nonce per request. Project lama mungkin masih memakai middleware.ts, tetapi konsepnya sama: buat nilai acak yang sulit ditebak, masukkan ke request header, lalu pakai nilai yang sama di script-src.

Nonce per request berdampak pada rendering. Halaman yang membutuhkan nonce baru tidak cocok dengan HTML statis yang sama untuk semua request. Untuk blog publik atau landing page, hash CSP atau memindahkan script inline ke file eksternal bisa lebih sederhana. Untuk login, checkout, akun, dan admin, nonce biasanya layak.

// proxy.ts
import { NextRequest, NextResponse } from "next/server";

export function proxy(request: NextRequest) {
  const nonce = Buffer.from(crypto.randomUUID()).toString("base64");
  const isDev = process.env.NODE_ENV !== "production";

  const csp = [
    "default-src 'self'",
    `script-src 'self' 'nonce-${nonce}' 'strict-dynamic' ${isDev ? "'unsafe-eval'" : ""} https: http:`,
    `style-src 'self' ${isDev ? "'unsafe-inline'" : `'nonce-${nonce}'`} https://fonts.googleapis.com`,
    "font-src 'self' https://fonts.gstatic.com",
    "img-src 'self' data: blob: https:",
    "connect-src 'self' https://www.google-analytics.com https://analytics.google.com",
    "frame-src 'self' https://www.youtube-nocookie.com",
    "object-src 'none'",
    "base-uri 'self'",
    "form-action 'self'",
    "frame-ancestors 'none'",
    "upgrade-insecure-requests",
    "report-uri /api/csp-report",
  ].join("; ").replace(/\s{2,}/g, " ").trim();

  const requestHeaders = new Headers(request.headers);
  requestHeaders.set("x-nonce", nonce);

  const response = NextResponse.next({ request: { headers: requestHeaders } });
  response.headers.set("Content-Security-Policy", csp);
  response.headers.set("X-Content-Type-Options", "nosniff");
  response.headers.set("X-Frame-Options", "DENY");
  response.headers.set("Referrer-Policy", "strict-origin-when-cross-origin");
  response.headers.set("Permissions-Policy", "camera=(), microphone=(), geolocation=(), payment=(self)");
  response.headers.set("Strict-Transport-Security", "max-age=300; includeSubDomains");
  return response;
}

export const config = {
  matcher: ["/((?!api/csp-report|_next/static|_next/image|favicon.ico).*)"],
};

Jika menggunakan Google Tag Manager, teruskan nonce ke snippet atau component. Bootstrap GTM adalah JavaScript inline, dan Google merekomendasikan nonce. AdSense juga memiliki panduan strict CSP karena domain iklan dapat berubah. Allowlist statis bisa merusak monetisasi di kemudian hari.

Endpoint CSP report

Report-Only berguna jika kamu mengumpulkan report.

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

export async function POST(request: NextRequest) {
  const contentType = request.headers.get("content-type") ?? "";
  const body = await request.text();

  const isReport =
    contentType.includes("application/csp-report") ||
    contentType.includes("application/reports+json") ||
    body.includes("violated-directive");

  if (!isReport) {
    return NextResponse.json({ ok: false }, { status: 415 });
  }

  console.warn("csp-report", body.slice(0, 4000));
  return new NextResponse(null, { status: 204 });
}

Di production, jangan menyimpan URL penuh jika query string bisa berisi data pribadi. Simpan route, directive yang dilanggar, blocked URI, user agent, waktu, dan jumlah kejadian. report-uri memang lama, tetapi masih praktis untuk kompatibilitas. report-to bisa ditambahkan, tetapi jangan jadikan satu-satunya jalur.

Astro, Express, dan Cloudflare

Astro dapat memasang header melalui src/middleware.ts. Untuk situs yang mayoritas statis, mengurangi script inline biasanya lebih mudah daripada membuat nonce.

// src/middleware.ts
import { defineMiddleware } from "astro:middleware";

const securityHeaders: Record<string, string> = {
  "Content-Security-Policy-Report-Only": "default-src 'self'; script-src 'self' https://www.googletagmanager.com; img-src 'self' data: blob: https:; connect-src 'self' https://www.google-analytics.com; frame-src 'self' https://www.youtube-nocookie.com; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; report-uri /api/csp-report",
  "X-Content-Type-Options": "nosniff",
  "X-Frame-Options": "DENY",
  "Referrer-Policy": "strict-origin-when-cross-origin",
  "Permissions-Policy": "camera=(), microphone=(), geolocation=(), payment=(self)",
};

export const onRequest = defineMiddleware(async (_context, next) => {
  const response = await next();
  for (const [name, value] of Object.entries(securityHeaders)) {
    response.headers.set(name, value);
  }
  return response;
});

Di Express, Helmet adalah pilihan praktis, tetapi CSP tetap harus disesuaikan dengan aplikasi.

import crypto from "node:crypto";
import express from "express";
import helmet from "helmet";

const app = express();

app.use((req, res, next) => {
  res.locals.cspNonce = crypto.randomBytes(16).toString("base64");
  next();
});

app.use(helmet({
  contentSecurityPolicy: {
    useDefaults: false,
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.cspNonce}'`, "'strict-dynamic'", "https:", "http:"],
      imgSrc: ["'self'", "data:", "blob:", "https:"],
      connectSrc: ["'self'", "https://www.google-analytics.com"],
      objectSrc: ["'none'"],
      baseUri: ["'self'"],
      frameAncestors: ["'none'"],
      reportUri: ["/csp-report"],
    },
  },
  strictTransportSecurity: { maxAge: 300, includeSubDomains: true },
  referrerPolicy: { policy: "strict-origin-when-cross-origin" },
  xFrameOptions: { action: "deny" },
}));

Cloudflare Pages memakai _headers untuk header statis. File ini tidak bisa membuat nonce per request.

/*
  X-Content-Type-Options: nosniff
  X-Frame-Options: DENY
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(self)
  Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' https://www.googletagmanager.com; img-src 'self' data: blob: https:; connect-src 'self' https://www.google-analytics.com; frame-src 'self' https://www.youtube-nocookie.com; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; report-uri /csp-report

Use case dan kesalahan umum

Situs konten dengan GA4, GTM, AdSense, font eksternal, YouTube, dan image CDN harus menyeimbangkan keamanan dan pendapatan. Gunakan Report-Only sebelum enforcement, lalu cek apakah iklan tampil, event Analytics masuk, dan gambar tetap termuat.

Area admin SaaS harus lebih ketat. Kurangi script pihak ketiga, gunakan frame-ancestors 'none', object-src 'none', base-uri 'self', dan form-action yang sempit. SDK payment atau chat cukup diizinkan pada route yang benar-benar membutuhkannya.

Widget yang perlu di-embed membutuhkan policy terpisah. Jika pelanggan harus memasang halaman kamu di iframe, X-Frame-Options: DENY salah untuk route tersebut. Gunakan header per route dan daftar domain tepercaya di frame-ancestors.

Verifikasi dan hasil uji

Cek minimal home, login atau form, dan route embed atau checkout.

curl -I https://example.com/
curl -I https://example.com/login
curl -I https://example.com/embed/widget

Lanjutkan dengan Security Headers untuk gambaran umum dan CSP Evaluator untuk kelemahan CSP. Skor tinggi berguna, tetapi bukan tujuan akhir. Tujuannya adalah policy yang melindungi tanpa merusak iklan, Analytics, payment, gambar, dan iframe yang memang diperlukan.

Pada setup uji untuk artikel ini, langkah paling berguna adalah Report-Only. Masalah nonce GTM, connect-src GA4, frame-src YouTube, dan img-src CDN muncul sebagai kategori yang berbeda. Setelah Claude Code diminta mengelompokkan report, hasilnya bukan sekadar menambah domain, tetapi policy per route, penerusan nonce, penghapusan tag yang tidak perlu, dan rollout HSTS bertahap. Untuk menerapkan ini pada repository nyata, gunakan training dan konsultasi Claude Code atau produk dan template ClaudeCodeLab agar checklist masuk ke aturan review CLAUDE.md.

#Claude Code #security #HTTP headers #CSP #web development
Gratis

PDF gratis: cheatsheet Claude Code

Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.

Kami menjaga datamu dan tidak mengirim spam.

Masa

Tentang penulis

Masa

Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.