Base64, URL Kodlama ve JWT Açıklaması
Üçü de verinin metin olarak taşınması gereken her yerde karşınıza çıkar: URL'lerde, HTTP başlıklarında, JSON'da ve oturum açma belirteçlerinde. Hiçbiri bir şey gizlemez. Bu rehber her birinin nasıl çalıştığını, nerede karşılaştığınızı ve sorunların çoğuna yol açan hataları açıklar.
Kodlama Şifreleme Değildir
Kodlama, verinin yazılış biçimini değiştirir; böylece veri yalnızca belirli karakterleri kabul eden bir kanaldan geçebilir. İşin içinde anahtar olmadığı için herkes kodlamayı geri çevirebilir. Şifreleme de veriyi dönüştürür, ancak onu yalnızca anahtara sahip olan geri getirebilir. Hash ise başka bir şeydir: hiç geri çevrilemeyen tek yönlü bir parmak izi. Bunu Hash Fonksiyonları Açıklaması rehberinde bulabilirsiniz.
Base64 ve URL kodlama birer kodlamadır. Bir JWT genellikle imzalıdır; imza, belirteci kimin verdiğini ve içeriğin değiştirilmediğini kanıtlar, ancak içerik yalnızca kodlanmıştır. Bir değerin gizli kalması gerekiyorsa şifreleme gerekir, bu biçimlerden biri değil.
Base64 Nasıl Çalışır?
Base64 veriyi üçer bayt (24 bit) okur ve bunları altı bitlik dört gruba böler. Her grup 0 ile 63 arasında bir sayıdır ve 64 karakterlik bir alfabeden tek bir karakterle yazılır: 0–25 için A–Z, 26–51 için a–z, 52–61 için 0–9, ardından + ve /. “Man” kelimesi adımları gösterir:
| Adım | M | a | n |
|---|---|---|---|
| Bayt değeri | 77 | 97 | 110 |
| Bitler | 01001101 | 01100001 | 01101110 |
| 6 bitlik dört grup | 010011 · 010110 · 000101 · 101110 = 19 · 22 · 5 · 46 | ||
| Base64 | T W F u → TWFu | ||
Girdinin uzunluğu üçün katı değilse son grup tamamlanır ve dolgu (padding) ile işaretlenir: kalan bir bayt iki karakter ve == verir, kalan iki bayt üç karakter ve = verir. “Ma” TWE=, “M” ise TQ== olur.
Her üç bayt dört karaktere dönüştüğü için Base64 veriyi yaklaşık üçte bir büyütür; buna bazı biçimlerin eklediği satır sonları da eklenir. E-posta eki olarak gönderilen 3 MB'lık bir fotoğraf yaklaşık 4 MB metin olarak taşınır, bir stil sayfasına data URL olarak gömülen bir görsel de dosyadan yaklaşık üçte bir daha ağırdır.
Base64 ile Nerede Karşılaşırsınız?
- E-posta ekleri (MIME) satır başına 76 karakterde bölünen Base64 metnidir.
- Data URL'ler, örneğin
data:image/png;base64,iVBORw0…, küçük bir dosyayı doğrudan HTML veya CSS'e koyar. - HTTP Basic kimlik doğrulaması,
user:passworddeğerini Authorization başlığında Base64 olarak gönderir. Bu, parolayı yalnızca ilk bakışta gizler; bu yüzden yalnızca HTTPS üzerinden güvenlidir. - Sertifikalar ve anahtarlar PEM dosyalarında
-----BEGIN …-----ve-----END …-----satırları arasında, 64 karakterde bölünmüş Base64'tür. - JSON ve XML, imza veya küçük resim gibi ikili değerleri Base64 dizesi olarak taşır, çünkü ikili bir veri türleri yoktur.
Base64URL ve Dolgu
Standart Base64'teki + ve / karakterlerinin URL'lerde ve dosya yollarında anlamı vardır; bu yüzden ikinci bir alfabe olan Base64URL bunların yerine - ve _ kullanır. Çözücü uzunluğu hesaplayabildiği için genellikle = dolgusunu da atar. JWT'ler, birçok API belirteci ve bazı dosya adları Base64URL kullanır. Standart Base64'ü Base64URL'ye çevirmek için + yerine -, / yerine _ yazın ve sondaki = işaretlerini silin; geri çevirmek için değişiklikleri tersine yapın ve uzunluk dördün katı olana kadar = ekleyin.
URL'lerde Yüzde Kodlama
Bir URL yalnızca sınırlı bir karakter kümesi içerebilir ve bunların bazıları adresin yapısını oluşturur: / ve ? yolu ve sorguyu ayırır, & ve = parametreleri ayırır, # parçayı başlatır. Bir değer bu karakterlerden birini ya da ASCII dışındaki herhangi bir karakteri içerdiğinde yüzde kodlanır: UTF-8 biçimindeki her bayt % ve ardından iki onaltılık basamak olarak yazılır. “café”, é iki bayttan (C3 A9) oluştuğu için caf%C3%A9 olur; Türkçedeki “ş” de aynı şekilde %C5%9F olur.
Harfler, rakamlar ve - . _ ~ hiçbir zaman kodlanmaz. En sık sorun çıkaran karakterler şunlardır:
| Karakter | Kodlanmış hali | Neden önemli? |
|---|---|---|
| boşluk | %20 | URL'de kullanılamaz |
| & | %26 | Yeni bir parametre başlatır |
| = | %3D | Parametre adını bitirir |
| ? | %3F | Sorguyu başlatır |
| # | %23 | Sunucuya gönderilmeyen parçayı başlatır |
| / | %2F | Yola bir bölüm ekler |
| + | %2B | Form verisinde boşluk olarak okunur |
| % | %25 | Bir kaçış dizisi başlatır |
Her değeri ayrı ayrı kodlayın, sonra URL'yi oluşturun. JavaScript'te encodeURIComponent bunu tek bir değer için yapar ve / ? & = # karakterlerini de kodlar; encodeURI ise tam bir adres içindir ve bu karakterlere dokunmaz. Tek bir değer için encodeURI kullanmak, bozuk sorgu dizelerinin yaygın bir nedenidir.
Artı İşaretleri, Boşluklar ve Çift Kodlama
HTML formları alanlarını application/x-www-form-urlencoded olarak gönderir ve burada boşluk + olur. Genel URL söz diziminde ise + yalnızca bir artı işaretidir. Bu yüzden q=C++ olarak gönderilen bir “C++” araması, form verisini çözen bir sunucuya “C” ve ardından iki boşluk olarak ulaşır; doğrusu q=C%2B%2B olarak göndermektir. Bir sorgu dizesini elle çözerken önce hangi kuralla oluşturulduğunu kontrol edin.
Çift kodlama, zaten kodlanmış bir değer yeniden kodlandığında olur: %20, % işaretinin kendisi %25 olduğu için %2520'ye dönüşür. Bir URL'de %25 ve ardından iki onaltılık basamak görürseniz zincirdeki bir adım iki kez kodlamıştır; bir kez çözün ve fazladan adımın nerede olduğunu bulun.
Bir JWT'nin İçinde Ne Var?
JSON Web Token (JWT), kullanıcının kim olduğu ve belirtecin ne zamana kadar geçerli olduğu gibi beyanları (claim) belirteci veren sistemden onu alan sisteme taşır. Yaygın imzalı biçim, noktalarla ayrılmış üç Base64URL bölümünden oluşur: başlık, yük (payload) ve imza. Çözüldüğünde ilk ikisi sıradan JSON'dur:
Header: {"alg": "HS256", "typ": "JWT"}
Payload: {"sub": "user-42", "role": "editor", "iat": 1767225600, "exp": 1767229200}
Standart (RFC 7519) birkaç kayıtlı beyan tanımlar; uygulamalar yukarıdaki role gibi kendi beyanlarını ekler.
| Beyan | Anlamı |
|---|---|
| iss | Veren: belirteci kim oluşturdu |
| sub | Konu: genellikle kullanıcı veya hesap kimliği |
| aud | Hedef kitle: belirtecin amaçlandığı hizmet |
| exp, nbf, iat | Sona erme, öncesinde geçersiz, verilme: saniye cinsinden Unix zamanı |
| jti | Belirteç kimliği; yeniden kullanımı tespit etmek veya tek bir belirteci iptal etmek için |
Yük yalnızca kodlandığı için belirteci elinde tutan herkes onu okuyabilir. Kişisel veri ve gizli bilgi koymayın, belirteci de küçük tutun: her istekle birlikte gider ve birçok sunucu istek başlıklarının boyutunu sınırlar.
İmzalı Olmak Gizli Olmak Demek Değildir: JWT Nasıl Doğrulanır?
İmza, başlık ve yük üzerinden hesaplanır. HS256'da veren ve alan taraf ortak bir gizli anahtar paylaşır ve SHA-256 ile HMAC kullanır. RS256 veya ES256'da veren taraf özel anahtarla imzalar, alan taraf da eşleşen ortak anahtarla doğrular; böylece alan taraf kendi belirtecini üretemez.
Belirteci alan sunucu, herhangi bir beyana güvenmeden önce imzayı beklenen algoritma ve anahtarla doğrulamalı, exp, nbf, iss ve aud değerlerini de kontrol etmelidir. LeedyBox aracının yaptığı gibi yalnızca çözmek bunların hepsini atlar: belirtecin içinde ne olduğunu gösterir, gerçek olup olmadığını değil. Kütüphaneler ayrıca imzasız bir belirteci belirten “none” algoritmasını, imzasız belirteçler bilerek beklenmiyorsa reddetmelidir. İçeriğin kendisinin gizlenmesi gerekiyorsa belirteç şifrelenir (JWE) ve anahtar olmadan okunamayan beş bölümden oluşur.
Yaygın Sorunlar ve Çözümleri
| Belirti | Olası neden | Çözüm |
|---|---|---|
| Base64 anlamsız metne çözülüyor | Veri ikili ya da başka bir karakter kodlamasındaki metin | Neyin kodlandığını kontrol edin; ikili veriyi dosya olarak kaydedin |
| Çözerken “geçersiz karakter” | data: öneki, tırnak işaretleri veya Base64URL alfabesi | Virgüle kadar her şeyi silin; - ve _ kabul eden bir çözücü kullanın |
| Parametre kesik ulaşıyor | Değerin içinde kodlanmamış bir & veya # | Her değeri encodeURIComponent ile kodlayın |
| URL'de %2520 | Değer iki kez kodlanmış | Yalnızca bir kez, URL'nin oluşturulduğu yerde kodlayın |
| exp gelecekte olduğu halde belirteç reddediliyor | Yanlış hedef kitle veya veren, saat farkı ya da farklı anahtar | aud, iss ve imza anahtarını sunucunun beklediğiyle karşılaştırın |
| Sona erme tarihi binlerce yıl sonra | exp saniye yerine milisaniye olarak yazılmış | exp, nbf ve iat değerlerini saniye olarak saklayın |
Sık Sorulan Sorular
Base64 bir parolayı veya API anahtarını koruyabilir mi?
Hayır. Herkes Base64'ü bir saniyede geri çevirebilir. Örneğin bir yapılandırma dosyasında veya URL'de Base64 ile kodlanmış kimlik bilgileri, düz metin kadar açıktadır.
JWT yüküne kişisel veri koyabilir miyim?
Koymamak daha iyidir. Belirteci elinde tutan herkes yükü okuyabilir; isteği gören tarayıcı eklentileri, günlükler ve proxy'ler de buna dahildir. Belirtece bir kimlik koyun, ayrıntıları sunucudan alın.
URL kodlama enjeksiyon saldırılarına karşı korur mu?
Yalnızca bir değerin URL'nin yapısını bozamaması anlamında. Sunucu yine de çözülmüş değeri, kullanıldığı yere göre (SQL, HTML veya bir kabuk komutu gibi) doğrulamalı ve kaçış işlemi uygulamalıdır.
Base64 dizem neden dosyadan daha uzun?
Her üç bayt dört karaktere dönüşür, bu yüzden metin yaklaşık %33 daha büyüktür; satır sonları da biraz daha ekler. Büyük dosyalarda baytları doğrudan göndermek Base64'ten daha verimlidir.