Anatomi JWT: Decode Tidak Sama dengan Verify
JWT punya tiga segmen yang bisa dibaca siapa pun. Tanda tangan membuktikan keaslian, dan melewatkan verifikasi adalah celah keamanan paling umum.
JWT adalah tiga string Base64URL yang dipisah titik: header, payload, signature. Header dan payload bisa dibaca siapa pun tanpa kunci. Itu bukan bug, itu desain — JWT untuk klaim, bukan untuk menyimpan rahasia.
Payload berisi klaim: sub, iss, exp, dan klaim kustom. Semuanya publik. Menaruh data sensitif di payload sama dengan menaruhnya di query string.
Signature yang membuat JWT berguna. Ia dihitung dari header dan payload dengan kunci rahasia (HMAC) atau kunci privat (RSA/ECDSA). Verifikasi memeriksa dua hal: tanda tangan cocok, dan klaim waktu masih valid.
Celah paling umum: memanggil decode lalu mempercayai isinya. Decode hanya membalik Base64. Ia tidak memverifikasi apa pun. Kode yang membaca klaim tanpa memverifikasi tanda tangan menerima token apa pun yang dikirim penyerang.
Serangan klasik: algoritma none. JWT lama menerima alg "none", yang berarti tanpa tanda tangan. Verifier yang mempercayai header alg akan menerima token tanpa signature sebagai valid. Pertahanan: tolak alg none secara eksplisit, dan jangan biarkan header memilih algoritma — server yang menentukan.
Yang juga sering dilupakan: exp tidak diperiksa otomatis oleh decoder. Kamu harus memeriksanya sendiri, dan memutuskan toleransi clock skew.