Clickjacking & UI Redressing — Security

Apa itu Clickjacking? Clickjacking (UI Redressing) adalah serangan di mana penyerang membuat halaman web yang menipu pengguna untuk mengklik sesuatu yang…

Clickjacking (kadang disebut UI redressing, "mendandani ulang tampilan") adalah serangan yang menipumu agar mengklik sesuatu yang berbeda dari yang kamu lihat. Caranya: halaman asli disembunyikan di dalam frame transparan, ditaruh pas di atas tombol umpan. Bayangin kaca bening yang ditempel di atas poster: kamu mengira menekan tombol di poster, padahal jarimu menyentuh kaca yang menutupinya. Yang kamu lihat poster, yang kamu sentuh kaca.

🧪 Tebakan cepat: sebuah halaman memuat bank.example di dalam <iframe>, lalu bikin iframe itu transparan (opacity: 0) dan menaruhnya di atas tombol "Klaim Hadiah". Satu HTTP header di bank.example bisa bikin iframe ini gak pernah tampil. Header apa? Tebak dulu, jawabannya ada di bagian "Dua header yang menolak dibingkai".

Gimana jebakannya tersusun

Di Lab semua ini terjadi di dalam kanvas Lab sendiri: ada "halaman umpan" dan "halaman bank", dua-duanya milik Lab, bukan situs sungguhan. Halaman umpan punya tombol besar "Klaim Hadiah". Di atasnya, sebuah iframe memuat tombol "Konfirmasi Transfer" dari halaman bank.

Tiga potong CSS yang menyusun jebakan:

.jebakan {
  position: absolute; /* lepas dari aliran, bisa ditaruh di mana saja */
  top: 0; left: 0;
  width: 100%; height: 100%;
  opacity: 0;   /* transparan: iframe-nya gak kelihatan */
  z-index: 10;  /* di atas tombol umpan */
}

Waktu kamu mengklik tombol "Klaim Hadiah", jarimu sebenarnya jatuh ke tombol "Konfirmasi Transfer" di iframe transparan. Kamu login di bank, jadi bank memproses klik itu seolah kamu sendiri yang menekannya. Itulah "jacking": klikmu dibajak ke tempat lain.

Jenis-jenisnya satu pola yang sama, beda sasaran: like/follow jacking (tanpa sadar nge-like akun penyerang), payment jacking (klik tombol bayar tersembunyi), dan permission jacking (klik tombol "Izinkan" di dialog kamera atau mikrofon).

Dua header yang menolak dibingkai

Clickjacking butuh satu syarat: halaman korban boleh dimuat di dalam iframe situs lain. Pertahanannya memotong syarat itu, yaitu melarang halaman dibingkai. Ada dua header, dikirim server bersama halaman:

# Cara lama, masih didukung semua browser
X-Frame-Options: DENY

# Cara modern, lewat Content-Security-Policy
Content-Security-Policy: frame-ancestors 'none'

X-Frame-Options punya dua nilai yang dipakai:

frame-ancestors di CSP lebih fleksibel dan mengganti X-Frame-Options:

Kalau bank.example mengirim salah satu header ini, browser menolak menampilkan iframe-nya: frame-nya kosong, dan jebakan runtuh. Itu jawaban tebakannya: X-Frame-Options (atau frame-ancestors).

Bedanya penting: X-Frame-Options cuma bisa "semua atau origin sendiri", sedangkan frame-ancestors bisa menyebut beberapa origin tertentu. Pasang keduanya kalau mau aman di browser lama sekalipun. Kalau dua-duanya dikirim, frame-ancestors yang diutamakan: browser yang mendukungnya mengabaikan X-Frame-Options. Perhatikan: ini header yang dikirim halaman yang dilindungi (bank.example), bukan halaman penyerang. Penyerang gak akan memasangnya.

Memasang header di server

Di server Express, satu middleware memasang header ini di setiap response:

app.use((req, res, next) => {
  res.setHeader("X-Frame-Options", "DENY");
  res.setHeader("Content-Security-Policy", "frame-ancestors 'none'");
  next();
});

💡 Frame-busting JavaScript sebagai cadangan

Kalau karena satu alasan header gak bisa dipasang, ada cara cadangan di sisi klien. Halaman mengecek apakah dirinya sedang berada di dalam frame:

if (window.self !== window.top) {
  // Halaman ini sedang dibingkai: paksa keluar.
  window.top.location = window.self.location;
}

Ini cuma cadangan, karena bisa diakali. Header jauh lebih kuat: browser yang menolak membingkai, bukan script yang berharap sempat jalan.

⚠️ Jebakan yang sering ketemu

TL;DR: Clickjacking menyembunyikan halaman korban di iframe transparan (opacity: 0, z-index tinggi) di atas tombol umpan, jadi klikmu jatuh ke tombol yang gak kamu lihat. Pertahanannya melarang halaman dibingkai, dengan dua header yang dikirim halaman yang dilindungi: X-Frame-Options: DENY (atau SAMEORIGIN) untuk semua browser, dan Content-Security-Policy: frame-ancestors 'none' (atau 'self', atau origin tertentu) untuk browser modern. frame-ancestors lebih fleksibel karena bisa menyebut origin tertentu. Frame-busting JavaScript cuma cadangan. Jangan lupa: header dipasang di halamanmu, bukan di halaman penyerang.

Yang akan kamu pelajari