Bir API'den dönen yanıtta garip görünümlü uzun bir karakter dizisi gördüyseniz, büyük ihtimalle Base64 ile karşılaşmışsınızdır. SGVsbG8gV29ybGQ= gibi bir şey. Şifreli değil ; ama okunabilir de değil. Tam olarak ne işe yarıyor?
Base64, binary (ikili) verileri ASCII metin formatına dönüştüren bir encoding yöntemidir. 1987'de RFC 989 ile tanımlandı, güncel standardı RFC 4648. Adındaki "64" rakamı kullandığı karakter sayısından gelir: A-Z, a-z, 0-9, + ve /, toplam 64 karakter. Şifreleme ile sık karıştırılıyor; ama bambaşka mekanizmalar.
Binary veriyi neden metne çevirmek gerekir?
Sorun uyumsuzluktan çıkar. Email protokolü SMTP, 1980'lerde yalnızca 7-bit ASCII karakterleri destekleyecek biçimde tasarlandı; bir fotoğrafın binary verisini bu kanal üzerinden taşımak için önce metin formatına çevirmek gerekiyordu; Base64 tam bu ihtiyaç için geliştirildi.
Günümüzde durum kısmen değişti ama temel uyumsuzluk aynı kaldı. JSON formatı binary veri taşıyamaz; URL'ler belirli karakterleri kabul etmez; HTML içine doğrudan binary veri gömemezsiniz. Tüm bu senaryolarda Base64 devreye girer.
3 byte nasıl 4 karaktere dönüşür?
Girdi olarak 3 byte (24 bit) alınır ve 6'şar bitlik 4 gruba bölünür. Her grup 0-63 arasında bir sayıya karşılık gelir; bu sayı da Base64 alfabesindeki bir karakterle eşleştirilir.
"Mer" harfleri üzerinden:
M = 77 → 01001101
e = 101 → 01100101
r = 114 → 01110010
Birleşik: 010011 010110 010101 110010
Decimal: 19 22 21 50
Base64: T W V y
"Mer" metni Base64'te "TWVy" olur. 3 karakter girdi, 4 karakter çıktı; bu oran değişmez. Base64'ün her zaman yaklaşık %33 daha büyük çıktı üretmesinin nedeni de bu sabit ilişkidir.
Padding nedir?
Girdi her zaman 3'ün katı olmayabilir. "Hi" kelimesi sadece 2 byte. Bu durumda eksik byte'lar sıfırla tamamlanır ve çıktının sonuna = karakteri eklenir. Tek byte eksikse bir =, iki byte eksikse iki = eklenir.
"Hi" → SGk= (2 byte girdi, 1 padding)
"H" → SA== (1 byte girdi, 2 padding)
"Mer" → TWVy (3 byte girdi, padding yok)
Padding, decode işleminde orijinal verinin uzunluğunu doğru hesaplamak için gereklidir. URL-Safe Base64 varyantında padding kaldırılır çünkü = karakteri URL'lerde sorun çıkarır.
Hangi sistemlerde karşılaşılır?
Kullanım alanı düşünüldüğünden geniş. Birkaç yaygın senaryo:
Data URI ile HTML/CSS'e görsel gömme
Küçük ikonları ve logoları doğrudan HTML veya CSS içine gömmek mümkün. data:image/png;base64,iVBOR... formatında bir string, tarayıcının ayrı bir HTTP isteği yapmasını engeller. 1-2 KB'lık ikonlar için mantıklı bir yaklaşım; her ikon için ayrı sunucu isteği yapmak yerine tek seferde yüklenir.
Base64 çıktısı orijinalden %33 büyük olduğu için büyük görsellerde bu yöntem ters teper. 50 KB'lık bir resim Base64'e çevrildiğinde yaklaşık 67 KB olur; üstelik tarayıcı bu veriyi cache'leyemez. Genel kural: 5 KB'ın altındaki dosyalar için Data URI, üstündekiler için normal dosya referansı kullanılmalı (CSS sprite gibi toplu ikon senaryolarında bu eşik daha da anlam kazanır).
Eşik net. Aşıldığında cache ve boyut her ikisi birden sorun üretir.
Email ekleri (MIME)
Email ile gönderdiğiniz her ek ( PDF, resim, ZIP dosyası ) arka planda Base64'e dönüştürülür. MIME (Multipurpose Internet Mail Extensions) standardı bunu zorunlu kılar. Email istemciniz eki otomatik olarak encode eder, alıcının istemcisi de otomatik decode eder. Kullanıcı bu sürecin farkında bile olmaz.
API'lerde binary veri taşıma
REST API'ler genellikle JSON formatında veri taşır. JSON'da binary veri için doğal bir tip yok. Profil fotoğrafı yükleme, dosya paylaşımı, dijital imza gibi işlemlerde binary veri Base64'e çevrilip JSON içinde taşınır.
{
"kullanici": "ahmet",
"avatar": "iVBORw0KGgoAAAANSUhEUgAA...",
"dosya_tipi": "image/png"
}
Alternatif olarak multipart/form-data kullanılabilir; Base64 yaklaşımı tek bir JSON nesnesi içinde her şeyi taşıma kolaylığı sağlar ama büyük dosyalarda boyut artışı nedeniyle multipart tercih edilir.
JWT token yapısı
JWT'nin header ve payload kısmı Base64URL ile encode edilir; signature hariç bu iki parça herhangi bir decode aracıyla okunabilir; şifrelenmemiş, yalnızca format dönüşümü yapılmış.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Decode →
{"alg":"HS256","typ":"JWT"}
Base64URL, standart Base64'ün URL'lerde sorun yaratan iki karakterini değiştirmiş varyantıdır: + URL'de boşluk, / path ayırıcı olarak yorumlandığından query string'e Base64 veri koyduğunuzda içerik bozulur. Base64URL bu ikisini - ve _ ile değiştirir, = padding'i de kaldırır. OAuth parametreleri ve URL query string'lerinde gördüğünüz Base64 varyantı budur; dönüşüm mantığı standart Base64 ile aynı, yalnızca üç karakter farkı var.
Base64 şifreleme midir?
Hayır. Bu en sık yapılan yanlış anlamadır ve güvenlik açıklarına yol açabilir.
Encoding, veriyi farklı bir formata dönüştürür ; herhangi bir anahtar gerekmez. Herkes encode edebilir; herkes decode edebilir. Amaç taşınabilirliktir, gizlilik değil.
Şifreleme (encryption) ise bambaşka bir mekanizma. AES veya RSA gibi algoritmalar bir anahtar ile veriyi okunamaz hale getirir; anahtarı olmayan kişi veriyi çözemez.
| Özellik | Base64 (Encoding) | AES (Şifreleme) |
|---|---|---|
| Anahtar gerekli mi? | Hayır | Evet |
| Herkes çözebilir mi? | Evet | Hayır |
| Amaç | Format dönüşümü | Veri gizleme |
| Güvenlik sağlar mı? | Hayır | Evet |
Şifre, API anahtarı veya kişisel veri gibi hassas bilgileri Base64 ile "gizlemeye" çalışmak tehlikelidir. Tarayıcının geliştirici araçlarında veya herhangi bir online decode aracında saniyeler içinde okunabilir.
Tarayıcıda Base64 işlemleri
JavaScript'te Base64 işlemleri için iki yerleşik fonksiyon var: btoa() encode, atob() decode yapar.
// Encode
btoa("Merhaba") // "TWVyaGFiYQ=="
// Decode
atob("TWVyaGFiYQ==") // "Merhaba"
Basit görünür.
Ama btoa() arka planda yalnızca Latin-1 karakter setini destekler; Türkçe karakterler (ş, ç, ğ, ı, ö, ü) ya da emoji gibi Unicode içerik doğrudan geçirildiğinde InvalidCharacterError hatası alırsınız; çözüm, önce encodeURIComponent() ile UTF-8'e dönüştürmek, ardından btoa()'ya vermektir:
// Türkçe karakter desteği
const encoded = btoa(unescape(encodeURIComponent("Türkçe şğüöçı")));
const decoded = decodeURIComponent(escape(atob(encoded)));
Node.js tarafında ise Buffer sınıfı kullanılır:
// Node.js
Buffer.from("Merhaba").toString("base64") // Encode
Buffer.from("TWVyaGFiYQ==", "base64").toString() // Decode
Dosya bazlı dönüşümlerde FileReader API'si devreye girer. readAsDataURL() metodu bir dosyayı okuyup Base64 formatında Data URI olarak döndürür; drag & drop ile dosya yükleyip anında Base64 çıktısı almak bu yöntemle mümkün. Metin ve dosya dönüşümlerini doğrudan test edebilirsiniz.
Boyut etkisi ve performans
10 MB'lık bir dosyayı Base64 olarak JSON içinde taşırsanız yanıt 13.3 MB'a çıkar; bu veri JSON parser tarafından string olarak bellekte tutulduğundan gerçek bellek kullanımı daha da yüksek olabilir. Her 3 byte girdi 4 karakter çıktı üretir; bu %33'lük artış küçük veriler için önemsiz görünür, API ölçeğinde belirgin bir yük oluşturur.
Boyut büyüyünce sorun ikiye katlanır: hem transfer hem bellek.
Performans açısından kırılma noktaları şunlar:
- 5 KB altındaki dosyalar için Data URI mantıklı (HTTP istek tasarrufu)
- Büyük dosyalarda
multipart/form-dataveya doğrudan binary transfer tercih edilmeli - API yanıtlarında GZIP sıkıştırma Base64'ün boyut artışını kısmen telafi eder
- Tarayıcıda büyük Base64 string'leri DOM'a eklemek render performansını düşürür
Data URI yolunu seçmeden önce görselin boyutunu kontrol etmek gerekir; 5 KB sınırını çok hızlı aşan dosyalar için boyutu önceden düşürmek daha temiz bir başlangıç noktası sağlar. Email ekleri, JWT token'ları, API payload'ları ; her üç senaryoda da karar aynı: boyut artışını kabul mı ediyorsunuz, yoksa binary transfer mi tercih ediyorsunuz? Eşik 5 KB. Altındaysa Data URI; üstündeyse multipart ya da doğrudan binary aktarım. Encoding burada bir güvenlik mekanizması değil, taşıma formatıdır ; hassas veriler için her koşulda gerçek şifreleme algoritmaları kullanılmalıdır.
JSON verilerinizi API'ye göndermeden önce doğrulamak da iyi bir alışkanlık ; özellikle Base64 ile birlikte kullanıldığında format hataları sık karşılaşılan bir sorun.