Penjelasan Base64, Encoding URL, dan JWT
Ketiganya muncul di mana pun data harus dikirim sebagai teks: di URL, header HTTP, JSON, dan token login. Tidak satu pun menyembunyikan apa pun. Panduan ini menjelaskan cara kerja masing-masing, di mana Anda menjumpainya, dan kesalahan yang menjadi penyebab sebagian besar masalah.
Encoding Bukan Enkripsi
Encoding mengubah cara data ditulis agar bisa melewati saluran yang hanya menerima karakter tertentu. Siapa pun dapat membaliknya, karena tidak ada kunci yang terlibat. Enkripsi juga mengubah data, tetapi hanya pemegang kunci yang bisa mengembalikannya. Hash berbeda lagi: sidik jari satu arah yang sama sekali tidak bisa dibalik, seperti dijelaskan dalam Penjelasan Fungsi Hash.
Base64 dan encoding URL adalah encoding. JWT biasanya ditandatangani, yang membuktikan siapa penerbitnya dan bahwa isinya tidak diubah, tetapi isinya hanya di-encode. Jika sebuah nilai harus tetap rahasia, ia memerlukan enkripsi, bukan salah satu format ini.
Cara Kerja Base64
Base64 membaca data tiga byte (24 bit) sekaligus dan membaginya menjadi empat kelompok enam bit. Setiap kelompok adalah angka 0 sampai 63 dan ditulis sebagai satu karakter dari alfabet 64 karakter: A–Z untuk 0–25, a–z untuk 26–51, 0–9 untuk 52–61, lalu + dan /. Kata “Man” menunjukkan langkah-langkahnya:
| Langkah | M | a | n |
|---|---|---|---|
| Nilai byte | 77 | 97 | 110 |
| Bit | 01001101 | 01100001 | 01101110 |
| Empat kelompok 6 bit | 010011 · 010110 · 000101 · 101110 = 19 · 22 · 5 · 46 | ||
| Base64 | T W F u → TWFu | ||
Jika panjang masukan bukan kelipatan tiga, kelompok terakhir dilengkapi dan ditandai dengan padding: satu byte sisa menghasilkan dua karakter dan ==, dua byte sisa menghasilkan tiga karakter dan =. “Ma” menjadi TWE= dan “M” menjadi TQ==.
Karena setiap tiga byte menjadi empat karakter, Base64 membuat data sekitar sepertiga lebih besar, ditambah jeda baris yang disisipkan sebagian format. Foto 3 MB yang dikirim sebagai lampiran email berpindah sebagai sekitar 4 MB teks, dan gambar yang disematkan ke stylesheet sebagai data URL sekitar sepertiga lebih berat daripada filenya.
Di Mana Anda Menjumpai Base64
- Lampiran email (MIME) adalah teks Base64 yang dipotong 76 karakter per baris.
- Data URL seperti
data:image/png;base64,iVBORw0…memasukkan file kecil langsung ke HTML atau CSS. - Autentikasi HTTP Basic mengirim
user:passwordsebagai Base64 di header Authorization. Itu hanya menyembunyikan kata sandi dari pandangan sekilas, jadi hanya aman lewat HTTPS. - Sertifikat dan kunci dalam file PEM adalah Base64 di antara baris
-----BEGIN …-----dan-----END …-----, dipotong 64 karakter. - JSON dan XML membawa nilai biner, seperti tanda tangan atau gambar mini, sebagai string Base64 karena keduanya tidak punya tipe biner.
Base64URL dan Padding
Tanda + dan / pada Base64 standar punya arti di URL dan path file, jadi alfabet kedua, Base64URL, memakai - dan _ sebagai gantinya. Biasanya ia juga menghilangkan padding =, karena decoder bisa menghitung panjangnya. JWT, banyak token API, dan sebagian nama file memakai Base64URL. Untuk mengubah Base64 standar menjadi Base64URL, ganti + dengan -, / dengan _, lalu hapus tanda = di akhir; untuk mengembalikannya, balik penggantian itu dan tambahkan = sampai panjangnya kelipatan empat.
Percent-Encoding di URL
URL hanya boleh berisi sekumpulan karakter terbatas, dan sebagian di antaranya membentuk struktur alamat: / dan ? memisahkan path dan kueri, & dan = memisahkan parameter, # memulai fragmen. Jika sebuah nilai berisi salah satu karakter ini, atau apa pun di luar ASCII, nilai itu di-percent-encode: setiap byte dari bentuk UTF-8-nya ditulis sebagai % diikuti dua digit heksadesimal. “café” menjadi caf%C3%A9, karena é adalah dua byte C3 A9.
Huruf, angka, dan - . _ ~ tidak pernah perlu di-encode. Karakter berikut paling sering menimbulkan masalah:
| Karakter | Hasil encoding | Mengapa penting |
|---|---|---|
| spasi | %20 | Tidak diizinkan di URL |
| & | %26 | Akan memulai parameter baru |
| = | %3D | Akan mengakhiri nama parameter |
| ? | %3F | Akan memulai kueri |
| # | %23 | Akan memulai fragmen, yang tidak dikirim ke server |
| / | %2F | Akan menambah segmen path |
| + | %2B | Dibaca sebagai spasi dalam data formulir |
| % | %25 | Akan memulai urutan escape |
Encode setiap nilai secara terpisah, lalu susun URL-nya. Di JavaScript, encodeURIComponent melakukannya untuk satu nilai dan juga meng-encode / ? & = #, sedangkan encodeURI ditujukan untuk alamat lengkap dan membiarkan karakter itu apa adanya. Memakai encodeURI untuk satu nilai adalah penyebab umum string kueri yang rusak.
Tanda Plus, Spasi, dan Encoding Ganda
Formulir HTML mengirim kolomnya sebagai application/x-www-form-urlencoded, di mana spasi menjadi +. Dalam sintaks URL umum, + hanyalah tanda plus. Jadi pencarian “C++” yang dikirim sebagai q=C++ tiba di server yang mendekode data formulir sebagai “C” diikuti dua spasi; seharusnya dikirim sebagai q=C%2B%2B. Saat Anda mendekode string kueri secara manual, cari tahu dulu aturan mana yang menghasilkannya.
Encoding ganda terjadi saat nilai yang sudah di-encode di-encode lagi: %20 menjadi %2520, karena % itu sendiri menjadi %25. Jika Anda melihat %25 diikuti dua digit heksadesimal di URL, ada bagian rantai yang meng-encode dua kali; dekode sekali dan cari di mana langkah tambahan itu terjadi.
Isi Sebuah JWT
JSON Web Token (JWT) membawa klaim, seperti siapa penggunanya dan sampai kapan token berlaku, dari sistem yang menerbitkannya ke sistem yang menerimanya. Bentuk bertanda tangan yang umum terdiri dari tiga bagian Base64URL yang dipisahkan titik: header, payload, dan tanda tangan. Setelah didekode, dua bagian pertama adalah JSON biasa:
Header: {"alg": "HS256", "typ": "JWT"}
Payload: {"sub": "user-42", "role": "editor", "iat": 1767225600, "exp": 1767229200}
Standar (RFC 7519) mendefinisikan beberapa klaim terdaftar; aplikasi menambahkan klaimnya sendiri, seperti role di atas.
| Klaim | Arti |
|---|---|
| iss | Penerbit: siapa yang membuat token |
| sub | Subjek: biasanya ID pengguna atau akun |
| aud | Audiens: layanan yang menjadi tujuan token |
| exp, nbf, iat | Kedaluwarsa, tidak sebelum, diterbitkan: waktu Unix dalam detik |
| jti | ID token, untuk mendeteksi pemakaian ulang atau mencabut satu token |
Karena payload hanya di-encode, siapa pun yang memegang token dapat membacanya. Jangan masukkan data pribadi dan rahasia, dan jaga token tetap kecil: token ikut di setiap permintaan, dan banyak server membatasi ukuran header permintaan.
Bertanda Tangan Bukan Berarti Rahasia: Cara JWT Diperiksa
Tanda tangan dihitung dari header dan payload. Dengan HS256, penerbit dan penerima berbagi satu rahasia dan memakai HMAC dengan SHA-256. Dengan RS256 atau ES256, penerbit menandatangani dengan kunci privat dan penerima memeriksa dengan kunci publik pasangannya, sehingga penerima tidak bisa membuat token sendiri.
Server yang menerima token harus memverifikasi tanda tangan dengan algoritme dan kunci yang diharapkan, serta memeriksa exp, nbf, iss, dan aud, sebelum memercayai klaim apa pun. Sekadar mendekode, seperti yang dilakukan alat LeedyBox, melewatkan semua itu: alat itu menunjukkan isi token, bukan apakah token itu asli. Pustaka juga harus menolak algoritme “none”, yang menandai token tanpa tanda tangan, kecuali token tanpa tanda tangan memang diharapkan. Jika isinya sendiri harus disembunyikan, token dienkripsi (JWE) dan kemudian terdiri dari lima bagian yang tidak bisa dibaca tanpa kunci.
Masalah Umum dan Solusinya
| Gejala | Kemungkinan penyebab | Solusi |
|---|---|---|
| Base64 didekode menjadi teks acak | Datanya biner, atau teks dengan encoding lain | Periksa apa yang di-encode; simpan data biner sebagai file |
| “Karakter tidak valid” saat mendekode | Awalan data:, tanda kutip, atau alfabet Base64URL | Hapus semua sebelum koma; pakai decoder yang menerima - dan _ |
| Parameter tiba terpotong | Ada & atau # yang belum di-encode di dalam nilai | Encode setiap nilai dengan encodeURIComponent |
| Ada %2520 di URL | Nilai di-encode dua kali | Encode sekali saja, di tempat URL disusun |
| Token ditolak padahal exp masih di masa depan | Audiens atau penerbit salah, selisih jam, atau kunci berbeda | Bandingkan aud, iss, dan kunci tanda tangan dengan yang diharapkan server |
| Tanggal kedaluwarsa ribuan tahun lagi | exp ditulis dalam milidetik, bukan detik | Simpan exp, nbf, dan iat dalam detik |
Pertanyaan Umum
Apakah Base64 bisa melindungi kata sandi atau kunci API?
Tidak. Siapa pun dapat membalik Base64 dalam sedetik. Kredensial yang di-encode Base64, misalnya di file konfigurasi atau URL, sama terbukanya dengan teks biasa.
Bolehkah saya memasukkan data pribadi ke payload JWT?
Sebaiknya jangan. Siapa pun yang memegang token dapat membaca payload, termasuk ekstensi browser, log, dan proxy yang melihat permintaan. Masukkan ID ke token dan ambil detailnya di server.
Apakah encoding URL melindungi dari serangan injeksi?
Hanya dalam arti bahwa nilai tidak bisa merusak struktur URL. Server tetap harus memvalidasi dan meng-escape nilai yang sudah didekode sesuai tempat penggunaannya, seperti SQL, HTML, atau perintah shell.
Mengapa string Base64 saya lebih panjang dari filenya?
Setiap tiga byte menjadi empat karakter, jadi teksnya sekitar 33% lebih besar, dan jeda baris menambah sedikit lagi. Untuk file besar, mengirim byte secara langsung lebih efisien daripada Base64.