4 poin oleh GN⁺ 18 jam lalu | 2 komentar | Bagikan ke WhatsApp
  • JWT tidak cocok digunakan untuk mempertahankan status login pengguna, dan untuk tujuan ini sesi cookie biasa lebih tepat
  • Spesifikasi JWT mengasumsikan token berumur pendek sekitar 5 menit atau kurang, sedangkan sesi membutuhkan masa berlaku yang lebih panjang
  • Autentikasi stateless yang aman sulit diwujudkan, dan untuk menangani token dengan aman pada akhirnya tetap dibutuhkan beberapa bentuk penyimpanan state
  • JWT yang hanya memuat token sesi sederhana lebih tidak efisien dan kurang fleksibel dibanding cookie sesi biasa, dan kredensial autentikasi tidak boleh disimpan di localStorage atau sessionStorage
  • Jika membutuhkan token bertanda tangan berumur pendek, PASETO yang dirancang untuk keamanan adalah pilihan yang lebih baik, tetapi tidak boleh digunakan untuk keperluan sesi

Ringkasan inti

  • JWT tidak seharusnya digunakan untuk mempertahankan pengguna tetap login, dan untuk tujuan itu sesi cookie biasa adalah alat yang lebih baik
  • JWT tidak dirancang untuk tujuan ini dan tidak aman, sedangkan sesi cookie reguler lebih cocok untuk mempertahankan sesi login
  • Sebagai topik terkait, kredensial autentikasi termasuk token JWT tidak boleh disimpan di localStorage atau sessionStorage
  • Ada presentasi terkait JWT yang bisa ditonton, tetapi topik lain seperti perlindungan CSRF umumnya hanya dibahas singkat, jadi perlu dipelajari terpisah dari sumber lain
  • Bahkan kasus penggunaan JWT yang “valid” di bagian akhir video pun dapat ditangani dengan alat yang lebih baik dan lebih aman, yaitu PASETO

Alasan menghindari JWT

  • Spesifikasi JWT dirancang hanya untuk token berumur sangat pendek sekitar 5 menit atau kurang, sedangkan sesi memerlukan masa berlaku yang lebih panjang
  • Autentikasi stateless yang aman tidak memungkinkan, dan untuk memproses token dengan aman sebagian state tetap diperlukan
    • Jika tetap membutuhkan penyimpanan data, lebih baik menyimpan seluruh data daripada hanya menangani sebagian state token
    • Masalah terkait dibahas lebih rinci di http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/
    • Memang ada aplikasi yang memakai JWT dengan cara ini, tetapi aplikasi semacam itu cacat, jadi kesalahan yang sama tidak boleh diulangi
  • JWT yang hanya menyimpan token sesi sederhana lebih tidak efisien dan kurang fleksibel daripada cookie sesi biasa, tanpa memberikan manfaat tambahan
  • Spesifikasi JWT sendiri tidak dipercaya oleh para ahli keamanan, sehingga sebaiknya dikeluarkan dari seluruh penggunaan terkait keamanan dan autentikasi

Sanggahan

  • Sanggahan “Google juga memakai JWT” tidak berlaku untuk sesi pengguna di browser
    • Google tidak memakai JWT untuk sesi pengguna di browser, melainkan menggunakan sesi cookie biasa
    • JWT hanya dipakai sebagai sarana pengiriman Single Sign On untuk meneruskan sesi login dari satu server atau host ke sesi di server atau host lain
    • Cara penggunaan ini termasuk dalam cakupan kasus penggunaan JWT yang masih masuk akal
    • Google memiliki sumber daya ahli keamanan untuk membuat dan memelihara implementasi JWT yang lebih aman
    • JWT milik Google pada praktiknya tidak sama dengan JWT di tempat lain
  • Sanggahan “stateless lebih baik” tidak sesuai dengan tuntutan autentikasi yang aman
    • Tanpa sumber daya yang sangat besar, autentikasi yang benar-benar stateless tidak bisa dijalankan dengan aman
    • Untuk pembahasan terkait, lihat Stateless is a lie
  • Masalah “tidak tahu cara mengatur sesi” biasanya bisa diselesaikan lewat dokumentasi dan implementasi dari sebagian besar framework web server
    • Teknologi sesi bukan hal yang benar-benar baru, jadi tulisan yang menjelaskan sesi tidak terlalu sering terlihat
    • Dokumentasi implementasi sesi saja seharusnya sudah cukup untuk mengikuti proses penyiapannya
    • Hampir semua framework web server memiliki implementasi sesi, dan meski tidak aktif secara default, biasanya mudah diaktifkan
    • Express dan framework Node.js lain agak menjadi pengecualian karena sifatnya yang sangat modular dan berfokus pada satu tujuan
    • Di Express, cukup gunakan middleware express-session dan store connector yang sesuai dengan penyimpanannya
    • Disarankan menggunakan connect-session-knex bersama Postgres, MySQL, atau jika memungkinkan SQLite

Token jangka pendek

  • Jika memerlukan token bertanda tangan berumur pendek untuk suatu keperluan, ada spesifikasi yang lebih baik bernama PASETO yang dirancang untuk keamanan
  • Sekalipun menggunakan PASETO, itu tetap tidak boleh dipakai untuk keperluan sesi

Cara kerja sesi

  • Untuk mempelajari lebih lanjut cara kerja sesi, sebaiknya lihat gist joepie91

2 komentar

 
shj5508 9 jam lalu
  1. JWT adalah cara untuk mengenkripsi token dan mengurangi query ke DB, bukan konsep yang berseberangan dengan autentikasi berbasis cookie. Jika JWT disimpan di cookie secure, risiko pencuriannya sama seperti metode autentikasi cookie lama.

  2. Mengelola daftar kedaluwarsa untuk membuat JWT expired memiliki keuntungan dari sisi performa. Ada perbedaan biaya antara hanya melakukan query informasi kedaluwarsa di redis dan melakukan query ke DB untuk seluruh anggota.

Puluhan ribu kali query berbasis indeks terhadap 100 ribu row anggota (metode cookie lama)
vs
Puluhan ribu kali query 50 item daftar kedaluwarsa di redis (metode JWT expire seketika)

JWT memang punya kelebihan. Hanya saja, di lingkungan berskala kecil perbedaannya tidak terlalu terasa.

 
GN⁺ 18 jam lalu
Opini Hacker News
  • Ada konteks penting yang hilang: ini membahas sesi pengguna berbasis browser
    Untuk komunikasi antarlayanan, sering kali ada kasus di mana JWT sangat cocok digunakan
    Tambahan, saya membaca sebagian tulisan yang ditautkan, misalnya ada artikel seperti https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba.... Kalau JWT memang standar yang seburuk itu dari sisi keamanan, ya silakan publikasikan cara meretas AssumeRoleWithWebIdentity di AWS STS, atau jangan dipublikasikan dan langsung jalankan penambang kripto di akun AWS produksi milik perusahaan Fortune 500. Kalau JWT memang sebegitu tidak amannya, kabari saya saat berhasil /sarkasme

    • Ini kesimpulan yang sangat masuk akal. Saya setuju bahwa JWT adalah alat yang keliru untuk sesi pengguna di browser
      Bagian tanda tangan dan enkripsi JWT itu rumit, dan library JWT yang umum baru belakangan ini sebagian besar mulai waras; dulu tidak begitu. Banyak library yang menerima algoritma "none" [1], dan ada juga yang memakai kunci publik seolah-olah itu shared secret sehingga penyerang bisa memalsukan token [2]. Ini tepat merupakan akibat dari kompleksitas yang dikritik oleh tulisan yang ditautkan
      JWT juga kadang tidak bisa memberikan hal yang sebenarnya diinginkan dari sesi pengguna. JWT tidak bisa dibatalkan kecuali Anda menyimpan daftar pencabutan di suatu tempat. Namun jika pada setiap request Anda harus mencocokkan identifier dengan daftar pencabutan, lebih baik gunakan session ID opak dan lakukan lookup tiap request. Tentu, Anda bisa memakai token berumur pendek dan terus memperbaruinya, tetapi dalam aplikasi biasa yang memang perlu mempertahankan state, alasan untuk melakukan itu tidak terlalu kuat
      Namun, saya sepenuhnya setuju bahwa dalam sistem terdistribusi atau komunikasi antarmesin, token bertanda tangan kadang sangat berguna. Jangan mencampuradukkan dua kasus ini
      [1] https://nvd.nist.gov/vuln/detail/cve-2022-23540
      [2] https://nvd.nist.gov/vuln/detail/CVE-2024-54150
    • Dulu JWT sering bermasalah karena library dengan default yang buruk. Beberapa tahun lalu, serangan downgrade juga cukup umum
      Sekarang library utama di berbagai bahasa sudah punya default yang lebih masuk akal, jadi menurut saya saat ini JWT dalam praktiknya sudah cukup aman
    • JOSE, meskipun aman jika diimplementasikan dengan benar, tetap bisa menimbulkan masalah. Permukaan API yang terkait sering kali kurang bagus
      Jika “aman bila dipegang dan dipakai dengan benar” otomatis berarti desainnya bagus, maka hal yang sama juga berlaku untuk X.509
      Dalam banyak kasus, ada alternatif yang lebih baik. Token sesi standar atau API key digunakan luas di sebagian besar situs web besar, dan hampir sempurna untuk kebanyakan kebutuhan
      Bukan berarti standar seperti ini sama sekali tidak punya nilai. Kelebihan terbesarnya adalah ia menjadi standar dasar untuk saling bertukar sesuatu tanpa ASN.1 encoding, dan tool di ekosistem ASN.1 tampaknya sangat rapuh dan penuh bug
    • Saya setuju dengan bagian awalnya, tetapi tambahan itu adalah sesat logika. Sesuatu tidak harus bisa diretas dulu agar kita boleh menyebutnya tidak aman
      Misalnya, saya tidak tahu cara mengeksploitasi SAML, tetapi saya tahu itu standar yang buruk karena menjadikan seluruh XML parser sebagai attack surface. Saya bukan peneliti keamanan, jadi saya juga tidak tahu cara menemukan kerentanan di XML parser, tetapi saya tetap bisa tahu bahwa attack surface yang besar itu buruk
    • Silsilah kerentanan yang timbul akibat JWT di aplikasi nyata sudah panjang sekali
  • JWT tidak aman? Maksudnya bahkan kalau memakai skema tanda tangan berbasis RSA/kunci publik yang tepercaya juga tetap begitu? Bukan shared secret?
    Klaim bahwa JWT hidup terlalu lama juga terasa aneh. Anda bisa membatasi masa hidup JWT dan memakai model refresh terhadap otoritas autentikasi. Bahkan kalau memakai sesi berbasis cookie pun, pada akhirnya Anda tetap menyimpan sesuatu di suatu tempat. Anda bisa membuat JWT hanya valid 5–15 menit, dan 15 menit mirip dengan waktu cache berbagai sistem otorisasi termasuk Entra. Token 5 menit pun cukup bisa dipakai di browser jika ada sistem refresh
    Terakhir, saya lebih suka memisahkan identitas/autentikasi dari layanan aplikasi/API. Konteks bisa dieksternalisasi, dan memproses JWT pada setiap request lebih mudah ditangani daripada sistem cache/state bersama yang kadang gagal secara intermiten. Token bertanda tangan bisa memverifikasi signature terhadap otoritas yang dikenal

    • JWT bisa dibuat tidak valid dalam 30 detik, bahkan 1 detik. Saat membuat JWT, Anda harus menetapkan audience
      Selain itu, tanda tangannya valid secara kriptografis. Cukup verifikasi semua JWT setiap kali dengan masa hidup pendek
      Sebagai catatan, token OIDC semuanya adalah JWT
  • Jika membandingkan sesi dengan daftar pencabutan JWT, ada juga argumen yang mendukung daftar pencabutan JWT. JWT punya waktu kedaluwarsa yang terbatas, jadi Anda hanya perlu mempertahankan daftar pencabutan untuk token yang belum kedaluwarsa
    Kemungkinan besar JWT yang dicabut hanyalah sebagian kecil dibanding JWT valid yang masih beredar, jadi pada tiap request Anda hanya melakukan lookup ke dataset yang sangat kecil
    Jika memakai sesi, daftar sesi valid kemungkinan beberapa orde magnitudo lebih besar daripada daftar pencabutan, sehingga biaya lookup dan biaya penyimpanan akibat statefulness lebih tinggi
    Lagi pula, tulisan itu menyebut JWT sebagai stateless, padahal biasanya tidak begitu. Umumnya Anda bukan hanya memverifikasi JWT, tetapi juga mengambil objek identitas yang cocok pada tiap request, yaitu detail pengguna, untuk memastikan pengguna masih aktif dan masih berwenang melakukan tindakan tersebut. Anda bisa memanfaatkan daftar pencabutan per pengguna atau nilai seperti minimum_issued_at untuk memverifikasi field iat pada JWT. Dengan begitu, pola “logout dari semua perangkat” juga dimungkinkan, dan tindakan itu cukup mengatur minimum_issued_at pengguna menjadi $NOW, sehingga semua token sebelumnya langsung dicabut. Tidak perlu lookup daftar pencabutan individual

    • Begitu Anda harus mengambil objek pengguna, keunggulan inti JWT sudah hilang, jadi sebaiknya dibuang saja
    • Lookup data sesi hanyalah satu select yang memakai indeks di database dan mengembalikan 0–1 baris. Dalam kebanyakan kasus, itu bukan hal yang perlu dikhawatirkan
    • Sesi juga punya waktu kedaluwarsa, dan bisa diatur sesuka Anda
  • Tulisan ini menautkan sebagian besar bagian “mengapa” ke tulisan blog lain, dan tulisan blog itu pada dasarnya tampak seperti keluhan bahwa “token JWT individual tidak bisa dibatalkan”
    Setiap kali saya mengimplementasikannya, pedoman umumnya adalah memeriksa nonce yang sudah dibatalkan di suatu tempat, dan itu juga menyelesaikan argumen kedua di tulisan tersebut
    Pernyataan bahwa “spesifikasi JWT sendiri tidak dipercaya oleh para pakar keamanan” tampaknya memerlukan dasar yang lebih kuat daripada satu tulisan blog. Dan tulisan itu pada dasarnya terdengar seperti menyalahkan implementasi yang buruk, padahal standar apa pun akan selalu diikuti masalah implementasi yang buruk
    Secara keseluruhan, saya juga tidak tahu apa yang saya harapkan ketika mengklik tautan gist acak

    • Beberapa implementasi awal memang membiarkan siapa pun menetapkan issuer di header lalu langsung memercayainya, dan itu jelas pendekatan yang salah sejak awal. Kalau hanya mengizinkan issuer yang tepercaya atau “dikenal”, banyak kekhawatiran kontekstual hilang
      Selain itu, JWT dengan masa hidup lebih pendek juga bisa dipakai dengan baik di browser, dan agen bisa dibuat memperbaruinya sendiri. Jika memakai Azure Entra atau banyak penyedia lain, memang begitulah cara kerjanya. JWT bisa dibuat relatif singkat, sekitar 5~15 menit, sambil tetap memeriksa apakah jti sudah dicabut
      JWT sangat berguna untuk memisahkan dan menggunakan ulang otoritas otorisasi dari sistem aplikasi/API. Ini memindahkan attack surface, tetapi memindahkannya dengan cara yang dapat dipercaya. Di seluruh dunia, pendekatan kunci publik dipakai di banyak tempat termasuk SSH. Saya tidak akan memakai shared secret atau token berumur panjang, tetapi token bertanda tangan kunci publik berumur pendek dari sumber yang terverifikasi dan dikenal umumnya baik-baik saja
      Justru yang sering benar-benar bermasalah adalah API key. Saya baru saja harus mengimplementasikannya, dan dalam kasus saya API key juga dibuat tampak seperti Bearer token, dengan awalan pendek sak., lalu bagian identitas (byte UUID base64url), lalu nilai rahasia (byte base64url). Di database saya menyimpan UUID serta salt+hash setingkat passphrase yang dibuat dari nilai rahasia itu. Jadi API key yang dihasilkan harus diperlakukan sebagai rahasia, dan di database hanya disimpan satu arah sehingga kebocoran DB tidak langsung berarti kebocoran autentikasi
      Meski begitu, kebocoran API key masih jauh lebih mungkin terjadi daripada masalah pada solusi JWT yang diimplementasikan dengan baik
    • Saya tidak 100% setuju dengan klaim bahwa “token JWT individual tidak bisa dibatalkan”. Saat mengimplementasikannya, memeriksa nonce yang telah dibatalkan di suatu tempat bagi saya adalah akal sehat, dan saya selalu heran setiap kali diingatkan bahwa orang-orang tidak melakukannya
  • Saya kebetulan melihat tulisan ini, dan karena dulu banyak mengerjakan topik ini, saya merasa menarik bahwa ini kembali jadi pembicaraan sekarang. Lalu saya klik dan ternyata penulisnya menautkan sebagian materi saya. Benar-benar membangkitkan kenangan lama
    Bagaimanapun, orang-orang yang jauh lebih pintar daripada saya sudah membahas topik ini secara luas selama bertahun-tahun, tetapi pada 2026 pun saya masih menganggap JWT adalah alat yang salah untuk autentikasi web. Untuk antar-layanan itu tidak masalah, tetapi jika punya pilihan, lebih baik pakai PASETO saja. Itu menyelesaikan banyak masalah

  • Saya sedang menambahkan RabbitMQ ke website sekarang untuk push notifikasi. Saya memakai autentikasi JWT untuk mengontrol dari mana klien bisa membaca apa, dengan masa hidup pendek dan pembaruan token berkala
    Saya tidak begitu tahu konfigurasi lain yang mendekati semudah setup ini. Cukup tambahkan satu endpoint yang memberi token JWT untuk sesi yang valid, dan otorisasi per pengguna juga bisa dilakukan

  • Salah satu tulisan yang ditautkan dan mengaku menjelaskan mengapa JWT tidak boleh dipakai, kalau dinilai baik-baik pun tetap aneh
    https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba...
    Ringkasnya, isinya “beberapa library punya bug”, lalu setelah itu menyarankan membawa libsodium dan mengerjakan semuanya sendiri. Ini saran yang konyol dan sulit dianggap serius. Semua perangkat lunak punya bug. Saat Heartbleed terjadi, seluruh internet kacau, tetapi kita tetap memakai TLS dan OpenSSL
    Saya baru pertama kali mendengar klaim bahwa “spesifikasi JWT dirancang khusus hanya untuk token yang sangat berumur pendek, kira-kira 5 menit atau kurang”, dan saya juga tidak bisa menemukan dasar pendukungnya. RFC 7519 tidak menyatakan hal seperti itu

  • Biasanya JWT dipakai seperti cache autentikasi. Anda mendapatkan token autentikasi dari layanan autentikasi, lalu token itu memberi hak ke layanan lain
    Ada beberapa kelebihannya, tetapi inti utamanya adalah layanan bawahan tidak perlu berinteraksi dengan database autentikasi dan tidak perlu punya wewenang untuk menerbitkan token. Dengan asumsi memakai RS256, bukan HMAC. Jadi kalau layanan bawahan dibobol, dampaknya tidak separah bila yang dibobol adalah layanan yang bisa mengakses database autentikasi
    Jika ada data sensitif di dalam token, maka Anda harus memakai JWE, tetapi itu kurang ideal karena setiap kali digunakan Anda harus meminta layanan internal yang memegang private key untuk mendekripsi token
    Struktur yang sering saya pakai adalah {"id": (uuid), "scopes": ["scope:read/write"]}
    Ini juga cukup bagus untuk SPA. Server situs statis bisa memverifikasi JWE dengan kunci publik sebelum menyajikan resource. Cara saya adalah mengompilasi situs statis ke bentuk /(scope)/path, sehingga halaman yang tidak boleh diakses layanan statis memang tidak akan disajikan sejak awal. Ini sangat berguna ketika Anda tidak ingin mengekspos kepada pengguna fitur yang dimiliki backend, seperti panel admin, atau jalur layanan internal yang bisa diserang
    Masa hidup JWT untuk “akses backend” sekitar 5 menit, dan hal seperti /me saya cache di localStorage kecuali /refresh secara eksplisit menyuruh membuang cache localStorage. Request handler aplikasi SPA mendeteksi “perlu refresh” lalu memperbarui token
    Saya rasa sebagian besar tanggung jawab di sini ada pada library node/next dan Python. Backend saya tulis dengan bahasa yang strongly typed, dan frontend selalu saya buat sebagai halaman statis yang sudah dikompilasi sebelumnya. Konfigurasi frontend saat ini memakai VITE, dengan landing berupa halaman prarender dan aplikasinya berupa SPA biasa
    Dengan semua itu pun, saya tetap sangat tidak setuju dengan keseluruhan gist ini. JWT bisa dibuat seaman yang Anda inginkan

  • JWT itu baik-baik saja, dan judulnya terasa agak sensasional
    Sebaliknya, ada topik-topik yang lebih layak dibahas: kapan harus memakai nilai terenkripsi (simetris atau asimetris), nilai acak tetapi rahasia, nilai bertanda tangan (bisa dibaca tetapi tidak bisa diubah), di mana nilai-nilai seperti ini sebaiknya disimpan (memori, localStorage, cookie), bagaimana memastikan nilainya tidak bertahan selamanya, dan apakah perlu dibuang sebelum waktu kedaluwarsa alaminya