Byg sikker hemmelighedsdeling med ren browser-teknologi

Jul 18, 2026 web-crypto end-to-end-encryption javascript security cryptography secret-sharing browser-api

Hemmeligheder der forsvinder: Browser-baseret kryptering uden afhængigheder

Lad os være ærlige: at dele følsomme oplysninger online er en frustrerende oplevelse. Du sender et password via email, hvorefter du panisk sletter det. Du bruger en tredjepartstjeneste og håber, de ikke læser dine data. Du sender det via Slack, vel vidende at din virksomhed har den historik for evigt. Der må findes en bedre løsning.

Det gør der – og du kan bygge den direkte i browseren.

Problemet med tredjepartstjenester til hemmeligheder

Tjenester som OneTimeSecret introducerede konceptet med selvdestruerende links. Du klistrer din hemmelighed ind, får et engangslink, deler det, og vupti – væk efter første visning. Men der er en hage, de færreste tænker over: hvad sker der egentlig med dine data?

Selv med "midlertidige" tjenester rører din hemmelighed i plaintext ofte deres servere. De lover, de ikke læser den. De lover, de sletter den. Men hvorfor stole på løfter, når du helt kan fjerne muligheden?

Her kommer end-to-end encryption (E2EE) ind i billedet. Med ægte E2EE kan serveren ikke læse din hemmelighed. Den opbevarer udelukkende ciphertext – meningsløse tilfældige bytes uden nøglen. Serveren bliver en dum opbevaringsboks, ikke en vogter af dine hemmeligheder.

Sådan fungerer E2EE hemmelighedsdeling i praksis

Forestil dig, at Bob vil dele et databasepassword med Alice. Det smukke er: krypteringen sker helt i Bobs browser, før noget som helst rører serveren.

Flowet:

  1. Bob skriver sin hemmelighed og vælger en adgangssætning
  2. Hans browser udleder en kryptografisk nøgle fra den pågældende adgangssætning
  3. Hemmeligheden krypteres lokalt med den nøgle
  4. Bob sender Alice et link (indeholdende ciphertext og salt) plus adgangssætningen (via en separat kanal)

Hvorfor separate kanaler? Hvis både linket og adgangssætningen rejser sammen, og en angriber opsnapper linket, får de alt. Send linket via Slack; adgangssætningen via Signal. Eller SMS. Eller brevduer. Pointen er: to forskellige angrebsoverflader.

Alice modtager linket, indtaster adgangssætningen, hendes browser udleder nøglen lokalt igen, og hemmeligheden dekrypteres – alt sammen uden at serveren nogensinde ser læsbare data.

Kryptografien bag det hele

Her bliver det teknisk, men hæng på – det er elegant.

Nøgleudledning: PBKDF2

Mennesker er elendige til at generere tilfældige, høj-entropi nøgler. Vi skriver "adgangskode123" og føler os kreative. Så vi har brug for en funktion, der transformerer svage adgangssætninger til stærke kryptografiske nøgler – langsomt, med vilje.

PBKDF2 (Password-Based Key Derivation Function 2) gør præcis dette. Den tager din adgangssætning, tilføjer et tilfældigt salt (opbevaret offentligt), og kører det igennem 600.000 iterationer af SHA-256 hashing. Hvert gæt i et brute-force angreb koster CPU-tid. Ved 600k iterationer bliver det beregningsmæssigt uoverkommeligt at knække en middelmådig adgangssætning.

async function deriveKey(passphrase, salt) {
  const keyMaterial = await crypto.subtle.importKey(
    "raw",
    new TextEncoder().encode(passphrase),
    "PBKDF2",
    false,
    ["deriveKey"]
  );
  
  return crypto.subtle.deriveKey(
    {
      name: "PBKDF2",
      salt: salt,
      iterations: 600_000,
      hash: "SHA-256"
    },
    keyMaterial,
    { name: "AES-GCM", length: 256 },
    false,
    ["encrypt", "decrypt"]
  );
}

Symmetrisk kryptering: AES-GCM

Til den egentlige kryptering bruger vi AES-256-GCM. Dette er ikke den AES, du måske har hørt om i teoretiske sammenhænge – det er den autentificerede version. GCM-tilstand krypterer ikke kun dine data, men genererer også en autentifikationstag. Hvis nogen manipulere ciphertext undervejs, fejler dekrypteringen med en fejl i stedet for silent at producere vrøvl.

Den kræver også en unik initialiseringsvektor (IV) for hver kryptering. Tænk på det som saltet: offentligt, tilfældigt og afgørende for sikkerheden. AES-GCM er solidt – det er, hvad NSA anbefaler til klassificerede oplysninger.

async function encrypt(plaintext, key) {
  const iv = crypto.getRandomValues(new Uint8Array(12));
  const encoded = new TextEncoder().encode(plaintext);
  
  const ciphertext = await crypto.subtle.encrypt(
    { name: "AES-GCM", iv: iv },
    key,
    encoded
  );
  
  return { iv, ciphertext };
}

Hvorfor nul afhængigheder betyder noget

Denne tilgang er radikal: ingen npm-pakker. Ingen kryptobiblioteker. Ingen tillid til tredjepartskode.

Du bruger det, der allerede er i din browser. Web Crypto API har været standardiseret siden 2015 og leveres i alle moderne browsere. Det er bakket op af platformleverandørerne – Apple, Google, Microsoft, Mozilla – som har investeret massivt i korrekte, constant-time implementeringer.

Overvej angrebsoverfladen i typiske applikationer med mange afhængigheder. Log4Shell skete på grund af en afhængighed. left-pad-hændelsen brød internettet på grund af en afhængighed. Hver npm install er en tillidsbeslutning.

Med Web Crypto API stoler du på browserens native implementering. Det er en langt mindre angrebsoverflade end at stole på en tilfældig npm-pakke med 2 millioner ugentlige downloads.

Server-side: Dum opbevaring er god opbevaring

På bagsiden opbevarer du:

  • Ciphertexten (værdiløs uden nøglen)
  • Saltet (ikke hemmeligt, nødvendigt for nøgleudledning)
  • IV'en (ikke hemmeligt, nødvendigt for dekryptering)
  • Metadata (creationstidspunkt, udløb, visningsantal)

Konfigurer din Redis (eller Valkey) med save "" og appendonly no – altså ingen persistens overhovedet. Når processen dør, fordamper alt. Sæt korrekt swap-konfiguration op for at forhindre data i at ramme disk.

Serveren bliver en midlertidig krypteret blob-opbevaring. Den håndhæver adgangsregler (én visning, udløb) men kan ikke læse indholdet, selv hvis den ville.

Hvad dette betyder for din stack

Du kan integrere dette direkte i enhver webapplikation. Et formularfelt her, et par JavaScript-funktioner der, og pludselig har din app sikker,ephemeral hemmelighedsdeling indbygget. Ingen backend-ændringer nødvendige – din server opbevarer og leverer blot krypterede blobs.

Dette er særligt kraftfuldt til:

  • Interne værktøjer, der har brug for midlertidigt at dele credentials
  • Kundeservicesystemer, der overfører følsomme data
  • Developer workflows, der deler API-nøgler eller databasepasswords

Hemmelighederne er kryptografisk isolerede fra din infrastruktur. Selv hvis nogen kompromitterer din database, får de ciphertext, de ikke kan knække uden adgangssætningen.

Afvejningerne er det værd

Er PBKDF2 med 600k iterationer langsommere end Argon2 ville være? Ja. Argon2, den moderne gold standard for password hashing, er endnu ikke tilgængelig i Web Crypto API. Men overvej konteksten: dette er engangs-hemmeligheder, typisk set inden for minutter. Den beregningsmæssige omkostning er acceptabel.

Afvejningen – lidt svagere KDF til fordel for nul afhængigheder – er det værd i de fleste use cases. Du beskytter ikke atomарbejdernes koder. Du deler et databasepassword, der alligevel vil blive ændret i morgen.

Byg det, stol ikke på det

Skønheden ved E2EE er, at du ikke behøver at stole på tjenesteoperatøren. Du kan auditere koden. Du kan self-host den. Du kan verificere, at serveren virkelig aldrig ser plaintext.

I en verden hvor databrud er daglig nyhed, er det at bygge systemer, hvor serveren er kryptografisk blind, ikke bare smart – det er ansvarligt.

Så næste gang du skal dele en hemmelighed online, husk: den bedste måde at beskytte data er at lade dem aldrig forlade brugerens hænder ukrypteret. Og med Web Crypto API har du værktøjerne til at gøre det muligt, direkte i browseren.


Klar til at implementere? Web Crypto API er tilgængelig i alle moderne browsere. Ingen installation, ingen build-step, ingen afhængigheder – bare ren browser-native kryptografi, der venter på at blive brugt.

Read in other languages:

FR ES DE ZH-HANS EN