İçeriğe atla
HexaTransfer
Bloga dön
Sifreleme ve guvenlik

Web Crypto API rehberi: tarayıcı yerel şifreleme geliştiriciler için

Şifreli dosya aktarım uygulamaları için Web Crypto API'yi öğrenin. AES-GCM, RSA-OAEP ve anahtar yönetimi tam rehberi.

Web Crypto API (W3C'nin Web Cryptography API önerisiyle tanımlanan ve window.crypto.subtle aracılığıyla erişilen), ağ üzerinden bir şifreleme kütüphanesi göndermeksizin kriptografi işlemi yapmanın tarayıcı-yerel yoludur. AES-GCM, AES-CBC, AES-CTR, AES-KW, HMAC, RSA-OAEP, RSA-PSS, RSASSA-PKCS1-v1_5, ECDH, ECDSA, HKDF ve PBKDF2'yi tüm modern tarayıcılarda destekler (Chrome 37+, Firefox 34+, Safari 10.1+, Edge 79+). Dosya aktarım uygulamaları için bu önem taşır: şifreli metnin her baytı yüklemeden önce istemci tarafında tarayıcıda üretilebilir. Bu rehber, şifreli dosya aktarımı için önemli olan primitifleri ve her ilk implementasyonu tökezleten tuzakları adım adım ele alır.

SubtleCrypto Promise Tabanlı ve Asenkrondur

crypto.subtle üzerindeki her yöntem bir Promise döndürür. Bu kasıtlıdır: kripto işlemleri donanıma veya arka plan iş parçacıklarına aktarılabilir, dolayısıyla zorunlu asenkron yapı API'nin ana iş parçacığını engelleyecek biçimlerde kötüye kullanılmasını önler. Kod yapısı:

const key = await crypto.subtle.generateKey(
  { name: "AES-GCM", length: 256 },
  true, // extractable
  ["encrypt", "decrypt"]
);

İkinci argüman (true) anahtarı dışa aktarılabilir olarak işaretler; yani daha sonra crypto.subtle.exportKey() aracılığıyla dışa aktarılabilir. Uzun ömürlü anahtarlar için ham baytları JavaScript'e erişilemez tutmak üzere bunu false yapın. URL parçasına serileştirmeniz gereken anahtarlar için (HexaTransfer örüntüsü) true olarak ayarlayın.

Üçüncü argüman bir anahtar kullanım dizisidir. ["encrypt"] ile üretilen bir anahtar şifre çözme için kullanılamaz; AES-GCM simetrik olsa bile. Bu ayrım, güvenliği ihlal edilmiş bir şifreleme akışının geçmiş veriyi çözmek için kötüye kullanılmasını engeller.

Simetrik Dosya Şifrelemesi için AES-GCM

AES-GCM, dosya içerikleri için temel araçtır. İlişkili verilerle kimlik doğrulamalı şifreleme (AEAD) sağlar: şifreli metin artı kimlik doğrulama etiketi artı kimliği doğrulanan ama şifrelenmeyen isteğe bağlı ilişkili veri. Dosya aktarımı için NIST SP 800-38D önerilerine göre 256 bit anahtar ve 96 bit nonce kullanın.

const iv = crypto.getRandomValues(new Uint8Array(12)); // 96 bit nonce
const ciphertext = await crypto.subtle.encrypt(
  { name: "AES-GCM", iv },
  key,
  plaintext
);

Çıktı, şifreli metne eklenmiş 128 bit GCM kimlik doğrulama etiketini içerir. Şifre çözme otomatik olarak etiketi doğrular ve eşleşmezse fırlatır. Nonce'u aynı anahtarla asla yeniden kullanmayın; GCM'nin güvenliği nonce yeniden kullanımında felaket biçimde çöker (saldırganlar kimlik doğrulama anahtarını kurtarabilir). Her dosyanın taze bir anahtar aldığı dosya aktarımında rastgele nonce'lar güvenlidir; uzun ömürlü anahtarlar için sayaç kullanın.

Parola Türetilen Anahtarlar için PBKDF2

Kullanıcılar bir dosyayı korumak üzere parola girdiğinde, parolayı doğrudan AES anahtarı olarak kullanamazsınız. Önce PBKDF2'den geçirin:

const passwordKey = await crypto.subtle.importKey(
  "raw",
  new TextEncoder().encode(password),
  "PBKDF2",
  false,
  ["deriveKey"]
);

const aesKey = await crypto.subtle.deriveKey(
  {
    name: "PBKDF2",
    salt: crypto.getRandomValues(new Uint8Array(16)),
    iterations: 600000,
    hash: "SHA-256",
  },
  passwordKey,
  { name: "AES-GCM", length: 256 },
  false,
  ["encrypt", "decrypt"]
);

OWASP'ın 2023 parola hashing rehberi, PBKDF2-SHA-256 için minimum 600.000 iterasyon öneriyor. 310.000'in altındaki her şey güncel en iyi uygulamanın altındadır. Salt rastgele olmalı ve şifreli metinle birlikte depolanmalıdır (gizli değil, yalnızca benzersiz olması gerekir).

2026'da yeni kodlar için PBKDF2 yerine Argon2id'yi göz önünde bulundurun. Argon2, henüz Web Crypto API'de yer almıyor; ancak argon2-browser veya @noble/hashes gibi kütüphaneler JavaScript/WASM implementasyonları sağlıyor. Argon2id, GPU saldırılarına PBKDF2'den çok daha iyi direnir.

Anahtar Sarma için RSA-OAEP

Bir dosyanın AES anahtarını alıcının genel anahtarıyla şifrelemek istediğiniz senaryolarda RSA-OAEP kullanın. Anahtar üretin:

const keyPair = await crypto.subtle.generateKey(
  {
    name: "RSA-OAEP",
    modulusLength: 4096,
    publicExponent: new Uint8Array([1, 0, 1]), // 65537
    hash: "SHA-256",
  },
  true,
  ["encrypt", "decrypt"]
);

Yeni anahtarlar için modulusLength 4096 kullanın; 2048 hâlâ kabul edilebilir ancak kuantum zaman çizelgeleri netleştikçe kullanımdan kalkacak. RSA-OAEP yalnızca küçük verileri şifreler (modulusLength/8 - 2*hashLength - 2 bayta kadar), bu yüzden dosya içeriklerini doğrudan şifrelemek yerine 256 bit AES anahtarını sarın.

Performansa duyarlı uygulamalarda P-256 veya P-384 ile ECDH, RSA'ya daha iyi bir alternatiftir. Anahtar üretimi büyük ölçüde daha hızlıdır ve anahtar boyutları çok daha küçüktür.

Büyük Dosyalar için Akış İşleme

2 GB'lık bir dosya tarayıcı ArrayBuffer'ına rahat biçimde sığmaz. Chrome, Firefox ve Safari, File.stream() ile ReadableStream döndüren akışları okumanıza ve parçalar halinde işlemenize olanak tanır. Web Crypto API'nin kendisinde henüz akış şifreleme/çözme yöntemleri yoktur (bu spesifikasyondaki bir boşluktur); iki çözüm vardır:

  1. Parçalara bölün (64 KB veya 1 MB) ve her birini benzersiz nonce ile şifreleyin. Alıcı sırayla birleştirir. Bu, tüm dosya üzerinde gerçek AEAD'ı kaybettirir; ancak çoğu durum için işe yarar.
  2. Akış AEAD modlarını (XChaCha20-Poly1305 veya AES-GCM-SIV gibi) destekleyen bir WASM kripto kütüphanesi kullanın (libsodium.js, WASM arka ucuyla @noble/ciphers).

Birkaç yüz megabaytın altındaki aktarımlar için tamponlanmış AES-GCM iyice çalışır ve çok daha basittir. Bu sınırın üzerinde, bellek baskısını önlemek için akış işleme gereklidir.

Anahtar Dışa Aktarma, İçe Aktarma ve URL Parçaları

Anahtarın URL parçasında gezdiği HexaTransfer tarzı akışlar için:

const rawKey = await crypto.subtle.exportKey("raw", aesKey);
const keyBase64 = btoa(String.fromCharCode(...new Uint8Array(rawKey)));
// URL'yi şu şekilde paylaşın: https://example.com/file/abc123#key=keyBase64

URL parçaları HTTP isteklerinde sunuculara gönderilmez (tarayıcı bunları siler). Bu, kullanıcı bir bağlantı paylaşsa bile anahtarı istemci tarafında tutar. Alıcı tarafında:

const keyBase64 = window.location.hash.slice(5); // "#key=" kısmını çıkar
const rawKey = Uint8Array.from(atob(keyBase64), c => c.charCodeAt(0));
const key = await crypto.subtle.importKey(
  "raw", rawKey, "AES-GCM", false, ["decrypt"]
);

URL kodlama sorunlarını önlemek için base64url kodlaması kullanın (+ yerine -, / yerine _ ve dolgu kaldırma).

Yaygın Tuzaklar

Salt veya IV için Math.random() kullanmak. Math.random() kriptografik açıdan güvenli değildir. Her zaman crypto.getRandomValues() kullanın.

Aynı anahtarla IV'ü yeniden kullanmak. GCM'nin güvenlik özellikleri nonce yeniden kullanımında tamamen bozulur. Rastgele 96 bit nonce'lar, aynı anahtar altında yaklaşık 2^48 şifreleme işleminden sonra (doğum günü sınırı) çakışmaya başlar. Her dosyanın kendi anahtarına sahip olduğu dosya aktarımı için güvenlidir; uzun ömürlü anahtarlar için sayaç kullanın.

HTTPS'i unutmak. crypto.subtle yalnızca güvenli bağlamlarda (HTTPS veya localhost) mevcuttur. Güvensiz bir kaynakta crypto.subtle tanımsızdır.

Dışa aktarılabilir anahtarları korumasız IndexedDB'de depolamak. Anahtarları kalıcı kılmanız gerekiyorsa, depolamadan önce bunları sarın (örn. parola türetilmiş anahtarla). Ham AES anahtarlarını asla kaynak üzerindeki herhangi bir betiğin erişebildiği localStorage'da depolamayın.

Kullanıcı tarafından sağlanan parolaları PBKDF2 olmadan güvenmek. UTF-8 baytlarına dönüştürülmüş ham bir parola, 256 bit anahtar değildir. Her zaman türetin.

Kimlik doğrulama etiketlerini doğrulamamak. crypto.subtle.decrypt(), AES-GCM için bunu otomatik yapar; ancak üstünde özel protokoller uygularsanız kontrolü atlamamaya dikkat edin.

Tarayıcı Desteği Nüansları

Tüm büyük tarayıcılar HTTPS üzerinde Web Crypto'yu destekler. Bazı ayrıntılar:

  • Safari'nin PBKDF2'si yıllarca Chrome/Firefox'tan daha yavaştı; uçurum Safari 15'te kapandı.
  • Firefox daha katı girdi doğrulaması uygular; Chrome'da çalışan kod Firefox'ta OperationError fırlatabilir. Her ikisinde de test edin.
  • Service worker'larında Web Crypto çalışır, ancak kayıt kapsamının HTTPS olması gerekir.
  • Node.js, Node 15'ten itibaren require("crypto").webcrypto ile uyumlu bir API sunar; izomorfik kripto kodu için kullanışlıdır.

Bunun Yerine Kütüphane Ne Zaman Kullanılmalı

Web Crypto temelleri iyi karşılar; ancak ChaCha20-Poly1305, Argon2, X25519 ve Ed25519 gibi modern primitifleri desteklemez (Ed25519 gelme aşamasındadır). Bunlar için libsodium.js (WASM aracılığıyla) veya @noble/ciphers / @noble/curves (saf JavaScript, denetlenmiş) önde gelen seçeneklerdir. HexaTransfer, dosya aktarım yolunu bağımlılık gerektirmeksizin kapsadığı için AES-GCM ve PBKDF2 için Web Crypto primitiflerini doğrudan kullanır.

Tam şifreli aktarım akışı için Web Crypto 100 satırın altında çalışır: AES anahtarı üret, türet veya rastgele oluştur, dosyayı şifrele, şifreli metni yükle, parçada anahtarla bağlantıyı paylaş, alıcı anahtarı içe aktarıp şifreyi çözer. Bunların tamamı budur.

hexatransfer.com'da deneyin — ücretsiz, hesap gerekmez, 10 GB'a kadar.

Uçtan uca şifreleme ile büyük dosyaları güvenle gönderin

Uçtan uca şifreleme ile 10 GB'a kadar dosya ücretsiz aktarın. Hesap gerekmez. Dosyalarınız yüklenmeden önce tarayıcınızda şifrelenir — başka kimse okuyamaz.

Dosya gönder