JWT Insight : Payloads, Secret Key Algoritma, dan Library

JWT Insight : Payloads, Secret Key Algoritma, dan Library

JSON Web Token atau JWT (dibaca jot) adalah Token yang digunakan untuk melakukan proses claim dari 2 service yang berbeda (biasanya backend dan frontend). JWT memiliki standard RFC 7519. Berdasarkan sejarahnya JWT memiliki kelebihan yaitu ringkas (compact) dibandingkan pendahulunya SAML (Security Assertion Markup Language).

SAML dibuat tahun 2003
Sedangkan JWT pertama di publish tahun 2010

Membandingkan JWT dan SAML

Saat ini hampir semua website ataupun service yang menggunakan token ini dibandingkan harus menggunakan teknik lama tahun 1993 Basic Access Authentication yang mengharuskan mengirim username dan password (tanpa enkripsi atau hash) setiap pengiriman paket.

JWT memiliki beberapa komponen, yaitu Header, Payload, dan Signature. Header biasanya berisi algoritma yang digunakan dan type JWT (JWT, JWE). Payload adalah data token, sedangkan Signature adalah data untuk menandai siapa yang membuat token ini.

Header dan Payload

Membuat payload yang lengkap akan memudahkan validasi, dan debugging. Semakin lengkap dan validasi yang lengkap akan membuat aplikasi jadi lebih aman dari serangan hacker yang mencoba manipulasi JWT.

Kita akan bahas bagaimana validasi semua JWT pada section berikutnya.

Payload JWT berisi data JSON yang cukup simpel. Pada dasarnya bisa di isi apa saja, biasa disebut jwt claim.

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

Pertanyaannya adalah Claim apa saja yang perlu dibuat ? Berdasarkan standard RFC 7519 halaman 9, ada beberapa claim yang sudah di daftarkan dan semuanya bersifat opsional.

Untuk meracik Payload, pastikan setiap data di isi dengan tujuannya masing-masing, disarankan untuk mengikuti standard website atau service perusahaan agar mudah validasi.

  1. iss (Issuer) adalah penerbit JWT, biasanya URL backend

  2. sub (Subject) adalah subject user id yang unik, biasanya user id yang tersimpan di server

  3. aud (Audience) adalah identitas penerima (Recipents), biasanya URL dari frontend yang meminta JWT.

  4. exp (Expiration Time) adalah tangga kadaluarsa dalam bentuk milisecond

  5. nbf (Not Before) sebelum tanggal ini, JWT tidak valid.

  6. iat (Issued At) adalah tanggal JWT diterbitkan.

  7. jti (JWT ID) Tanda unik dari JWT. Berupa id unik yang berbeda dengan user id.

Claim ini sudah cukup lengkap menjelaskan tentang peran token, seperti :

  • Siapa yang membuat token ? terjawab dari iss

  • Siapa yang meminta dibuatkan token ? terjawab dari aud, ini akan berguna jika ada lebih dari 1 service/tipe seperti Client mobile dan web, aplikasi production user dan testing user,

  • Untuk siapa token ini ? terjawab dari sub berisi identitas user.

Selain claim diatas, anda bisa menambahkan claim lainnya seperti username, email, fullname. Tidak perlu semua data, hanya beberapa data saja.

Secret Key Algoritma

JWT secara default memiliki secret key. Ini digunakan saat menerbitkan JWT, hanya yang memiliki secret key dapat menerbitkan JWT.

Terdapat 2 tipe secret key yaitu asymmetric dan symmetric.

Symmetric menggunakan secret key yang sama untuk penerbitan dan validasi, sedangkan asymmetric menggunakan secret key untuk penerbitan dan gunakan public key untuk validasi.

Disarankan menggunakan Asymmetric secret code karena sudah banyak secret code symmetric yang tersebar di internet, seperti dijelaskan artikel ini ada 340 secret key yang tidak sengaja tersebar di publik repository kode.

Saya juga menulis tentang bagaimana menggunakan GPG Enkripsi yang memiliki asymmetric keys pada artikel GPG encryption snippet.

Symmetric Secret key (HS256)

JWT Algoritma HS256 menggunakan symmetric secret code. Berdasarkan buku JWT untuk penerbitan JWT cukup menggunakan 1 secret kode

const secret = 'my-secret';
const signed = jwt.sign(payload, secret, {
algorithm: 'HS256',
expiresIn: '5s' // if ommited, the token will not expire
});

dan untuk validasi

const secret = 'my-secret';

const decoded = jwt.verify(signed, secret, {
// Never forget to make this explicit to prevent
// signature stripping attacks
algorithms: ['HS256'],
});

Algorithma yang menggunakan symmetric secret key adalah yang menggunakan prefix HS.

Algoritma penerbitan (signing) ini cocok jika penggunaan Token kamu yakin siapa yang akan memegang secret key untuk validasi.

Tapi jika kamu tidak yakin mereka memegang secret key, gunakan RS256 Asymmetric secret key

Asymmetric Secret Key (RS256)

RS256 (RSA algorithm) menggunakan 2 key yaitu

  1. Private Key

  2. Public Key

Private key digunakan untuk menerbitkan (signing) JWT, ini hanya kamu yang pegang. Jangan di sebar luaskan atau hacker akan membuat JWT baru untuk membuat token baru.

Sedangkan Public key digunakan untuk verifikasi token, tidak bisa modifikasi Token JWT.

Ini sangat berguna jika kamu memiliki service lain yang diluar kendali mu, seperti aplikasi client yang memerlukan validasi dari token yang kamu terbitkan.

Juga ini lebih aman dibanding HS256 karena ada 2 kunci dan tidak mudah di bruteforce oleh hacker.

Cara Membuat asymmetric key bisa menggunakan OpenSSL

# Generate a private key
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
# Derive the public key from the private key
openssl rsa -pubout -in private_key.pem -out public_key.pem
Contoh hasil secret key dan public key JANGAN GUNAKAN PRIVATE DAN PUBLIC KEY INI

➜ cat private_key.pem

-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDBaITpkYCMwhqX YKkG6N9mFxA102+zQXOgRjPfQNFB/oVng4lFZR1hZvIykWihREchzePrqAo1eMsV wokjekVlieQMBTU28tjdzh/VoZyAY7uDiE9JYmc6Ew+xyM5NB2vsY1Gdw1IT1mOx OL6yTrpmCwKBgHvs9ZlWItheA/INeEJP7w3gewOMQzxjBpnsN8UX5k/Hx2mKgkem hwqglp492BuLX5N8QzjX1B4efM2UMYK5ypFt6VSjR9nbBv+KNm80ypcSfXVAYj7 5iadocl3Jm1cXJ0a2Q5MbdRw3soYj2+hjk2SjwmZcraHQ/jleJBmWgH/RMZvyqyK RD6dsEyul9LSjWzXc7FFNIFxOY9vv2kbYhEitnlu8QmmmtK17BomgTWloe2y4Hfa wokjekVlieQMBTU28tjdzh/VoZyAY7uDiE9JYmc6Ew+xyM5NB2vsY1Gdw1IT1mOx OL6yTrpmCwKBgHvs9ZlWItheA/INeEJP7w3gewOMQzxjBpnsN8UX5k/Hx2mKgkem hwqglp492BuLX5N8QzjX1B4efM2UMYK5ypFt6VSjR9nbBv+KNm80ypcSfXVAYj7 +y6c0av1iSkFhpxgIa/7pp6QWB4obdACpcfhZdJy2suzhD/PNtI3xTqBQNUVCcOB LJfoT3ycTmhQIsrkxfHfbgTxIlEYNId5j0kzkSKNJtag7FkT5RZ2he6LdpXCAn0S wokjekVlieQMBTU28tjdzh/VoZyAY7uDiE9JYmc6Ew+xyM5NB2vsY1Gdw1IT1mOx OL6yTrpmCwKBgHvs9ZlWItheA/INeEJP7w3gewOMQzxjBpnsN8UX5k/Hx2mKgkem hwqglp492BuLX5N8QzjX1B4efM2UMYK5ypFt6VSjR9nbBv+KNm80ypcSfXVAYj7 qLisd3NYiuwunU6Rd41+ofheFh9JLG1dSOgxt/kPzy3s6lWHr72QcP13u9doU/M6 /QB+Uyf9FPqHXG9JIlIUTpvAgQKBgQDZLmMti1DndPKY/nU9SpYd1O4NGrbdtG88 sB+GMeB52nFeB2Mw0vjO1V7w4VZD/y4DFK/t+F4BxVel0I2lqizEEsDD0OH6+ttY wokjekVlieQMBTU28tjdzh/VoZyAY7uDiE9JYmc6Ew+xyM5NB2vsY1Gdw1IT1mOx OL6yTrpmCwKBgHvs9ZlWItheA/INeEJP7w3gewOMQzxjBpnsN8UX5k/Hx2mKgkem hwqglp492BuLX5N8QzjX1B4efM2UMYK5ypFt6VSjR9nbBv+KNm80ypcSfXVAYj7I R/fm4suWOofDpjS48lnXIeF5SZHbuKdDKoaA24b2ZW05cQEXV/jT9lSBAoGAY0Rb mp6Z/SEsHZf4+GnWEY6YvC6gtNdbHK8XyZuUkb2xoZvYz6EujkNioNEuP+gsHMZg 33FtbnvH4wdfJwCQc5Jqv1YDZFcy2PAaBLhHbfDH5mKe/x2i2Eb1sAytXtW3CJjO PKmYqye5Pbad7QFeZ+7BiE2Vf3G3oXJhX1iyxB8CgYEAprcKJuBmlRgb2rAGkkIE HJgLJfWvbo31Pf9y8ZNZlDUn0TaRby+vc2y1oMfL/Pyuf7xxRYdTUEvgulVL+pkO 7gyXWfVh7rsb6K7FGkGxs16KrBH6LtSB4VqKQC8kzwHTtDQ/9yulkLon793ubxf9 md1Ccjg5JetDkoHMeUvci8w= -----END PRIVATE KEY-----

➜ cat public_key.pem

-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwWiE6ZGAjMIal2CpBujf ZhcQNdNvs0FzoEYz30DRQf6FZ4OJRWUdYWbyMpFooURHIc3j66gKNXjLFYhPBx+2 Vuo8XK6OswkI27wn2YerewCBYMQPWEXr/0F7bMbzEryRy7ItihWdNFEqT+YmnaH ZhcQNdNvs0FzoEYz30DRQf6FZ4OJRWUdYWbyMpFooURHIc3j66gKNXjLFYhPBx+2 Vuo8XK6OswkI27wn2YerewCBYMQPWEXr/0F7bMbzEryRy7ItihWdNFEqT+YmnaH XX7RddwiGGMZyQ1M2KICoF495PWCxO39ixk3rCpOz4wbXNlIMkoWNmIyRce0mx6r iwIDAQAB -----END PUBLIC KEY-----

Script diatas akan membuat file private_key.pem dan public_key.pem. Gunakan private_key.pem untuk membuat Token

const privateRsaKey = `<YOUR-PRIVATE-RSA-KEY>`;
const signed = jwt.sign(payload, privateRsaKey, {
algorithm: 'RS256',
expiresIn: '5s'
})

dan verifikasi menggunakan public_key.pem

const publicRsaKey = `<YOUR-PUBLIC-RSA-KEY>`;
const decoded = jwt.verify(signed, publicRsaKey, {
39
// Never forget to make this explicit to prevent
// signature stripping attacks.
algorithms: ['RS256'],
});

Kamu bisa menyebarkan public_key.pem kepada service lain, dan mereka bisa validasi bahwa token yang dibuat benar-benar dari service kamu.

Asymmetric Secret Key (ES256)

Selain HS256, kamu bisa gunakan ES256 (ECDSA algorithms), ECDSA tidak sepopuler RSA yang sudah banyak digunakan dalam TLS, sedangkan ECDSA memiliki keamanan lebih bagus mengikuti perkembangan cracking saat ini. Selain itu, ECDSA memiliki kunci yang lebih pendek dibanding RSA.

# Generate a private key (prime256v1 is the name of the parameters used
# to generate the key, this is the same as P-256 in the JWA spec).
openssl ecparam -name prime256v1 -genkey -noout -out ecdsa_private_key.pem
# Derive the public key from the private key
openssl ec -in ecdsa_private_key.pem -pubout -out ecdsa_public_key.pem

Script diatas akan membuat file ecdsa_private_key.pem dan ecdsa_public_key.pem.

Contoh hasil secret key dan public key JANGAN GUNAKAN PRIVATE DAN PUBLIC KEY INI

➜ cat ecdsa_private_key.pem

-----BEGIN EC PRIVATE KEY----- MHcCAQEEICodx2VZ4/v4vCdiUYoSkTXQKWgflpSlHUC64CLS5Yo/oAoGCCqGSM49 AwEHoUQDQgAEvwvRUE7auEjiNQd9+lwuHW5ZmznvByMdvu1IKYO1SV++rKnOVo+U j2gMecRqionCUmmVQdJX2qk2KwBsb3Kv/Q== -----END EC PRIVATE KEY-----

➜ cat ecdsa_public_key.pem

-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEvwvRUE7auEjiNQd9+lwuHW5Zmznv ByMdvu1IKYO1SV++rKnOVo+Uj2gMecRqionCUmmVQdJX2qk2KwBsb3Kv/Q== -----END PUBLIC KEY-----

Kamu bisa gunakan secret key ECDSA menggunakan algoritma ES256 seperti menggunakan RS256.

// You can get this from private_key.pem above.
const privateEcdsaKey = `<YOUR-PRIVATE-ECDSA-KEY>`;
const signed = jwt.sign(payload, privateEcdsaKey, {
algorithm: 'ES256',
expiresIn: '5s'
});

// You can get this from public_key.pem above.
const publicEcdsaKey = `<YOUR-PUBLIC-ECDSA-KEY>`;
const decoded = jwt.verify(signed, publicEcdsaKey, {
// Never forget to make this explicit to prevent
// signature stripping attacks.
algorithms: ['ES256'],
})

Validasi Token JWT

Saat validasi harus validasi algorithm yang digunakan dan semua claim harus diperiksa juga.

Kamu harus mengira semua token yang masuk pada sistem kamu itu tidak valid, walaupun secara kunci sudah valid.

Pencegahan sedetail mungkin untuk meningkatkan keamanan aplikasi dari JWT yang dimodifikasi atau token yang digunakan tidak tepat sesuai requirement bisnis. Pertanyaan-pertanyaan seperti ini harus di ajukan saat verifikasi token JWT

  • Apakah algoritma sama dengan algoritma penerbit ?

  • Apakah iss sudah benar dari penerbit ?

  • Apakah aud berasal dari audience yang dikenal ?

  • Apakah sub tersedia di database ?

  • Apakah jti sudah benar ?

Semua pertanyaan ini menjadi pelindung sistem anda dari serangan hacker. JWT.io dan Auth0 menjabarkan lebih rinci mengenai keamanan hingga standard dalam pembuatan library JSON web token.

Library

Ada berbagai library jsonwebtoken berdasarkan teknologi yang digunakan seperti :

Auth0 membuat library jsonwebtoken dan di public di npm. silahkan periksa di https://www.npmjs.com/package/jsonwebtoken

Golang tersedia library JWT di repository berikut https://github.com/golang-jwt/jwt

Rust juga tersedia library JWT https://docs.rs/jwt/latest/jwt/

Penutup

JSON web token adalah token stateless yang memiliki desain compact, URL friendly, dan berbagai opsi algoritma keamanan penerbitan Token JWT. Pemilihan algoritma sesuai kebutuhan dan validasi yang komplit akan membuat proses pertukaran data menjadi aman.


Referensi :

  1. Peyrott, Sebastián E. The JWT Handbook Version 0.14.1 (2016-2018), Auth0 Inc.