Studi Kasus Atmo LMS: PKCE dan Webhook Signing Tutup Celah Spoofing Pembayaran dari 7 Insiden ke Nol dalam 60 Hari di 2026
TL;DR: Pada Q1 2026, Atmo LMS mencatat 7 insiden spoofing notifikasi pembayaran lewat endpoint webhook publik plus 2 percobaan code interception di alur login Google OAuth. Pemasangan HMAC signature verification untuk semua webhook gateway dan PKCE di alur OAuth menutup celah dalam 60 hari, dengan zero insiden lanjutan selama 90 hari berikutnya.
Dalam beberapa proyek terakhir, saya melihat pola yang sering luput dari pemilik platform digital di Indonesia. Webhook gateway pembayaran sering dibiarkan menerima request tanpa verifikasi signature, dan alur OAuth public client masih banyak yang belum memakai PKCE. Dua celah ini terlihat kecil, tapi dampaknya bisa langsung ke pendapatan dan kepercayaan user.
Konteks: Endpoint Webhook Tanpa Verifikasi
Atmo LMS menerima notifikasi pembayaran dari Midtrans dan Xendit lewat endpoint webhook publik. Pada Januari 2026, tim ops mendapati 7 transaksi premium berstatus "lunas" tanpa pernah dibayar. Investigasi menunjukkan attacker menebak URL webhook (URL endpoint memang mudah ditemukan di network tab inspector), lalu mengirim payload palsu dengan struktur JSON yang valid. Sistem otomatis melepas akses kursus karena status di body bernilai "settlement".
Solusi: HMAC Signature Verification
Lihat glosarium webhook signing. Setiap penyedia gateway pembayaran Indonesia (Midtrans, Xendit, Doku) mengirim header signature di setiap webhook. Tugas server hanyalah menghitung ulang HMAC SHA-256 dari body memakai server key, lalu membandingkan dengan constant-time compare. Implementasi di Next.js Route Handler:
import crypto from 'crypto';
export async function POST(req: Request) {
const body = await req.text();
const sig = req.headers.get('x-signature') ?? '';
const expected = crypto
.createHmac('sha256', process.env.MIDTRANS_SERVER_KEY!)
.update(body)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
return new Response('Invalid signature', { status: 401 });
}
// proses payload aman
}
Constant-time compare via timingSafeEqual mencegah kebocoran info via timing attack.
Konteks Kedua: OAuth Tanpa PKCE
Alur login Google di Atmo LMS awalnya memakai authorization code flow standar tanpa PKCE. Dua kali tercatat percobaan menukar authorization code curian (kemungkinan dari browser extension yang mencegat redirect URI). Walaupun tidak berhasil karena ada validasi tambahan di backend, tim memutuskan menutup celah ini sebelum eksploitasi nyata terjadi.
| Tahap | Tanpa PKCE | Dengan PKCE |
|---|---|---|
| Generate code_verifier | Tidak | Wajib (43-128 char random) |
| Kirim code_challenge ke /authorize | Tidak | Ya (SHA-256 dari verifier) |
| Tukar code ke token | Hanya butuh code | Butuh code + verifier |
| Risiko code interception | Tinggi | Mitigated |
Auth.js (NextAuth) v5 dan Supabase Auth sudah default mengaktifkan PKCE. Jika memakai library OAuth manual, pastikan parameter code_challenge dan code_challenge_method=S256 dikirim di authorize step, dan code_verifier disertakan di token exchange. Referensi standar ada di RFC 7636.
Hasil 60 Hari
Setelah signature verification dipasang di 3 endpoint webhook (Midtrans, Xendit, Doku) dan PKCE diaktifkan di alur Google plus Microsoft OAuth, monitoring 60 hari berikutnya mencatat:
- 0 insiden spoofing pembayaran (dari 7 di Q1)
- 14 request webhook ditolak otomatis karena signature invalid (semua dari IP non-gateway)
- 0 percobaan code interception berhasil (3 dicegat di tahap token exchange karena verifier tidak cocok)
Tim ops sekarang punya log audit lengkap karena semua signature failure tercatat dengan IP, timestamp, dan path. Ini memudahkan korelasi dengan log gateway saat ada keluhan user.
Pertanyaan Umum
Apakah HTTPS saja sudah cukup untuk webhook?
Tidak. HTTPS mencegah penyadapan di jaringan, tetapi tidak mencegah pihak lain yang tahu URL webhook untuk mengirim payload palsu langsung ke endpoint. Signature verification mengatasi ini.
Apakah PKCE memperlambat login?
Tidak. PKCE menambah satu hash SHA-256 di sisi klien (mikrodetik) dan satu perbandingan di server. Latency tambahan tidak terdeteksi user.
Bagaimana menyimpan code_verifier dengan aman di SPA?
Gunakan sessionStorage (otomatis terhapus saat tab ditutup). Jangan pakai localStorage karena persistent. Library OAuth modern sudah menangani ini.
Apakah perlu rotate webhook secret berkala?
Idealnya ya, setiap 90-180 hari. Kalau infrastruktur belum siap rotation otomatis, minimal rotate saat ada indikasi kompromi atau saat pergantian staff yang punya akses.
Apa lapisan keamanan berikutnya setelah ini?
Rate limiting endpoint webhook, IP allowlist gateway, dan logging signature failure ke alerting tool seperti Sentry atau BetterStack.
Penutup
Dua celah ini, webhook tanpa signature dan OAuth tanpa PKCE, adalah default unsafe yang sering dilewatkan tim kecil karena tidak ada checklist eksplisit. Kabar baiknya, keduanya bisa ditutup dalam waktu kerja kurang dari dua hari developer dan punya dampak langsung ke trust user serta integritas data revenue.
Artikel Terkait
Case Study
Studi Kasus Yuanita Sekar: Pakai view-timeline CSS untuk Scroll Storytelling Naikkan Waktu Baca Personal Brand dari 1,8 ke 4,6 Menit di 2026
Yuanita Sekar mengganti library GSAP 92 KB dengan view-timeline CSS native. Waktu baca halaman naik 156%, LCP turun 1,4 detik, dan engagement scroll depth dari 38% ke 72%.
Case Study
Studi Kasus Felicia Tan: Marketing Mix Modeling Pindahkan 23 Persen Budget dari Meta ke TikTok dan Naikkan Revenue Inkremental 19 Persen di 2026
Marketing Mix Modeling Felicia Tan ungkap Meta over-attributed 31 persen, TikTok under-attributed 18 persen. Realokasi budget hasilkan +19 persen revenue inkremental di 2026.

Case Study
Studi Kasus Vetmo: Incrementality Test Ungkap 34 Persen Spend Iklan Meta Tidak Berkontribusi pada Konversi di 2026
Saat Vetmo lari incrementality test selama 6 minggu, terungkap 34 persen budget Meta hanya menyentuh audiens yang akan beli secara organik. Pelajari metode dan hasilnya.
Butuh website yang benar-benar bekerja?
Hubungi Vito untuk konsultasi gratis 15 menit.
WhatsApp Sekarang