Beranda

Security

CORS untuk Pemula: Bukan Serangan, Tapi...

CORS untuk Pemula: Bukan Serangan, Tapi Salah Konfigurasinya...

CORS untuk Pemula: Bukan Serangan, Tapi Salah Konfigurasinya Bisa Fatal

Berbeda dengan XSS yang jelas-jelas sebuah serangan, CORS sebenarnya adalah mekanisme keamanan browser. Masalahnya muncul ketika developer salah mengonfigurasinya — dan celah itu bisa membocorkan data pengguna. Ini penjelasan lengkapnya untuk pemula.

CORS untuk Pemula: Bukan Serangan, Tapi Salah Konfigurasinya Bisa Fatal

Setelah membahas XSS, banyak pembaca bertanya: topik apa lagi yang wajib dipahami developer web pemula? Salah satu jawabannya adalah CORS.

Tapi ada satu hal penting yang perlu diluruskan sejak awal: CORS bukan jenis serangan. Berbeda dengan XSS atau SQL Injection yang memang merupakan teknik penyerangan, CORS adalah mekanisme keamanan yang dibangun di dalam browser. Yang berbahaya bukan CORS-nya, melainkan konfigurasi CORS yang dibuat sembarangan oleh developer.

Artikel ini akan membedah CORS dari nol — mulai dari alasan kemunculannya, cara kerjanya, sampai kesalahan konfigurasi yang paling sering ditemukan di lapangan.

Semuanya Bermula dari Same-Origin Policy

Sebelum memahami CORS, kita harus memahami aturan yang lebih tua: Same-Origin Policy (SOP).

SOP adalah aturan bawaan browser yang berbunyi kira-kira begini: sebuah halaman web hanya boleh membaca data dari origin yang sama dengan dirinya.

Lalu apa itu "origin"? Origin adalah kombinasi tiga hal:

  1. Skema (http atau https)
  2. Host (nama domain)
  3. Port

Ketiganya harus sama persis. Perhatikan contoh berikut, dengan acuan https://yowisben.com:

URL Origin sama? Alasan
https://yowisben.com/blog Ya Hanya path yang berbeda
http://yowisben.com Tidak Skema berbeda
https://api.yowisben.com Tidak Subdomain dianggap host berbeda
https://yowisben.com:8080 Tidak Port berbeda

Kenapa aturan ini penting? Bayangkan Anda sedang login di aplikasi bank melalui browser. Lalu di tab lain Anda membuka situs acak yang ternyata jahat. Tanpa SOP, JavaScript di situs jahat itu bisa memanggil API bank Anda, dan karena cookie sesi Anda otomatis ikut terkirim, ia bisa membaca saldo, riwayat transaksi, bahkan data pribadi Anda.

SOP-lah yang mencegah skenario mimpi buruk tersebut.

Catatan: SOP memblokir pembacaan respons, bukan selalu pengiriman request. Ini perbedaan halus yang akan kita bahas lagi nanti, dan menjadi alasan kenapa CSRF tetap bisa terjadi.

Lalu Kenapa CORS Dibutuhkan?

Masalahnya, SOP terlalu ketat untuk arsitektur aplikasi modern.

Hari ini sangat lumrah kita memisahkan frontend dan backend:

  • Frontend di https://app.perusahaan.com
  • Backend API di https://api.perusahaan.com

Keduanya milik satu perusahaan, tapi menurut SOP mereka adalah origin yang berbeda. Tanpa jalan keluar, frontend Anda tidak akan bisa mengambil data dari API-nya sendiri.

Di sinilah CORS (Cross-Origin Resource Sharing) masuk. CORS adalah mekanisme untuk melonggarkan SOP secara terkendali. Intinya sederhana:

Server yang menentukan siapa saja yang boleh membaca responsnya, dan browser yang menegakkan aturan itu.

Perhatikan kalimat di atas baik-baik, karena itulah inti dari seluruh konsep CORS.

Cara Kerja CORS Secara Praktis

Simple Request

Untuk request sederhana (misalnya GET biasa), alurnya begini:

  1. Browser mengirim request sambil menyertakan header Origin:
GET /api/produk HTTP/1.1
Host: api.perusahaan.com
Origin: https://app.perusahaan.com
  1. Server merespons dengan header izin:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://app.perusahaan.com
Content-Type: application/json
  1. Browser membandingkan keduanya. Jika cocok, JavaScript boleh membaca respons. Jika tidak cocok, browser memblokir akses dan menampilkan error CORS di console.

Preflight Request

Untuk request yang berpotensi mengubah data (PUT, DELETE, PATCH, atau POST dengan Content-Type: application/json), browser melakukan langkah pengaman tambahan: mengirim request OPTIONS terlebih dahulu untuk "bertanya izin".

OPTIONS /api/produk/12 HTTP/1.1
Origin: https://app.perusahaan.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: Authorization

Server menjawab:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.perusahaan.com
Access-Control-Allow-Methods: GET, POST, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 600

Baru setelah izin didapat, browser mengirim request DELETE yang sesungguhnya. Access-Control-Max-Age membuat browser menyimpan hasil izin ini selama beberapa waktu agar tidak bertanya berulang-ulang.

Tiga Kesalahpahaman Paling Umum

1. "CORS melindungi server saya."

Tidak. CORS ditegakkan oleh browser, bukan oleh server. Penyerang yang menggunakan curl, Postman, atau skrip Python sama sekali tidak terpengaruh aturan CORS. CORS melindungi pengguna dari situs jahat, bukan melindungi API Anda dari penyerang langsung.

2. "Kalau ada error CORS, berarti request-nya gagal."

Belum tentu. Pada banyak kasus request sudah sampai ke server dan sudah dieksekusi — browser hanya menolak memberikan responsnya ke JavaScript. Jadi jangan pernah mengandalkan CORS untuk mencegah aksi berbahaya.

3. "CORS bisa menggantikan autentikasi."

Tidak sama sekali. CORS mengatur siapa yang boleh membaca respons di browser. Otorisasi tetap harus dilakukan di sisi server melalui token, session, dan pengecekan hak akses.

Salah Konfigurasi yang Berbahaya

Inilah bagian yang membuat CORS relevan dibahas dalam kategori keamanan.

Memantulkan Origin secara membabi buta

Ini adalah pola paling berbahaya, dan sayangnya sering ditemukan:

// JANGAN LAKUKAN INI
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', req.headers.origin);
  res.header('Access-Control-Allow-Credentials', 'true');
  next();
});

Kode di atas menjawab "boleh" kepada siapa pun yang bertanya, sambil mengizinkan pengiriman cookie. Artinya, situs mana pun yang dikunjungi korban dapat memanggil API Anda dengan sesi korban yang aktif, lalu membaca hasilnya. Efeknya setara dengan kebocoran data akun.

Spesifikasi CORS sebenarnya melarang kombinasi Access-Control-Allow-Origin: * dengan Allow-Credentials: true. Memantulkan origin adalah cara developer "mengakali" larangan itu — dan justru menciptakan lubang besar.

Validasi domain yang lemah

// Rentan: "evil-perusahaan.com" dan "perusahaan.com.jahat.id" ikut lolos
if (origin.includes('perusahaan.com')) { /* izinkan */ }

Pencocokan dengan includes(), startsWith(), atau regex yang tidak diikat di awal-akhir string adalah sumber celah klasik. Gunakan pencocokan persis terhadap daftar putih.

Mengizinkan origin null

Nilai null bisa berasal dari halaman yang di-sandbox atau file lokal, dan mudah dipalsukan penyerang. Jangan pernah memasukkannya ke daftar izin.

Wildcard subdomain

*.perusahaan.com terlihat praktis, tapi berarti satu subdomain kecil yang terbengkalai dan rentan XSS bisa menjadi pintu masuk ke API utama Anda.

Konfigurasi yang Lebih Aman

const daftarIzin = [
  'https://app.perusahaan.com',
  'https://admin.perusahaan.com'
];

app.use(cors({
  origin: (origin, callback) => {
    // Izinkan request tanpa origin (mobile app, curl) sesuai kebutuhan
    if (!origin) return callback(null, true);
    if (daftarIzin.includes(origin)) return callback(null, true);
    return callback(new Error('Origin tidak diizinkan'));
  },
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  maxAge: 600
}));

Checklist singkat yang bisa Anda pakai:

  • Gunakan daftar putih eksplisit, bukan pemantulan origin.
  • Jangan gabungkan wildcard * dengan credentials: true.
  • Tambahkan header Vary: Origin agar cache (CDN maupun browser) tidak menyajikan izin milik origin lain.
  • Batasi method dan header hanya pada yang benar-benar dipakai.
  • Pakai * hanya untuk API publik yang datanya memang terbuka dan tidak butuh cookie.
  • Tetap terapkan autentikasi dan otorisasi penuh di sisi server.

Hubungannya dengan XSS dan CSRF

Ketiganya sering tertukar, padahal berbeda:

  • XSS — penyerang menyisipkan skrip berbahaya ke dalam halaman Anda.
  • CSRF — penyerang memancing browser korban mengirim aksi yang tidak diinginkan (mengirim, bukan membaca).
  • CORS — aturan yang menentukan apakah JavaScript boleh membaca respons lintas origin.

Yang menarik, XSS mampu melumpuhkan semuanya. Jika penyerang berhasil menjalankan skrip di dalam origin Anda, maka menurut browser ia sudah "sah" berada di dalam — SOP dan CORS tidak lagi menjadi penghalang. Karena itu, mengamankan aplikasi dari XSS tetap menjadi prioritas utama.

Penutup

CORS bukanlah musuh yang harus dimatikan setiap kali muncul error merah di console. Ia adalah pagar pengaman yang bekerja untuk melindungi pengguna Anda.

Godaan terbesar bagi developer pemula adalah menyalakan mode "izinkan semua" agar aplikasi cepat jalan, lalu lupa merapikannya sebelum masuk produksi. Padahal, satu baris konfigurasi yang terlalu longgar bisa membuka jalan bagi kebocoran data pengguna.

Prinsipnya sederhana: pahami dulu kenapa pagar itu ada, baru buka pintunya seperlunya — untuk pihak yang memang Anda percaya.

Post Terkait

CSRF untuk Pemula: Ketika Browser Anda Sendiri Jadi Senjata Penyerang

CSRF memanfaatkan satu kebiasaan browser: mengirim cookie sesi ke domain tujuan tanpa peduli halaman mana yang memicunya...

19 Agt 2026

SQL Injection untuk Pemula: Saat Satu Tanda Kutip Bisa Membobol Database

Kerentanan berumur lebih dari dua dekade ini masih rutin muncul di berita kebocoran data. Pahami kenapa query yang diben...

19 Agt 2026

XSS (Cross-Site Scripting): Cara Kerja Serangan dan Pencegahannya

Bedah tuntas cara kerja Cross-Site Scripting (XSS): tiga jenisnya, pola berpikir penyerang saat mencari celah, dan cara...

19 Agt 2026

© 2026 Yowisben. Semua hak dilindungi.

Powered by LONTAR CMS v1.60.1