Skip to content
Kembali ke Blog
Keamanan

Praktik Terbaik Keamanan JWT: Serangan dan Pertahanan

Amankan JWT Anda: hentikan serangan alg:none dan kebingungan algoritma, kunci algoritma, rotasi kunci, validasi klaim, dan simpan token dengan aman.

13 menit baca

Praktik Terbaik Keamanan JWT: Serangan, Pertahanan, dan Checklist 2026

JSON Web Token menjalankan sebagian besar autentikasi modern, tetapi praktik terbaik keamanan yang membuatnya tetap aman jauh lebih sering dilewati daripada yang seharusnya. JWT sudah jadi format kredensial standar untuk OAuth 2.0, OpenID Connect, dan panggilan antar-layanan di dalam microservices. JWT juga jadi sumber CVE yang seperti tak pernah habis tiap tahun, dan hampir semuanya berakar dari kesalahan yang sebenarnya bisa dihindari: menerima token tanpa tanda tangan, mempercayai algoritma yang dipilih penyerang, memakai secret penandatanganan yang lemah, atau melewatkan validasi klaim.

Sebuah JWT aman kalau empat hal terpenuhi sekaligus. Tanda tangannya utuh, algoritmanya tidak bisa ditukar penyerang, klaimnya benar-benar diperiksa, dan tokennya disimpan di tempat yang tidak gampang dicuri. Kalau salah satu saja terlewat, yang Anda dapat bukan API yang tangguh, melainkan celah untuk menembus autentikasi. Panduan ini membahas tiga serangan yang paling penting beserta pertahanannya: memilih dan mengunci algoritma, mengelola kunci, memvalidasi klaim, dan menyimpan token. Di akhir ada checklist yang bisa langsung Anda tempelkan ke proses review.

Bagaimana tanda tangan JWT sebenarnya melindungi Anda (dan apa yang tidak)

Sebelum serangan apa pun terasa masuk akal, ada satu fakta yang harus Anda pegang: JWT itu dikodekan (encoded), bukan dienkripsi. Token yang ditandatangani punya tiga segmen Base64URL yang disambung titik, yaitu header.payload.signature. Header dan payload cuma Base64URL dari JSON. Siapa pun yang memegang token bisa membaca setiap klaim di dalamnya. Tempel token apa pun ke dekoder JWT kami dan header serta payload akan terurai dalam JSON yang mudah dibaca tanpa perlu kunci sama sekali. Payload memang dirancang bersifat publik.

Lalu dari mana keamanannya datang? Dari tanda tangan, dan hanya tanda tangan. Itu adalah nilai kriptografis yang dihitung atas header dan payload menggunakan sebuah secret (HMAC) atau private key (RSA, ECDSA). Penyerang bebas membaca token, tetapi tidak bisa menghasilkan token yang berbeda dan lolos verifikasi tanpa kunci penandatanganan. Satu properti itu saja yang menopang seluruh model kepercayaannya.

Dua hal mengikuti dari sini. Pertama, jangan pernah menaruh rahasia di payload (kata sandi, API key, PII lengkap), karena semua itu bisa dibaca siapa pun yang menyadap token. Kedua, seluruh postur keamanan Anda bertumpu pada satu langkah: memverifikasi tanda tangan dengan benar. Langkah itulah yang justru diincar penyerang. Kalau Anda ingin penjelasan lebih dalam soal membaca token segmen demi segmen, lihat cara mendekode JWT.

3 serangan JWT kritis (dan cara menghentikan masing-masing)

Sebagian besar kerentanan JWT adalah variasi dari satu tema: server mempercayai sesuatu yang dikendalikan penyerang. Berikut tiga serangan yang langsung mematahkan autentikasi, lengkap dengan mekanisme di baliknya dan perbaikannya.

1. Serangan alg:none — menembus lewat token tanpa tanda tangan

Spesifikasi JWS menyertakan nilai alg berupa none, yang berarti “tanpa tanda tangan.” Token alg:none punya segmen tanda tangan kosong dan tetap diakhiri titik di belakang, seperti header.payload.. Serangannya sederhana: ambil token yang valid, ubah alg di header menjadi none, ganti klaim sesuka hati (misalnya "role": "admin"), lalu buang tanda tangannya. Library JWT generasi awal menerima ini secara bawaan, sehingga token palsu itu lolos verifikasi tanpa hambatan. Tanpa kunci, tanpa penandatanganan, tapi tetap diakui server.

Anda bisa melihat seperti apa wujud token semacam itu dengan memuat contoh “alg:none” di dekoder JWT kami. Alat itu memunculkan peringatan merah yang tegas bahwa token tersebut tidak ditandatangani dan tak boleh diterima untuk autentikasi. Membuat ulang satu token semacam ini cuma butuh satu menit untuk memahami ancamannya.

Pertahanannya adalah allowlist algoritma yang eksplisit di setiap panggilan verifikasi. Jangan biarkan nilai bawaan library yang memutuskan apa yang boleh diterima, karena bawaan versi lama longgar dan biaya untuk bersikap eksplisit cuma satu opsi tambahan.

// WRONG — the library may accept alg:none or any algorithm
jwt.verify(token, key);

// RIGHT — pin the exact algorithm you expect
jwt.verify(token, key, { algorithms: ['RS256'] });

none tak boleh pernah muncul di array itu. Kalau library Anda tidak bisa mengunci algoritma, ganti library-nya.

2. Kebingungan algoritma — RS256 diturunkan ke HS256

Inilah kerentanan JWT paling berbahaya dalam praktik. Sudah dikenal sejak 2015 dan masih ditemukan dalam audit sampai hari ini. Serangan ini memanfaatkan server yang menentukan bagaimana memverifikasi berdasarkan field alg di header, satu-satunya bagian token yang bisa ditulis ulang penyerang.

Begini mekanismenya. Server Anda menerbitkan token RS256: menandatangani dengan private key RSA dan memverifikasi dengan public key pasangannya. Public key itu, menurut definisinya, memang publik, bisa jadi tersedia di endpoint JWKS Anda atau di repo Anda. Penyerang mengambilnya, mengubah header token dari RS256 menjadi HS256, lalu menandatangani payload palsu memakai HMAC-SHA256 dengan string public key tadi sebagai secret HMAC. Sekarang giliran sisi verifikasi: kalau kode Anda membaca alg dari header lalu memilih HMAC sesuai itu, ia menghitung HMAC-SHA256 atas token menggunakan public key yang sama persis sebagai secret. Tanda tangannya cocok. Token palsu diterima.

Akar masalahnya adalah dua fakta yang bertabrakan: verifier mempercayai header alg yang dikendalikan penyerang, dan public key RSA tersedia bagi penyerang untuk dipakai sebagai kunci HMAC. Tidak satu pun dari keduanya merupakan bug tersendiri. Public key memang seharusnya publik, dan header alg memang seharusnya mendeskripsikan token. Kerentanan lahir begitu logika verifikasi Anda membiarkan header itu memilih jenis kunci dan algoritma yang dipakai, karena saat itulah nilai yang ditulis penyerang menyetir jalur kripto yang dijalankan server.

// WRONG — verification method follows the header's alg field
jwt.verify(token, publicKeyOrSecret);

// RIGHT — hard-code the expected algorithm; never let the header choose
jwt.verify(token, publicKey, { algorithms: ['RS256'] });

Kunci algoritma asimetris secara eksplisit (RS256 atau ES256 saja), pisahkan verifikasi HMAC pada jalur kode yang benar-benar terpisah dari verifikasi RSA, dan pakai library terawat yang membedakan jenis kunci. Dekoder JWT kami menandai setiap token keluarga HS dengan peringatan kebingungan public key justru karena serangan ini sangat umum. Ketika token yang Anda harapkan asimetris malah muncul sebagai HS256, peringatan itu adalah sinyalnya.

3. Secret HMAC lemah — serangan brute-force dan kamus

Kalau Anda memang memakai HMAC (HS256/384/512), seluruh keamanan token bertumpu pada entropi satu secret. Kalau secret itu pendek, berupa kata kamus, atau nilai seperti secret atau password123, penyerang yang menangkap satu token valid saja bisa membobolnya secara offline. Alat seperti hashcat melahap miliaran kandidat per detik terhadap tanda tangan token. Begitu secret tumbang, penyerang bisa mencetak token apa pun yang dia mau, termasuk kredensial admin yang valid selamanya.

Yang membuat serangan ini diam-diam berbahaya adalah sifatnya yang sepenuhnya offline. Penyerang tidak menggedor endpoint login Anda, jadi tak ada rate limit yang terpicu dan tak ada apa pun di log Anda yang mencurigakan. Mereka menangkap satu token, membobol secret di perangkat keras mereka sendiri, dan baru muncul kembali saat sudah bisa menandatangani token yang lolos setiap pemeriksaan Anda. Perbaikannya tidak bisa ditawar: pakai minimal 32 byte acak (256 bit) dari sumber yang aman secara kriptografis, dan simpan di secrets manager, bukan di kode atau repo.

// WRONG — guessable, low entropy, crackable in seconds
const secret = "password123";

// RIGHT — 256 bits from a CSPRNG, then load from KMS at runtime
const secret = require('crypto').randomBytes(32).toString('base64');

Butuh nilai kuat dengan cepat? Generator kata sandi acak kami menghasilkan string berentropi tinggi yang cocok untuk kunci HMAC. Mau merasakan langsung bedanya? Tandatangani token uji dengan secret yang kuat di encoder JWT kami, yang berjalan sepenuhnya di browser sehingga secret tak pernah meninggalkan mesin Anda. Dan kalau verifikasi melintasi batas kepercayaan, misalnya banyak layanan atau verifier pihak ketiga, berhentilah memakai HS256 sama sekali dan beralih ke algoritma asimetris, yang dibahas berikutnya.

Memilih dan mengunci algoritma yang tepat

Pemilihan algoritma adalah titik di mana serangan kebingungan menang atau kalah, jadi pilihlah dengan sengaja. Tiga yang akan benar-benar Anda pakai:

AlgoritmaTipeKunci penandatangan / verifikasiKapan dipakai
HS256Simetris (HMAC)Satu shared secretSatu batas kepercayaan, pihak yang sama menandatangani dan memverifikasi
RS256Asimetris (RSA)Private key menandatangani / public key memverifikasiAntar-layanan, verifikasi pihak ketiga, rotasi JWKS
ES256Asimetris (ECDSA)Private key menandatangani / public key memverifikasiSama seperti RS256, kunci lebih kecil dan cepat — disukai untuk sistem baru

Aturannya pendek. Kalau pihak yang sama menandatangani dan memverifikasi di dalam satu batas kepercayaan, HS256 sudah memadai dan cepat. Kalau ada pihak selain penandatangan yang perlu memverifikasi, entah layanan lain, mitra, atau klien publik, pakai algoritma asimetris, dan utamakan ES256: kunci dan tanda tangannya jauh lebih kecil daripada RSA pada kekuatan setara. Anda bisa menandatangani contoh token HS256, RS256, dan ES256 berdampingan di encoder JWT untuk membandingkan struktur dan panjang tanda tangannya.

Apa pun pilihan Anda, pertahanan yang benar-benar penting tetap sama: kunci satu set algoritma eksplisit pada panggilan verifikasi dan jangan pernah mempercayai field alg di header. Allowlist itu adalah fondasi tempat segalanya bertumpu.

Pengelolaan dan rotasi kunci

Algoritma hanya seaman kunci di belakangnya, dan penanganan kunci adalah bagian yang sering didiamkan kebanyakan panduan. Untuk HS256, secret-nya minimal 32 byte acak dan tinggal di secrets manager seperti AWS Secrets Manager, HashiCorp Vault, atau Azure Key Vault. Untuk algoritma asimetris, private key tempatnya di HSM atau KMS dan tak pernah menyentuh kode aplikasi; public key dipublikasikan, biasanya lewat endpoint JWKS yang diambil para verifier.

Rotasi harus jadi rutinitas, bukan keadaan darurat. Beri tag setiap kunci dengan kid (key ID) di header JWT supaya verifier tahu kunci mana yang menandatangani token tertentu. Simpan sekumpulan kecil kunci yang valid di sisi verifikasi, yaitu kunci saat ini ditambah kunci sebelumnya yang baru saja diganti, supaya token yang ditandatangani tepat sebelum rotasi tetap terverifikasi selama masa berlakunya. Tumpang tindih itulah yang membuat rotasi mulus alih-alih jadi gangguan layanan.

Checklist singkat untuk kunci:

  • Rotasi kunci penandatanganan minimal setiap 90 hari, dan segera setiap kali ada kecurigaan kompromi.
  • Publikasikan public key lewat JWKS; beri versi dengan kid.
  • Simpan private key dan secret HMAC di KMS atau HSM. Jangan pernah di git, jangan pernah di kode klien, jangan pernah ditulis langsung di kode.
  • Saat terjadi kebocoran, rotasi kunci dan cabut semua refresh token yang masih beredar sekaligus.

Validasi klaim yang tak boleh Anda lewatkan

Pemeriksaan tanda tangan membuktikan sebuah token autentik. Itu tidak membuktikan bahwa token tersebut untuk Anda, sekarang. Itulah tugas validasi klaim, dan inilah pertahanan termurah yang bisa Anda tambahkan. Lima klaim perlu diperiksa di setiap permintaan:

  • exp (expiration): tolak token yang masa berlakunya sudah lewat.
  • nbf (not before): tolak token yang dipakai sebelum jendela validnya terbuka.
  • iat (issued at): kalau perlu, tolak token yang umurnya tak masuk akal tuanya.
  • iss (issuer): pastikan token datang dari penerbit yang Anda percaya.
  • aud (audience): pastikan token dicetak untuk layanan Anda. Pemeriksaan aud yang hilang adalah lubang senyap paling umum, membuat token yang diterbitkan untuk satu API bisa diputar ulang terhadap API lain.

Kebanyakan library memvalidasi semua ini untuk Anda begitu Anda meneruskan nilai yang diharapkan:

jwt.verify(token, key, {
  algorithms: ['ES256'],
  issuer: 'https://auth.example.com',
  audience: 'api.example.com',
  clockTolerance: 5, // seconds, for distributed clock skew
});

Beri sedikit toleransi jam (lima detik adalah angka lazim) supaya pergeseran kecil antar-server tidak menolak token yang sebenarnya valid. Tahan keinginan untuk membuatnya lebih besar; toleransi yang murah hati memperlebar jendela di mana token kedaluwarsa masih bisa dipakai, dan justru itulah yang dirancang ditutup oleh exp. Untuk memeriksa nilai exp dan iat pada sebuah token secara langsung, jatuhkan ke dekoder JWT dan konversi timestamp-nya dengan konverter Unix timestamp kami.

Masa berlaku token dan di mana menyimpan JWT

Pemeriksaan di sisi server cuma separuh cerita. Di mana klien menyimpan token menentukan seberapa mudah token itu dicuri, dan penyimpanan adalah titik pertemuan antara XSS dan pembajakan sesi. Pola yang teruji: access token berumur pendek (15 sampai 60 menit) dipasangkan dengan refresh token terpisah yang lebih panjang umurnya dan bisa dicabut.

Keputusan penyimpanan bermuara pada satu kompromi:

Lokasi penyimpananPaparan XSSRisiko CSRFRekomendasi
localStorageTinggi — JavaScript mana pun di halaman bisa membacanyaTidak adaHindari untuk token sesi
Cookie HttpOnly + Secure + SameSite=StrictRendah — tak terlihat oleh JavaScriptButuh proteksi CSRFDisarankan untuk sesi

Token di localStorage bisa dibaca oleh skrip apa pun yang berjalan di halaman, jadi satu bug XSS saja membocorkan seluruh sesi, dan penyerang bisa memutar ulangnya dari mesinnya sendiri selama token masih berlaku. Cookie HttpOnly sama sekali tidak bisa dibaca JavaScript, yang menyusutkan kerusakan XSS jadi sebatas apa yang bisa dilakukan penyerang di dalam halaman yang hidup. Tetap buruk, tetapi bukan kredensial curian yang bisa mereka bawa kabur. Biaya pendekatan cookie adalah Anda kini perlu proteksi CSRF, karena cookie ikut terbawa otomatis di setiap permintaan; SameSite=Strict ditambah token CSRF mengatasinya. Buat access token tetap pendek supaya kebocoran punya radius ledak kecil, dan taruh refresh token di cookie HttpOnly, Secure, SameSite. Saat logout atau dicurigai kompromi, cabut refresh token di sisi server dan rotasi kunci penandatanganan. Untuk konteks lebih luas seputar XSS, CSRF, dan cookie aman, lihat panduan praktik terbaik keamanan web kami.

Checklist keamanan JWT

Telusuri ini sebelum merilis autentikasi berbasis JWT apa pun:

  • Verifikasi mengunci allowlist algoritma yang eksplisit dan menolak alg:none.
  • Verifikasi asimetris menulis algoritma yang diharapkan langsung di kode (hard-code) dan tak pernah membaca alg dari header (memblokir kebingungan).
  • Secret HS256 minimal 32 byte acak, dimuat dari KMS.
  • Private key tinggal di HSM/KMS; public key dipublikasikan lewat JWKS dan diberi versi dengan kid.
  • Kunci penandatanganan dirotasi minimal setiap 90 hari.
  • Setiap permintaan memvalidasi exp, nbf, iat, iss, dan aud, dengan toleransi jam 5 detik atau kurang.
  • Access token bertahan 15 sampai 60 menit; refresh token tinggal di cookie HttpOnly.
  • Tidak ada rahasia di payload, karena payload dikodekan, bukan dienkripsi.

FAQ

Apakah JWT aman secara bawaan?

Tidak. Keamanan JWT bergantung pada konfigurasi. Anda harus mengunci algoritma, menolak alg:none, memakai secret atau kunci berentropi tinggi, dan memvalidasi klaim. Pengaturan library yang bawaan atau longgar kerap membuka jalan pintas menembus autentikasi.

Apa kerentanan JWT yang paling berbahaya?

Kebingungan algoritma, ketika RS256 diturunkan ke HS256 dan public key dipakai sebagai secret HMAC. Sudah dikenal sejak 2015 tetapi masih muncul dalam audit, karena ia memanfaatkan server yang memilih metode verifikasi dari field alg di header.

Sebaiknya pakai HS256 atau RS256?

Pakai HS256 ketika pihak yang sama menandatangani dan memverifikasi di dalam satu batas kepercayaan. Pakai RS256 atau ES256 ketika layanan lain atau pihak ketiga harus memverifikasi, atau saat Anda butuh rotasi JWKS. Untuk sistem baru, utamakan ES256: kunci lebih kecil dan cepat pada kekuatan setara.

Di mana sebaiknya menyimpan JWT?

Utamakan cookie HttpOnly, Secure, SameSite untuk token sesi, karena JavaScript tak bisa membacanya dan satu bug XSS tak bisa mencurinya. Hindari localStorage untuk token sesi, karena XSS apa pun membocorkan seluruh sesi untuk diputar ulang.

Seberapa sering kunci penandatanganan JWT harus dirotasi?

Rotasi minimal setiap 90 hari sebagai rutinitas, dan segera setiap kali dicurigai ada kompromi. Beri versi kunci dengan kid dan simpan baik kunci aktif maupun kunci sebelumnya yang baru saja diganti di verifier supaya token yang ditandatangani tepat sebelum rotasi tetap valid.

Bisakah JWT dirusak?

Tidak bisa tanpa kunci penandatanganan; tak ada penyerang yang bisa memalsukan token yang lolos verifikasi. Tetapi kalau server Anda menerima alg:none, rentan terhadap kebingungan algoritma, atau memakai secret lemah, tanda tangannya bisa dilewati. Itu kegagalan konfigurasi, bukan cacat pada JWT itu sendiri.

Klaim apa saja yang wajib saya validasi?

Validasi exp (expiration), nbf (not before), iat (issued at), iss (issuer), dan aud (audience). Pemeriksaan aud yang hilang adalah kerentanan senyap paling umum, membuat token yang dimaksudkan untuk satu layanan bisa diputar ulang terhadap layanan lain.

Kesimpulan

Keamanan JWT tidak rumit, tetapi setiap lapisan harus kuat. Tanda tangan adalah satu-satunya jaminan Anda, jadi verifikasi dengan benar. Kunci satu algoritma eksplisit dan jangan pernah mempercayai alg di header. Pakai kunci yang kuat dan rutin dirotasi yang disimpan di KMS. Validasi exp, nbf, iat, iss, dan aud di setiap permintaan. Dan simpan token di tempat yang tak bisa dijangkau XSS.

Untuk mempraktikkannya, tempel token apa pun ke dekoder JWT kami untuk memeriksa algoritma dan klaimnya serta menangkap risiko alg:none atau kebingungan HS, lalu pakai encoder JWT untuk bereksperimen menandatangani sepenuhnya di browser Anda. Kunci Anda tak pernah meninggalkan perangkat.

Tag: jwt security authentication oauth api-security

Artikel Terkait

Lihat semua artikel