Erstellen Sie an Verschlüsselt Dateifreigabe App from Scratch
Step-by-step tutorial to build an encrypted Datei sharing application. Frontend encryption, secure backend, und deployment walkthrough.
Eine verschlüsselte Dateifreigabe-App in etwa 400 Codezeilen bauen und für unter 5 USD monatlich hosten — das ist möglich, wenn man die Kryptographie in den Browser legt, nicht auf den Server. Die DSGVO unterscheidet unter Artikel 4 zwischen personenbezogenen Daten und blossen Byteströmen: wer nur Ciphertext speichert, hat kaum personenbezogene Daten auf dem Server. Der minimale Stack: ein Vite-powered React-Frontend, das mit AES-256-GCM via der Web Crypto API verschlüsselt, ein Fastify-Backend, das jeden Upload als opaques Blob behandelt, S3-kompatibler Storage (Cloudflare R2 oder Backblaze B2) und eine kurze Share-URL, bei der der Entschlüsselungsschlüssel nach dem # lebt, sodass er nie den Server erreicht.
Architekturentscheidungen, die wirklich zählen
Die einzige wichtigste Entscheidung ist, wo der Verschlüsselungsschlüssel lebt. Wenn er je den Server berührt, hat man keine Ende-zu-Ende-Verschlüsselung, sondern serverseitige Verschlüsselung mit zusätzlichen Schritten. Das richtige Pattern: einen zufälligen 256-Bit-Schlüssel im Browser generieren, die Datei damit verschlüsseln, den Ciphertext hochladen und den Schlüssel in das URL-Fragment legen (https://yourapp.com/f/abc123#k=base64key). Browser senden Fragmente nie in HTTP-Anfragen, sodass der Schlüssel clientseitig bleibt.
Zweite Entscheidung: Chunked Uploads. Für Dateien über 100 MB braucht man fortsetzbare Multipart-Uploads, oder jedes WLAN-Aussetzer tötet den Transfer. S3s Multipart-API unterstützt 5-MB-Mindest-Chunks und bis zu 10.000 Parts, was eine 50-GB-Obergrenze ergibt. Von Anfang an dafür planen.
Das Projektskelett aufsetzen
Mit zwei Packages starten: ein Vite + React-Frontend und ein Fastify-Backend. Das Frontend übernimmt die gesamte Kryptographie, das Backend übernimmt Storage und Metadaten. TypeScript für Typsicherheit bei ArrayBuffer und CryptoKey verwenden.
pnpm create vite@latest frontend -- --template react-ts
pnpm create fastify backend
Diese Deps zum Backend hinzufügen: @fastify/multipart, @aws-sdk/client-s3, @aws-sdk/s3-request-presigner und better-sqlite3 für Share-Metadaten. Das SQLite-Schema klein halten: shares(id, object_key, size_bytes, expires_at, download_count, max_downloads). Keine Dateinamen, keine Nutzerdaten, keine IPs.
Die Frontend-Verschlüsselungs-Pipeline schreiben
Einen Schlüssel generieren, mit AES-256-GCM verschlüsseln und ein Ciphertext-Blob plus einen Base64-Schlüssel für das URL-Fragment produzieren:
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) };
}
Für Dateien über 50 MB durch eine Streaming-Version ersetzen, die 4-MB-Chunks verschlüsselt und sie an einen ReadableStream anhängt. Mobile-Safari-Heap chokes bei allem über ~400 MB in einem einzelnen ArrayBuffer.
Den Upload-Endpunkt gestalten
Das Backend sollte nichts Nützliches wissen. Einen POST mit dem Ciphertext akzeptieren, eine zufällige 16-Zeichen-URL-sichere ID generieren, sie in SQLite mit Ablauf speichern und den Body direkt zu S3 streamen:
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 };
});
Standard-Ablauf bei 7 Tagen, max 10 Downloads. Aggressive Defaults, weil die Alternative unbegrenztes Storage-Wachstum ist. Ein nächtlicher Cron löscht abgelaufene Blobs.
Share-Links mit Fragment-Schlüsseln generieren
Sobald der Upload abgeschlossen ist, die Share-URL clientseitig bauen:
const { id } = await uploadResponse.json();
const shareUrl = `${location.origin}/f/${id}#k=${keyBase64}`;
Dieses Fragment verlässt nie den Browser des Nutzers. Wenn ein Empfänger den Link anklickt, liest die React-App window.location.hash, parst den Schlüssel, holt den Ciphertext und entschlüsselt lokal. Der Server hat keinen Pfad zum Plaintext — außer durch das Ausliefern von bösartigem JavaScript, weshalb man eine strikte Content Security Policy einsetzen und Subresource-Hashes pinnen sollte.
Den Download-Flow implementieren
Auf der Download-Seite den Ciphertext als Stream holen und chunk-aligned entschlüsseln:
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]));
Für große Dateien StreamSaver.js oder die File System Access API nutzen, sodass die entschlüsselten Bytes direkt auf die Disk gehen statt in RAM.
Das Ganze deployen
Frontend: zu Cloudflare Pages oder Vercel pushen, beide kostenlosen Tiers bewältigen dies. Backend: ein einzelner 5-USD-DigitalOcean-Droplet, der Node 22 hinter Caddy (automatisches TLS 1.3) betreibt. Storage: Cloudflare R2 bietet null Egress-Kosten — das ist die Killer-Feature für Datei-Sharing im Scale. Strikte Header via Caddy setzen: Strict-Transport-Security, Content-Security-Policy: default-src 'self'; script-src 'self', X-Content-Type-Options: nosniff und Referrer-Policy: no-referrer.
Die App DSGVO-konform machen
Da der Server nur Ciphertext sieht, gibt es kaum personenbezogene Daten im Sinne von Art. 4 DSGVO. Dennoch Auftragsverarbeitungsbeziehungen dokumentieren (R2 und DigitalOcean), eine 30-Tage-Blob-Aufbewahrungsgrenze setzen und einen klaren Hinweis veröffentlichen, dass Share-Links Schlüssel enthalten und über vertrauenswürdige Kanäle übermittelt werden sollten. Rate-Limiting bei 50 Uploads pro IP pro Stunde, um Missbrauch zu erschweren, ohne Nutzeridentitäten zu loggen. Der BfDI hat wiederholt betont, dass Privacy-by-Design-Architekturen — also Systeme, die Daten gar nicht erst erheben — präventiv DSGVO-konform sind.
HexaTransfer basiert auf genau dieser Architektur — Web Crypto im Browser, opaker Blob-Storage, Schlüssel in URL-Fragmenten, kein Plaintext auf Servern.
Jetzt ausprobieren: https://hexatransfer.com — kostenlos, kein Account, bis zu 10 GB.
Große Dateien sicher mit Ende-zu-Ende-Verschlüsselung senden
Übertragen Sie Dateien bis zu 10 GB kostenlos mit Ende-zu-Ende-Verschlüsselung. Kein Konto erforderlich. Ihre Dateien werden in Ihrem Browser verschlüsselt, bevor sie hochgeladen werden — niemand sonst kann sie lesen.
Datei senden