Keamanan6 Agustus 20268 mnt baca

Webhook Pencabutan Akses yang Hilang Adalah Insiden Keamanan, Bukan Celah Data

Lewatkan access.granted, pengguna membuat tiket. Lewatkan access.revoked, tidak ada yang sadar: dari luar semua tetap jalan. Uptime adalah kontrol akses.

JIKA PEMBERIAN AKSES HILANGaccess.grantedtidak pernah tibapengguna buka tiket. Anda perbaiki dalam sejam.JIKA PENCABUTAN AKSES HILANGaccess.revokedtidak pernah tibatidak ada yang buka tiket, karena dariluar semuanya masih berfungsi.
Event yang sama-sama hilang, dua akibat yang sangat berbeda. Hanya satu yang memicu keluhan.

Sebagian besar tulisan tentang keandalan webhook memperlakukan event yang hilang sebagai masalah data. Satu baris hilang, lambat laun Anda menyadarinya, lalu Anda melakukan backfill. Menyebalkan, bisa dipulihkan, dan sebagian besar tidak terlihat bagi siapa pun di luar tim engineering.

Event identitas mematahkan cara pandang itu, karena kedua arahnya tidak simetris.

Event access.granted yang tidak pernah tiba menghasilkan pengguna yang tidak bisa masuk, dan pengguna yang tidak bisa masuk akan memberi tahu Anda dalam hitungan menit. Masalah ini melaporkan dirinya sendiri. Sistemnya punya lapisan peringatan berupa manusia, terpasang gratis.

Event access.revoked yang tidak pernah tiba menghasilkan pengguna yang masih bisa masuk. Tidak ada yang melaporkannya. Orang yang diuntungkan tidak punya alasan untuk menyebutnya, dan semua orang lain percaya offboarding sudah selesai karena identity provider Anda mengatakan begitu. Celah itu bertahan sampai audit menemukannya, dan itu bisa setahun kemudian.

TL;DR

  • Melewatkan pemberian akses berarti satu tiket support. Melewatkan pencabutan akses berarti pintu terbuka tanpa alarm
  • Dashboard identity provider Anda menunjukkan pencabutan berhasil, karena di sisi mereka memang berhasil
  • Clerk, dan apa pun yang dibangun di atas Svix, melakukan 8 upaya dalam sekitar 27,5 jam, lalu menonaktifkan endpoint setelah 5 hari gagal total
  • Endpoint yang dinonaktifkan itu sendiri adalah keadaan yang senyap, dan justru keadaan inilah yang paling penting
  • Perlakukan ketersediaan penerima webhook sebagai kontrol akses, bukan sekadar kebersihan infrastruktur

Kegagalan yang tidak bisa ditunjukkan dashboard

Seorang admin mengeluarkan seseorang dari organisasi. Identity provider memperbarui catatannya sendiri, membatalkan sesinya sendiri, lalu mengirim organizationMembership.deleted atau user.deleted atau session.revoked ke endpoint Anda.

Endpoint Anda sedang di tengah deploy dan mengembalikan 502.

JIKA PEMBERIAN AKSES HILANGaccess.grantedtidak pernah tibapengguna buka tiket. Anda perbaiki dalam sejam.JIKA PENCABUTAN AKSES HILANGaccess.revokedtidak pernah tibatidak ada yang buka tiket, karena dariluar semuanya masih berfungsi.

Di konsol identity provider, keanggotaan itu sudah hilang. Dari sudut pandang admin, offboarding sudah selesai. Aplikasi Anda masih menyimpan baris yang menyatakan orang ini anggota organisasi tersebut, dan sesi ter-cache atau token API apa pun yang Anda terbitkan berdasarkan pemberian akses awal masih berlaku.

Tidak ada tampilan error di mana pun yang dilihat manusia. Log webhook milik provider memang berisi satu pengiriman yang gagal, tetapi tidak ada yang membaca log webhook kecuali sudah mencurigai sesuatu.

Percobaan ulang (retry) memberi Anda waktu, lalu berhenti

Clerk mengirim webhook-nya lewat Svix, dan cukup banyak produk identitas dan infrastruktur lain melakukan hal yang sama. Jadwalnya publik dan layak diketahui dengan tepat, karena jadwal itulah yang menentukan berapa lama tepatnya endpoint Anda boleh rusak sebelum Svix berhenti mencoba ulang sebuah pencabutan akses.

Delapan upaya: “Segera, 5 detik, 5 menit, 30 menit, 2 jam, 5 jam, 10 jam, 10 jam (dihitung dari upaya sebelumnya).”

Itu sekitar 27,5 jam cakupan, yang memang murah hati, dan termasuk yang terpanjang di antara semua pengirim di referensi provider webhook kami. Jendela deploy, insiden, hari Jumat yang buruk: semuanya tertampung dengan nyaman. Setelah upaya kedelapan, Svix mengirim webhook operasional berjenis message.attempt.exhausted, yang hanya berguna jika Anda punya tujuan untuk webhook operasional.

Lalu ada ambang kedua: “Jika semua upaya ke endpoint tertentu gagal selama 5 hari, endpoint akan dinonaktifkan dan webhook operasional (EndpointDisabledEvent) akan dikirim ke akun Anda.” Penghitung waktunya punya syarat: “Penghitung waktu baru mulai setelah beberapa pengiriman gagal dalam rentang 24 jam, dengan selisih minimal 12 jam antara kegagalan pertama dan terakhir.”

Baca keadaan nonaktif itu dengan cermat. Begitu endpoint dinonaktifkan, event baru tidak dimasukkan ke antrean untuknya. Event itu tidak dikirim belakangan saat Anda memperbaiki endpoint. Setiap pencabutan akses selama jendela itu tetap tidak terkirim sampai ada yang menyadarinya dan mengirimnya ulang, dan satu-satunya pemberitahuan adalah webhook operasional yang dikirim ke akun yang tujuannya tidak pernah dikonfigurasi siapa pun.

Asimetri ini adalah masukan desain

Begitu Anda menerima bahwa kedua arah itu membawa biaya yang berbeda, beberapa keputusan biasa ikut berubah.

Terapkan fail closed pada event yang mencabut akses. Jika handler Anda tidak bisa memproses session.revoked, perilaku yang benar bukanlah mengembalikan 200 lalu mencatat peringatan. Kembalikan 5xx agar jadwal percobaan ulang berjalan, dan pastikan peringatan Anda sendiri menyala. Untuk pemberian akses, Anda boleh optimis. Untuk pencabutan akses, tidak.

Jangan hanya mengandalkan webhook. Event push adalah optimasi latensi, bukan sumber kebenaran. Rekonsiliasi berkala terhadap API identity provider, yang bertanya “siapa yang saat ini seharusnya punya akses”, mengubah pencabutan akses yang terlewat secara permanen menjadi pencabutan yang pulih sendiri pada sapuan berikutnya. Itu argumen hybrid yang sama dengan Webhook vs Polling, dan identitas adalah kasus ketika pola itu tidak lagi opsional. Jalankan setiap jam, dan kasus terburuknya adalah satu jam akses basi, bukan selamanya.

Buat sesi Anda sendiri kedaluwarsa. Jika aplikasi Anda menerbitkan sesi atau token sendiri berdasarkan event identitas, TTL yang pendek dengan refresh yang memeriksa ulang keanggotaan berarti pencabutan akses yang terlewat akan kedaluwarsa dengan sendirinya. Token berumur panjang mengubah satu webhook yang hilang menjadi akses tanpa batas waktu.

Urutan juga penting di sini. member.added yang dicoba ulang setelah member.removed akan menambahkan kembali orang yang baru saja Anda keluarkan, padahal tidak ada event yang diproses dua kali. Pola version guard, yaitu menerapkan pembaruan hanya jika stempel waktunya (timestamp) lebih baru daripada milik baris itu, ada di Anda Menerima Webhook yang Sama Dua Kali. Untuk kontrol akses, lebih baik langsung menolak transisi status yang tidak sah daripada mengandalkan perbandingan stempel waktu.

Ketahui seperti apa tandanya saat endpoint Anda dinonaktifkan. Inilah peringatan yang paling berharga di seluruh kategori ini. Jika webhook identitas Anda sepi lebih lama dari jeda normalnya, ada yang salah, dan “sepi” adalah gejala persis dari keadaan nonaktif. Pemeriksaan “tidak ada event identitas dalam 6 jam selama jam kerja” akan menangkapnya. Tidak ada cara lain yang bisa.

Apa yang harus dilakukan soal pertanyaan audit

Jika Anda menangani SOC 2, ISO 27001, atau kuesioner keamanan pelanggan apa pun, ada pertanyaan tentang deprovisioning yang tepat waktu. Jawaban jujurnya, jika jalur pencabutan akses Anda hanyalah satu webhook tanpa rekonsiliasi, adalah bahwa deprovisioning terjadi dengan segera kecuali ketika diam-diam tidak terjadi, dan Anda tidak bisa membedakannya setelah kejadian.

Itu hal yang sulit dituliskan. Namun bisa diperbaiki dengan dua komponen: log persisten dari setiap event identitas yang tiba, dan job rekonsiliasi yang hasilnya bisa Anda tunjukkan. Log menjawab “apa yang diberitahukan kepada kami, dan kapan”; sapuan menjawab “dan apakah kami menindaklanjutinya.” Kami menulis mengapa baris database yang bisa diubah adalah jawaban yang lemah untuk pertanyaan pertama dalam Log Webhook yang Tamper-Evident.

Peran AnyHook

Masalah strukturalnya adalah ketersediaan penerima Anda telah menjadi bagian dari kontrol akses Anda, dan penerima yang dibangun di atas infrastruktur aplikasi mewarisi uptime aplikasi.

Mengarahkan identity provider ke in.anyhook.net/you/identity memisahkan keduanya. AnyHook mengonfirmasi penerimaan dan menyimpan secara persisten di edge (Cloudflare Worker AnyHook di in.anyhook.net) dalam sekitar satu detik, jadi deploy, cold start, atau gangguan database di sisi Anda sama sekali tidak menghasilkan pengiriman yang gagal. Dari sana:

  • Percobaan ulang ke endpoint Anda sendiri berjalan pada 5 menit, 30 menit, 3 jam, 18 jam, lalu setiap hari. Di Scale (sekitar 6 hari) rentang itu melampaui 27,5 jam milik Svix; di Pro upaya terakhir terjadi pada sekitar 22 jam dan di Free pada 35 menit, dan setelah itu event yang tersimpan itulah yang Anda putar ulang (replay)
  • Setiap pencabutan akses disimpan sebelum pengiriman dicoba, dienkripsi saat disimpan (at rest), jadi pertanyaan “apakah kami pernah menerimanya” punya jawaban yang tidak bergantung pada log aplikasi Anda
  • Memutar ulang event dalam satu rentang waktu mengubah jendela deploy yang rusak menjadi satu kali putar ulang, bukan audit manual tentang siapa yang seharusnya sudah kehilangan akses
  • Peringatan kegagalan pada 1, 5, dan 20 kegagalan berturut-turut tiba jauh sebelum ambang penonaktifan provider mana pun

Semua ini tidak menghapus kebutuhan akan sapuan rekonsiliasi, dan Anda tetap harus menjalankannya. Relay menyimpan setiap event yang diterimanya; hanya sapuan yang bisa menangkap apa yang tidak pernah dikirim.

Kesimpulan

Pemberian akses memperbaiki dirinya sendiri karena orang yang terdampak mengeluh. Pencabutan akses tidak, karena orang yang terdampak tidak mengeluh. Satu asimetri itulah alasan webhook identitas layak mendapat standar keandalan yang lebih ketat daripada integrasi Anda yang lain, meskipun payload-nya terlihat sama.

Terapkan fail closed pada pencabutan, buat sesi Anda sendiri kedaluwarsa, jalankan sapuan rekonsiliasi, dan pasang peringatan untuk keheningan yang tidak terduga. Alternatifnya adalah kontrol keamanan yang mode kegagalannya berupa keheningan.

Semua artikel6 Agustus 2026 · 8 mnt

Berhenti kehilangan webhook.

Ganti satu URL. Dapatkan percobaan ulang, log event, dan putar ulang sekali klik. Atau lihat dulu: daftar dan jalankan latihan gangguan 30 detik, lalu saksikan event tetap selamat saat server Anda mati. Tidak perlu server.