Topik wawancara representatif

Wawancara Frontend: Bagaimana Cara Anda Mendebug CORS Preflight dan Kredensial Permintaan?

FrontendSedang
Tim Redaksi Offer.ccDipublikasikan Diperbarui

Pertanyaan

Sebuah halaman di https://app.example.com menggunakan fetch untuk mengirim JSON POST ke https://api.example.com/profile/preferences dengan header X-CSRF-Token dan cookie login. Pemanggilan tersebut berhasil di curl tetapi gagal dengan galat CORS di peramban. Jelaskan permintaan mana saja yang dikirim oleh peramban, diagnosis konfigurasinya, berikan perbaikan yang aman, dan jelaskan bagaimana Anda memverifikasinya.

Pertanyaan dan Kapan Ini Berlaku

Halaman berjalan di https://app.example.com, sedangkan API berada di https://api.example.com. Frontend mengirimkan preferensi pengguna:

ts
await fetch("https://api.example.com/profile/preferences", {
  method: "POST",
  credentials: "include",
  headers: {
    "Content-Type": "application/json",
    "X-CSRF-Token": csrfToken,
  },
  body: JSON.stringify({ compactMode: true }),
})

Server saat ini mengembalikan respons berikut untuk OPTIONS:

http
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST

POST langsung melalui curl berhasil, tetapi konsol peramban hanya melaporkan galat lintas-asal (cross-origin). Jelaskan:

  1. mengapa kedua subdomain tersebut masih berstatus lintas-asal;
  2. mengapa peramban mengirimkan OPTIONS terlebih dahulu dan kapan peramban akan melanjutkan dengan POST;
  3. apa yang salah dengan header respons saat ini dan bagaimana cara menerapkan perbaikan berprinsip least-privilege;
  4. tanggung jawab terpisah dari CORS, cookie, autentikasi, otorisasi, dan CSRF;
  5. bagaimana cara membuktikan perbaikan tersebut di developer tools dan pengujian otomatis.

Ini berguna untuk wawancara frontend dan full-stack. Ujiannya bukanlah apakah seseorang dapat menghafal serangkaian header. Melainkan apakah mereka dapat menelusuri balik dari fase jaringan peramban dan memisahkan empat pertanyaan: apakah permintaan terkirim, apakah kredensial disertakan, bolehkah JavaScript membaca respons, dan apakah aplikasi mengotorisasi operasi tersebut?

Apa yang Dinilai oleh Pewawancara

Pertama, kandidat harus mengidentifikasi asal (origin) secara tepat. Sebuah origin terdiri dari skema, host, dan port. Kedua URL sama-sama menggunakan HTTPS dan biasanya berstatus same-site, tetapi host-nya berbeda, sehingga permintaan tersebut berstatus same-site dan cross-origin. CORS berbasis origin; atribut cookie SameSite berbasis site. Keduanya tidak dapat dipertukarkan.

Kedua, kandidat harus memahami pemicu preflight. application/json bukanlah nilai request-header yang masuk dalam CORS-safelist, dan X-CSRF-Token bukanlah request header yang masuk dalam safelist. Oleh karena itu, peramban mengirimkan OPTIONS untuk menanyakan apakah metode dan header sebenarnya diizinkan. Jika preflight gagal, POST tidak dikirim.

Ketiga, kandidat harus menemukan dua kesalahan konfigurasi langsung. Respons dengan kredensial tidak dapat menggunakan Access-Control-Allow-Origin: *, dan respons preflight tidak mengizinkan Content-Type atau X-CSRF-Token. Mencantumkan POST di bawah metode yang diizinkan saja tidak cukup.

Terakhir, kandidat harus menjaga batasan keamanan. CORS mengontrol apakah peramban membagikan respons lintas-asal kepada skrip. Ini tidak menggantikan autentikasi, otorisasi, atau perlindungan CSRF. Server tidak boleh merefleksikan sembarang origin hanya untuk membungkam konsol atau mengizinkan setiap metode dan header.

Pertanyaan untuk Diklarifikasi Terlebih Dahulu

  • Pada fase jaringan mana kegagalan terjadi? Tidak ada permintaan, hanya OPTIONS, atau POST selesai yang responsnya

tidak dapat diakses oleh JavaScript menunjukkan kegagalan yang berbeda.

  • Apakah permintaan harus membawa cookie? Bearer token atau sumber daya publik anonim mengubah kebijakan

kredensial dan origin yang diizinkan.

  • Origin frontend mana saja yang secara tepat diizinkan? Produksi, staging, dan pengembangan lokal memerlukan origin

eksplisit, termasuk skema dan port. “Domain perusahaan” tidak cukup presisi.

  • Apakah gateway, middleware autentikasi, atau pengalihan (redirect) mencegat OPTIONS? Preflight biasanya tidak memiliki

kredensial pengguna, sehingga tidak boleh diwajibkan untuk lolos autentikasi login terlebih dahulu.

  • Apa saja atribut Domain, Path, Secure, dan SameSite pada cookie? Lolos CORS tidak menjamin

bahwa peramban mengirimkan cookie.

  • Apakah respons aktual dan galat semuanya membawa header CORS? Jika respons 401, 403, atau 500 kehilangan header origin

yang diizinkan, peramban mungkin menyembunyikan status aslinya di balik galat CORS generik.

  • Apakah ada CDN atau cache bersama? Jika respons bervariasi berdasarkan Origin, kirimkan Vary: Origin sehingga respons satu origin

tidak digunakan kembali untuk origin lain.

Kerangka Jawaban 30 Detik

“Saya akan membagi ini menjadi empat gerbang: origin, izin preflight, pengiriman kredensial, dan pembagian respons. Host-nya berbeda, jadi permintaan tersebut berstatus cross-origin. Content-Type JSON dan X-CSRF-Token memicu preflight OPTIONS. Peramban mengirimkan POST hanya jika respons mengizinkan origin yang tepat, POST, dan kedua header tersebut. Karena fetch menggunakan credentials: include, Allow-Origin tidak boleh berupa wildcard. Setelah pencocokan allowlist yang tepat, server harus mengembalikan https://app.example.com, Allow-Credentials, dan Vary: Origin. OPTIONS itu sendiri tidak bergantung pada cookie login; POST tetap memerlukan autentikasi, otorisasi, dan validasi CSRF. Saya akan memverifikasi OPTIONS, POST, cookie, header respons, dan status aplikasi di panel Network, lalu menjalankan matriks pengujian untuk origin positif dan origin berbahaya.”

Pembahasan Mendalam Langkah demi Langkah

Langkah satu: memodelkan state machine yang benar-benar dijalankan oleh peramban.

Preflight kira-kira berbentuk:

http
OPTIONS /profile/preferences HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-csrf-token

Peramban tidak menanyakan apakah frontend dan backend milik perusahaan yang sama. Peramban menanyakan apakah respons secara eksplisit mengizinkan Origin, metode, dan kumpulan header ini. Bukti berikut mengisolasi setiap fase:

Bukti jaringanArtiPemeriksaan berikutnya
Tidak ada OPTIONS atau POSTJavaScript tidak berjalan, atau aturan sebelumnya seperti CSP memblokir URLPeriksa pemanggilan dan konsol terlebih dahulu
Hanya OPTIONS yang gagalPOST tidak dikirimPeriksa status, pengalihan, dan header allow
OPTIONS berhasil; POST tidak memiliki cookieIzin CORS lolos; pengiriman kredensial tidakPeriksa credentials dan atribut cookie
POST mengembalikan 401/403/500, tetapi skrip hanya melihat CORSRespons galat tidak memiliki header CORS yang validPertahankan status dan tambahkan header origin yang diizinkan
POST berhasil dan skrip dapat membacanyaJalur CORS lolosVerifikasi status aplikasi dan uji negatif keamanan

Langkah dua: menurunkan kumpulan izin minimum dari permintaan.

Untuk satu frontend produksi pada pertanyaan tersebut, kembalikan:

http
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, X-CSRF-Token
Vary: Origin

Server harus membandingkan Origin dengan allowlist yang tepat dan menuliskannya kembali hanya setelah cocok. Jangan menyalin Origin yang diberikan klien tanpa syarat. Jika lingkungan staging dan lokal juga diizinkan, cantumkan setiap origin lengkap di lingkungan yang sesuai. Pencocokan akhiran (suffix match) dapat menerima domain penyerang yang tampak serupa.

Wildcard dapat sesuai untuk sumber daya publik, anonim, dan tanpa kredensial. Endpoint preferensi pengguna ini membawa cookie dan melakukan operasi sensitif, sehingga memerlukan origin yang spesifik. Preflight OPTIONS tidak membawa cookie. Gateway dapat menanganinya sebelum autentikasi sambil tetap memvalidasi Origin, metode, dan header permintaan secara ketat.

Langkah tiga: periksa permintaan aktual dan kredensial secara terpisah.

Peramban mengirim POST hanya setelah preflight berhasil. credentials: "include" memungkinkan permintaan lintas-asal masuk ke pemrosesan kredensial, tetapi Domain, Path, Secure, SameSite, dan kebijakan privasi peramban tetap menentukan apakah cookie disertakan.

Kedua subdomain HTTPS ini biasanya berstatus same-site dan cross-origin. SameSite mungkin mengizinkan cookie sementara CORS tetap berlaku. “CORS lolos” tidak berarti “cookie terkirim,” dan “cookie terkirim” tidak berarti “skrip boleh membaca respons.” Periksa Request Cookies, status respons, dan header respons CORS sebagai fakta terpisah di panel Network.

Langkah empat: pisahkan CORS dari keamanan aplikasi.

CORS adalah protokol pembagian respons peramban, bukan kontrol akses sisi server. Curl dan klien HTTP sisi server tidak menerapkan kebijakan origin yang sama (same-origin policy) peramban. Pemanggilan curl yang berhasil membuktikan bahwa API dapat menangani permintaan tersebut, bukan bahwa jalur peramban sudah benar.

POST tetap harus:

  • mengautentikasi pengguna;
  • mengotorisasi pengguna tersebut untuk memodifikasi sumber daya target;
  • memvalidasi token CSRF atau menggunakan pertahanan yang sama kuatnya;
  • memvalidasi input dan mendefinisikan perilaku idempotensi atau pengiriman ganda;
  • mengembalikan header CORS yang benar pada respons 401, 403, dan 500 untuk origin yang diizinkan agar frontend melihat galat yang sebenarnya.

“Halaman berbahaya tidak dapat membaca respons” tidak berarti “permintaan tidak memiliki efek samping.” Beberapa permintaan lintas-asal mirip-formulir tidak memerlukan preflight dan dapat mencapai server. Operasi penulisan sensitif tidak dapat mengandalkan CORS saja untuk perlindungan CSRF.

Langkah lima: buktikan batasan dengan pengujian positif dan negatif.

Setelah perbaikan, verifikasi setidaknya:

KasusHasil yang diharapkan
Origin yang diizinkan mengirimkan permintaan yang ditentukanOPTIONS 204, lalu POST; skrip membaca respons sebenarnya
Origin yang diizinkan menghilangkan token CSRFKonfigurasi protokol menentukan preflight; validasi aplikasi menolak penulisan
Origin yang tidak diizinkan mengirimkan permintaan yang samaTidak ada header CORS yang mengizinkan origin tersebut; preflight tidak lolos
Permintaan menggunakan metode atau header yang tidak diizinkanPreflight gagal, POST tidak ada, dan status tidak berubah
Cookie login kedaluwarsaPOST mengembalikan 401 yang dapat dibaca dan frontend memulai alur login-nya
Server mengembalikan 500Frontend melihat 500 dan galat terstruktur, bukan pesan CORS generik
Permintaan berulang menggunakan cache preflightPerilaku tetap benar; perubahan konfigurasi juga diuji dengan cache dingin

Korelasikan ini dengan log server. Preflight yang gagal tidak boleh memiliki POST yang cocok dan tidak ada pembaruan preferensi. Log dapat mencatat Origin, metode, nama header, dan alasan penolakan, tetapi bukan nilai cookie atau token CSRF.

Contoh Jawaban yang Kuat

“Saya pertama-tama akan mengidentifikasi fase jaringan. app.example.com dan api.example.com memiliki host yang berbeda, jadi keduanya berstatus cross-origin meskipun same-site. POST menggunakan Content-Type JSON dan X-CSRF-Token, sehingga peramban pertama-tama mengirimkan permintaan OPTIONS tanpa cookie. Permintaan ini mendeklarasikan Origin, POST, dan dua header non-sederhana tersebut. Peramban mengirimkan POST hanya jika respons preflight mengizinkan ketiganya.

Konfigurasi saat ini memiliki dua cacat langsung. Pertama, frontend menetapkan credentials: include, sehingga respons berkredensial tidak dapat menggunakan wildcard untuk Access-Control-Allow-Origin. Kedua, respons tidak mencakup Access-Control-Allow-Headers: Content-Type, X-CSRF-Token. Saya akan memvalidasi Origin terhadap allowlist server yang tepat. Untuk https://app.example.com, saya akan mengembalikan nilai spesifik tersebut, Allow-Credentials, POST, kedua header yang diizinkan, dan Vary: Origin. OPTIONS dapat ditangani sebelum middleware autentikasi pengguna, tetapi origin, metode, atau header yang tidak diizinkan tetap ditolak.

Setelah preflight lolos, saya akan memeriksa Request Cookies pada POST. credentials: include diperlukan tetapi tidak cukup; Domain, Path, Secure, SameSite, dan kebijakan peramban tetap berlaku. POST harus terus mengautentikasi, mengotorisasi, dan memvalidasi CSRF karena CORS mengontrol pembagian respons, bukan kontrol akses.

Untuk verifikasi, saya akan mengonfirmasi di panel Network bahwa POST hanya muncul setelah OPTIONS berhasil, lalu memeriksa cookie, status sebenarnya, dan header respons. Saya akan menguji origin yang diizinkan, origin yang tidak diizinkan, metode yang tidak diizinkan, login yang kedaluwarsa, dan respons 500. Log server harus membuktikan bahwa preflight yang gagal tidak memiliki POST dan tidak ada perubahan status. Curl adalah baseline API, bukan pengganti bukti CORS peramban.”

Kesalahan Umum

  • Menganggap same-site sebagai same-origin → Subdomain yang berbeda tetap memicu CORS → **Bandingkan skema, host,

dan port.**

  • Mengasumsikan POST dalam Allow-Methods sudah cukup → Header non-sederhana tidak diizinkan → **Periksa Origin,

Method, dan Headers secara bersamaan.**

  • Menggunakan Allow-Origin: * dengan kredensial → Peramban menolak untuk mengekspos respons → **Kembalikan

origin allowlist yang tepat.**

  • Merefleksikan setiap Origin yang diminta → Situs mana pun dapat memperoleh akses baca ke respons berkredensial → **Cocokkan

allowlist yang tepat terlebih dahulu.**

  • Mengautentikasi OPTIONS sebagai pengguna yang login → Preflight biasanya tidak memiliki kredensial → **Lakukan

pemeriksaan preflight yang dibatasi sebelum autentikasi pengguna.**

  • Menggunakan mode: "no-cors" sebagai perbaikan → Frontend menerima respons buram (opaque response) yang tidak dapat dibaca → **Perbaiki

protokol CORS server.**

  • Memperlakukan CORS sebagai perlindungan CSRF → Permintaan dapat mencapai server dan menimbulkan efek samping → **Pertahankan CSRF

dan pemeriksaan otorisasi pada operasi penulisan sensitif.**

  • Menambahkan header CORS hanya ke respons 2xx → Respons 401 atau 500 tersamarkan sebagai galat lintas-asal → **Gunakan

header CORS yang konsisten pada galat untuk origin yang diizinkan.**

  • Hanya menguji dengan curl → Curl tidak menerapkan kebijakan same-origin peramban → **Verifikasi dengan bukti

jaringan peramban yang sebenarnya.**

Pertanyaan Lanjutan

Mengapa permintaan dapat melewati OPTIONS dan tetap gagal CORS?

Permintaan yang menggunakan metode, header, dan Content-Type yang masuk safelist dapat dikirim secara langsung. Peramban tetap memeriksa header CORS respons aktual. Jika pembagian respons tidak diizinkan, JavaScript tidak dapat membacanya meskipun server mungkin telah memprosesnya. Bukti jaringan harus membedakan antara “terkirim tetapi tidak dibagikan” dari preflight yang gagal.

Mengapa Access-Control-Allow-Credentials tidak boleh muncul dalam permintaan preflight?

Ini adalah header respons server yang menunjukkan bahwa peramban boleh mengekspos respons aktual yang dibuat dalam mode kredensial. Klien menyatakan niatnya melalui mode kredensial Fetch; preflight itu sendiri tidak berisi kredensial pengguna. Respons aktual juga harus memenuhi ketentuan origin spesifik dan Allow-Credentials.

Masalah apa yang diselesaikan oleh Vary: Origin?

Ketika server memilih Access-Control-Allow-Origin berdasarkan Origin permintaan, cache bersama harus menyertakan Origin dalam kunci cache-nya. Jika tidak, respons untuk satu origin yang diizinkan dapat digunakan kembali untuk origin lain, menyebabkan penolakan atau pengungkapan data yang salah.

Mengapa cookie masih hilang setelah CORS diperbaiki?

Periksa credentials: "include", lalu periksa Domain, Path, Secure, SameSite, masa kedaluwarsa cookie, dan pembatasan privasi peramban. Izin CORS dan pengiriman cookie adalah gerbang yang berdampingan tetapi independen.

Bagaimana cara mendukung beberapa domain frontend yang sah?

Pertahankan allowlist yang tepat, validasi Origin permintaan lengkap, tulis kembali nilai yang cocok, dan kirimkan Vary: Origin. Jangan mengembalikan beberapa nilai Allow-Origin atau menggunakan ekspresi reguler yang permisif, pencocokan akhiran, atau refleksi tanpa syarat.

Bisakah frontend memperbaiki kegagalan CORS server dengan sendirinya?

Tidak. Frontend dapat menghapus header non-sederhana yang tidak perlu atau memilih mode kredensial yang dimaksudkan, tetapi API, reverse proxy, atau gateway harus mengembalikan header respons yang mengizinkan pembagian lintas-asal. Kode produksi tidak boleh bergantung pada ekstensi peramban atau menonaktifkan kontrol keamanan.

Berapa lama preflight harus di-cache?

Pilih durasi berdasarkan perputaran konfigurasi, kebutuhan pencabutan, dan batas peramban. Saat merilis perubahan CORS, uji cache dingin maupun jalur cache yang sudah ada. Caching mengurangi lalu lintas OPTIONS tetapi dapat memperpanjang izin yang salah, sehingga tidak boleh menyembunyikan cacat konfigurasi.

Sumber publik

Pertanyaan terkait