Ketika Tombol Hapus
Tidak Mencabut Tautan Lama.
Menghapus objek dari layar belum tentu mengakhiri kemampuan lama untuk membacanya. Di sinilah desain save, share, delete, dan revoke perlu dipisahkan.
Seluruh identitas sumber, nama layanan, rute, parameter, dan identifier telah dihapus. Eksperimen menggunakan objek sintetis milik peneliti dan tidak menyentuh data pihak lain.
Bayangkan pengguna menyimpan konfigurasi, memperoleh tautan panjang, lalu menekan tombol hapus. Antarmuka menyatakan objek sudah hilang. Pertanyaan keamanan yang lebih penting bukan hanya “apakah kartu di dashboard menghilang?”, melainkan “apakah seluruh kemampuan lama untuk mengambil objek itu ikut dicabut?”
Save bukan otomatis share
Banyak produk memakai identifier berentropi tinggi sebagai capability: siapa pun yang memegang nilai tersebut dapat meminta objek tanpa sesi yang sama. Pola ini dapat sah untuk berbagi cepat, tetapi maknanya harus eksplisit. Jika tombolnya bernama simpan, pengguna mungkin menganggap objek terikat akun. Jika sebenarnya sistem menghasilkan bearer link, keputusan produk sudah bergeser dari penyimpanan pribadi menjadi distribusi capability.
Capability bukan sekadar ID. Ia adalah gabungan acquisition, possession, operation, state, dan waktu. Daftar inventaris harus menjawab siapa memperoleh tautan, tindakan apa yang dibolehkan, apakah ada expiry, apakah penggunaan dibatasi, serta transisi mana yang mencabutnya. Tanpa inventaris ini, UI dan backend mudah memiliki definisi lifecycle berbeda.
Identifier yang sulit ditebak mengurangi peluang penemuan, tetapi tidak menjawab apakah akses lama harus berakhir setelah delete.
Eksperimen satu variabel
Baseline menggunakan objek konfigurasi sintetis bersensitivitas rendah. Objek dapat dibaca melalui capability yang sudah dimiliki pada sesi terpisah. Kontrol negatif memakai identifier mustahil dan menghasilkan respons kosong. Dengan begitu, pembacaan baseline tidak cukup dijelaskan oleh halaman publik generik atau cache halaman yang sama untuk semua input.
Satu variabel kemudian diubah: objek dihapus melalui alur resmi. Antarmuka melaporkan keberhasilan. Capability lama dicoba kembali dari sesi anonim baru, bukan hanya tab yang masih menyimpan state. Objek yang sama masih terbaca. Pengamatan tersebut direproduksi setelah jeda panjang. Itu membuktikan perilaku lifecycle yang nyata, tetapi belum otomatis membuktikan kerentanan karena kontrak produk tentang delete, retention, dan public link belum ditetapkan secara otoritatif.
Capability lama adalah pusat pertanyaan
Tim sering memusatkan pengujian pada enumerasi. Padahal identifier acak dapat sepenuhnya tahan tebakan dan tetap memiliki masalah revocation. Pertanyaan yang berbeda harus diuji terpisah: apakah capability dapat diperoleh tanpa hak, apakah ia dapat diteruskan, apakah terikat akun atau perangkat, berapa lama berlaku, dan apakah delete benar-benar menonaktifkannya.
Dalam pengamatan ini tidak ada enumerasi, tidak ada identifier orang lain, tidak ada privilege, dan tidak ada data sensitif. Karena itu status yang jujur adalah perilaku boundary terkonfirmasi dengan klasifikasi dampak masih terbuka. Nilainya bagi engineering tetap besar: tim memperoleh tes konkret untuk menyelaraskan makna produk dan implementasi.
Delete, revoke, dan retention
Delete dapat berarti setidaknya empat hal: menghilangkan referensi dari dashboard, menandai record sebagai terhapus, menjadwalkan penghapusan penyimpanan, atau meniadakan seluruh kemampuan baca. Revoke memiliki tujuan lebih sempit: capability yang sebelumnya sah tidak boleh lagi digunakan. Retention menentukan apakah data masih disimpan untuk pemulihan, audit, atau kewajiban operasional. Ketiganya tidak boleh disamarkan sebagai satu tombol tanpa penjelasan.
Arsitektur yang kuat memisahkan record objek dari record capability. Saat delete dipilih, server dapat memindahkan objek ke state tombstone sekaligus menonaktifkan seluruh capability aktif. Jika retention dibutuhkan, data boleh bertahan secara internal dengan kontrol akses berbeda, tetapi jalur publik lama harus mengikuti keputusan revocation yang terdefinisi.
Kontrol yang dapat diterapkan
- Buat capability inventory yang mencatat owner, purpose, scope, expiry, dan revoked_at.
- Bedakan tombol Simpan, Bagikan, Hapus dari daftar, dan Cabut semua tautan.
- Terapkan pemeriksaan state pada setiap read, bukan hanya ketika link dibuat.
- Gunakan audit event untuk create, access, share, revoke, dan delete.
- Uji sesi baru, perangkat baru, delayed readback, serta cache dan origin secara terpisah.
Komunikasi lifecycle adalah kontrol keamanan
Jika tautan memang dirancang permanen, UI perlu mengatakannya sebelum pengguna menaruh data. Jika delete hanya menghapus tampilan, gunakan bahasa yang tepat dan sediakan revoke. Jika link akan kedaluwarsa, tampilkan masa berlaku. Transparansi mengurangi false expectation dan membantu support menjelaskan kejadian tanpa mengandalkan asumsi.
Pelajaran utamanya sederhana: tombol bukan authority. Authoritative readback setelah transisi state menentukan apa yang benar-benar terjadi. Uji lifecycle harus mengikuti capability lama sampai server menolaknya, bukan berhenti ketika komponen UI menghilang.
Checklist untuk tim produk
Mulailah dari invariant: setelah pengguna memilih tindakan tertentu, aktor mana masih boleh membaca objek melalui capability mana, dalam state dan waktu apa? Pertahankan baseline sukses, ubah satu transisi, gunakan identifier mustahil sebagai kontrol, reproduksi dari konteks baru, lalu periksa penyimpanan atau API canonical. Jika semantik produk masih ambigu, perbaiki kontraknya sebelum memberi label keamanan.
Riset seperti ini tidak membutuhkan data korban agar berguna. Objek sintetis sudah cukup untuk memperlihatkan ketidaksinkronan antara bahasa UI dan perilaku server. Yang penting adalah tidak melebihkan klaim: capability lama terbukti bertahan; niat produk dan dampak material masih harus diputuskan melalui bukti tambahan.
Uji apa yang terjadi setelah tombol ditekan.
CyberSecAudit memetakan capability, state transition, revocation, dan authoritative readback tanpa mengandalkan asumsi UI.