Oluşturun an Şifreli Dosya Paylaşımı App from Scratch
Step-by-step tutorial to build an encrypted dosya sharing application. Frontend encryption, secure backend, ve deployment walkthrough.
Şifreli bir dosya paylaşım uygulaması geliştirmek, kriptografiyi sunucuya değil tarayıcıya koymak demektir. Minimal bir yığın şöyle görünür: Web Crypto API aracılığıyla AES-256-GCM ile şifreleyen Vite tabanlı bir React ön ucu, her yüklemeyi opak bir blob olarak ele alan bir Fastify arka ucu, S3 uyumlu depolama (Cloudflare R2 veya Backblaze B2) ve şifre çözme anahtarının sunucuya hiç ulaşmaması için # işaretinden sonra yer aldığı kısa bir paylaşım URL'si. Çalışan bir sürümü yaklaşık 400 satır kodla gönderebilir ve aylık 150 TL'nin altında barındırabilirsiniz.
Gerçekten Önemli Olan Mimari Kararlar
En kritik karar şifreleme anahtarının nerede bulunduğudur. Sunucunuza bir kez dahi değerse, uçtan uca şifrelemeniz yoktur; fazladan adımlarla sunucu tarafı şifreleme yapıyorsunuzdur. Doğru desen şudur: tarayıcıda rastgele 256 bitlik bir anahtar oluşturun, dosyayı bu anahtarla şifreleyin, şifreli metni yükleyin ve anahtarı URL parçasına koyun (https://uygulamaniz.com/f/abc123#k=base64key). Tarayıcılar HTTP isteklerinde parçaları hiçbir zaman göndermez; bu nedenle anahtar istemci tarafında kalır.
İkinci karar: parçalı yüklemeler. 100 MB üzerindeki dosyalar için devam ettirilebilir çok parçalı yüklemeler gereklidir; aksi takdirde her kararsız Wi-Fi transferi öldürür. S3'ün çok parçalı API'si minimum 5 MB parça ve 10.000 parçaya kadar destek sunarak 50 GB tavan sağlar. Bunu ilk günden planlayın.
Proje İskeletini Kurma
İki paket ile başlayın: Vite + React ön ucu ve Fastify arka ucu. Ön uç tüm kriptografiyi yönetir, arka uç depolamayı ve meta verileri üstlenir. ArrayBuffer ve CryptoKey üzerinde tür güvenliği kazanmak için TypeScript kullanın.
pnpm create vite@latest frontend -- --template react-ts
pnpm create fastify backend
Arka uca şu bağımlılıkları ekleyin: @fastify/multipart, @aws-sdk/client-s3, @aws-sdk/s3-request-presigner ve paylaşım meta verileri için better-sqlite3. SQLite şemanızı küçük tutun: shares(id, object_key, size_bytes, expires_at, download_count, max_downloads). Dosya adı yok, kullanıcı verisi yok, IP adresi yok.
Ön Uç Şifreleme Boru Hattını Yazma
Bir anahtar oluşturun, AES-256-GCM ile şifreleyin ve URL parçası için şifreli metin blobu ile base64 anahtarı üretin:
async function encryptFile(file: File) {
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']
);
const iv = crypto.getRandomValues(new Uint8Array(12));
const plaintext = await file.arrayBuffer();
const ciphertext = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv }, key, plaintext
);
const rawKey = await crypto.subtle.exportKey('raw', key);
const blob = new Blob([iv, new Uint8Array(ciphertext)]);
return { blob, keyBase64: toBase64(rawKey) };
}
50 MB üzerindeki dosyalar için bunu 4 MB parçaları şifreleyip bir ReadableStream'e ekleyen akış sürümüyle değiştirin. Mobil Safari yığını, tek bir ArrayBuffer'da yaklaşık 400 MB'dan büyük herhangi bir şeyde çöker.
Yükleme Uç Noktasını Tasarlama
Arka uç yararlı hiçbir şey bilmemelidir. Şifreli metinle bir POST kabul edin, rastgele 16 karakterlik URL güvenli bir kimlik oluşturun, sona erme süresiyle birlikte SQLite'a kaydedin ve gövdeyi doğrudan S3'e aktarın:
fastify.post('/upload', async (req, reply) => {
const id = nanoid(16);
const key = `blobs/${id}`;
const upload = new Upload({
client: s3,
params: { Bucket: 'hexa-transfers', Key: key, Body: req.raw }
});
await upload.done();
db.prepare('INSERT INTO shares VALUES (?, ?, ?, ?, 0, ?)').run(
id, key, req.headers['content-length'], Date.now() + 7*86400*1000, 10
);
return { id };
});
Varsayılan sona erme 7 gün, maksimum 10 indirme. Agresif varsayılanlar istiyorsunuz çünkü alternatif sınırsız depolama büyümesidir. Süresi dolan blob'ları silmek için geceleri bir cron çalıştırın.
Parça Anahtarlarıyla Paylaşım Bağlantıları Oluşturma
Yükleme tamamlandığında paylaşım URL'sini istemci tarafında oluşturun:
const { id } = await uploadResponse.json();
const shareUrl = `${location.origin}/f/${id}#k=${keyBase64}`;
Bu parça kullanıcının tarayıcısından hiçbir zaman çıkmaz. Bir alıcı bağlantıya tıkladığında React uygulamanız window.location.hash'i okur, anahtarı ayrıştırır, şifreli metni alır ve yerel olarak şifre çözer. Sunucunun düz metne giden tek yolu, kullanıcıya kötü amaçlı JavaScript göndermektir; bu nedenle sıkı bir İçerik Güvenliği Politikası göndermeniz ve alt kaynak karmalarını sabitlemeniz tam da bu yüzden önemlidir.
İndirme Akışını Uygulama
İndirme sayfasında şifreli metni akış olarak çekin ve parça hizalı şifresini çözün:
const keyRaw = base64ToBytes(location.hash.slice(3));
const key = await crypto.subtle.importKey(
'raw', keyRaw, { name: 'AES-GCM' }, false, ['decrypt']
);
const resp = await fetch(`/blob/${id}`);
const iv = new Uint8Array(await resp.body.getReader().read().then(r => r.value.slice(0, 12)));
const ct = await resp.arrayBuffer();
const pt = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ct.slice(12));
const url = URL.createObjectURL(new Blob([pt]));
Büyük dosyalar için StreamSaver.js veya Dosya Sistemi Erişim API'sini kullanın; böylece şifresi çözülmüş baytlar RAM yerine doğrudan diske ulaşır.
Her Şeyi Dağıtma
Ön uç: Cloudflare Pages veya Vercel'e gönderin, her ikisinin ücretsiz katmanı bunu kaldırır. Arka uç: Caddy'nin arkasında (otomatik TLS 1.3) Node 22 çalıştıran tek bir aylık ~160 TL'lik DigitalOcean sunucusu. Depolama: Cloudflare R2 sıfır çıkış ücreti sunar; bu ölçekte dosya paylaşımı için belirleyici özelliktir. WeTransfer, Smash ve SwissTransfer AWS çıkış ücretlerinde servet harcar; R2 ekonomiyi tamamen değiştiriyor.
Caddy aracılığıyla sıkı başlıklar ayarlayın: Strict-Transport-Security, Content-Security-Policy: default-src 'self'; script-src 'self', X-Content-Type-Options: nosniff ve Referrer-Policy: no-referrer. Bunlar, URL parçasını yönlendirme veya enjekte edilmiş betikler aracılığıyla sızdırmak için yaygın vektörleri kapatır.
Uygulamayı Varsayılan Olarak KVKK Uyumlu Yapma
Sunucu yalnızca şifreli metni gördüğünden, KVKK'nın 3. maddesi kapsamında kişisel veri niteliği taşıyan neredeyse hiçbir şey yoktur. Yine de işlemci ilişkilerinizi (R2 ve DigitalOcean) belgeleyin, maksimum 30 günlük blob saklama süresi belirleyin ve paylaşım bağlantılarının anahtar içerdiğini ve yalnızca göndericinin güvendiği kanallar üzerinden iletilmesi gerektiğini açıkça bildirin. Kullanıcı kimliklerini kayıt altına almadan kötüye kullanımı caydırmak için IP başına saatte 50 yükleme sınırı ekleyin.
HexaTransfer, özünde bu mimari üzerine kuruludur — tarayıcıda Web Crypto, opak blob depolama, URL parçalarında anahtarlar, sunucularda sıfır düz metin. hexatransfer.com'da deneyin — ücretsiz, hesap gerekmez, maksimum 10 GB.
MVP Çalıştıktan Sonra Eklenecekler
Temel akış gönderildikten sonra en değerli eklemeler şunlardır: parça anahtarı üstüne şifre koruması (600.000 iterasyonla PBKDF2), geçici bir gelen kutusu aracılığıyla indirme başına e-posta bildirimleri ve içeriği açığa çıkarmadan şifreli metnin karmasının işaretlenmesini sağlayan suistimal bildirimi. Belirli bir nedeniniz olmadıkça hesap eklemeyin — bu uygulamanızı bir gecede gizlilik aracından veri yükümlülüğüne dönüştürür. Küçük gönderin, tutarlı kalın ve şifrelemenin ağır yükü taşımasına izin verin.
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