Sikkerhed

    Hvorfor URL'er lækker følsomme oplysninger, og hvad du gør

    Browserhistorik, serverlogs, CDN'er og Referer-headere gemmer hele URL'er, også over HTTPS. Se, hvor links lækker, og hvordan URL'er kan tåle at lække.

    W. Miller · Opdateret · Om LinkPilot

    En URL føles privat, fordi kun de personer, du sender den til, burde have den. I praksis er en URL en af de mest loggede oplysninger på nettet: den bliver skrevet ned, kopieret og videresendt af systemer, der aldrig har bedt om din tilladelse, og som du ikke har indsigt i. Her kan du se præcis, hvor den lækker, og hvordan du designer links, der tåler det. Det er også grunden til, at en generator til engangslinks gemmer dekrypteringsnøglen efter # i linket: den del når aldrig frem til en serverlog.

    Hvor lækagerne sker

    • Browserhistorik. Hver URL, brugeren besøger, gemmes lokalt og kan synkroniseres til andre enheder og til browserleverandørens synkroniseringstjeneste.
    • Adgangslogs på HTTP-servere. De fleste servere logger som standard hele stien og query-strengen. Alle med adgang til loggen har URL'en.
    • Reverse proxyer og CDN'er. Cloudflare, Fastly og din load balancer logger alle URL'en, hver med sin egen opbevaringspolitik.
    • Pipelines til samling af logs. Adgangslogs bliver sjældent på én maskine. De sendes videre til centrale tjenester til logning og overvågning, så antallet af systemer, der har URL'en, ganges op.
    • Referer-headere. Når siden linker til en ressource hos en tredjepart, kan browseren sende kildesidens URL i headeren Referer. Statistikscripts, indlejrede videoer og annoncepixels modtager den alle.
    • Browserudvidelser. Udvidelser med tilladelsen ”læse browserhistorik” ser hver URL, inklusive den del, der står efter #.
    • Synkronisering af bogmærker. URL'er, der er gemt som bogmærker, synkroniseres mellem brugerens enheder og til browserleverandørens servere.
    • Forhåndsvisningsbots. Slack, Teams, iMessage, LinkedIn og e-mailprogrammer henter URL'er for at vise en linkforhåndsvisning. Det sker i det øjeblik, beskeden sendes, uden at nogen ser det.
    • Virksomheders proxyer og e-mailgateways. Mange organisationer inspicerer, omskriver og logger hver URL, der passerer deres grænse.

    Holder HTTPS URL'en privat?

    Nej. HTTPS krypterer URL'en under overførslen og intet andet, og begge ender gemmer den stadig. Det er værd at være præcis her, fordi ”forbindelsen er krypteret” ofte bliver misforstået som ”URL'en er privat”.

    TLS krypterer stien og query-strengen under overførslen: en, der lytter på netværket mellem browseren og serveren, kan ikke læse /reset?token=.... Det, TLS ikke skjuler, er værtsnavnet på destinationen (synligt via DNS-opslaget og feltet SNI i TLS på de fleste forbindelser i dag) og alt i de to ender. Browseren gemmer stadig hele URL'en i historikken, og serveren skriver den stadig i sin adgangslog. Kryptering under overførslen beskytter ledningen, ikke de to ender, og det er i enderne, URL'er lækker.

    Et eksempel trin for trin: en URL's liv

    Følg en enkelt følsom URL, fx et link til nulstilling, https://example.com/reset?token=8f3a91..., fra afsendelse til klik:

    1. E-mailudbyderen gemmer beskeden (med URL'en) på ubestemt tid, og dens sikkerhedsscanner kan hente URL'en ved levering.
    2. Modtagerens e-mailgateway omskriver og logger URL'en og henter den igen, når der bliver klikket.
    3. DNS slår example.com op, og værtsnavnet (ikke stien) ligger nu i resolverens logs.
    4. Webserveren skriver hele anmodningslinjen i sin adgangslog. En linje i standardformatet ”combined” fra nginx eller Apache ser sådan ud:
    203.0.113.7 - - [14/Jul/2026:09:12:45 +0000]
      "GET /reset?token=8f3a91... HTTP/1.1" 200 5123 "-" "Mozilla/5.0 ..."
    
    1. CDN'et foran serveren logger den samme URL med sin egen opbevaringstid.
    2. Sidens statistikscript registrerer sidens URL, med hele query-strengen, i et system hos en tredjepart, medmindre det udtrykkeligt er sat op til at fjerne den.
    3. Browseren gemmer URL'en i historikken og synkroniserer den.

    Én afsendelse, syv kopier hos mindst fem organisationer. Intet af det krævede en angriber. Det er bare nettet, der virker, som det er designet.

    Referer-headeren i praksis

    Hvis din side til visning af hemmeligheder linker til en ekstern ressource (en skrifttype fra et CDN, et statistikscript, et indlejret billede), kan browseren sende sidens URL til det domæne i headeren Referer.

    Moderne browsere bruger som standard strict-origin-when-cross-origin (MDN: Referrer-Policy), der skærer referreren ned til kun domænet ved anmodninger på tværs af domæner (https://example.com/ i stedet for hele stien). Det er et reelt fremskridt, men ikke noget, du kan regne med: anmodninger inden for samme domæne har stadig hele URL'en med, en politik på sideniveau kan løsne standarden, og ældre klienter og indlejrede webviews opfører sig forskelligt.

    To praktiske modforanstaltninger:

    <!-- Strip the referer for outbound requests on the page -->
    <meta name="referrer" content="no-referrer" />
    
    Referrer-Policy: no-referrer
    

    Headeren gælder for hele sitet, og meta-tagget gælder for den enkelte side. Brug begge som flere lag af forsvar. Endnu bedre er det at levere følsomme sider helt uden ressourcer fra tredjeparter, så der ikke er noget at sende en referrer til.

    Er et token sikrere i stien, i query-strengen eller efter #?

    Kun den del, der står efter #, holdes uden for anmodningen, og derfor holdes kun den uden for serverlogs. Stien og query-strengen er ligeværdige. Hvor du placerer et token i URL'en, afgør, hvem der ser det:

    PlaceringSendes til serveren?I serverlogs?I Referer?I browserhistorikken?
    Sti (/s/abc123)JaJaAfhænger af politikkenJa
    Query (?token=abc123)JaJaAfhænger af politikkenJa
    Fragment (#abc123)NejNejNejJa

    Den del, der står efter #, er reelt anderledes: ifølge RFC 3986, afsnit 3.5 behandles den i klienten og kommer aldrig med i HTTP-anmodningen. Det er derfor, værktøjer til end-to-end-krypterede tekstnoter lægger dekrypteringsnøglen der: serveren modtager den bogstavelig talt aldrig. Den er dog ikke usynlig. Browserhistorikken, udvidelser og alt JavaScript, der kører på siden, kan læse den. Forskellen mellem sti og query er derimod uden betydning for privatlivet: begge ender i de samme logs.

    Problemet med tokens til nulstilling af adgangskoder

    Følsomme tokens i URL'er er en anerkendt klasse af sårbarheder. MITREs CWE-598 (”Use of GET Request Method With Sensitive Query Strings”) dækker præcis det: følsomme oplysninger i query-strenge ender i logs, historik og referrere, uanset om transporten er krypteret. Derfor stoler velbyggede forløb til nulstilling af adgangskoder aldrig kun på, at URL'en er hemmelig. De gør tokenet til engangsbrug, giver det kort levetid og binder det til en efterfølgende handling (at vælge en ny adgangskode), så et token, der bliver fundet i en log tre uger senere, er værdiløst.

    Det er den generelle lære: du kan som regel ikke holde en URL ude af logs, men du kan gøre den loggede URL værdiløs, inden nogen læser den.

    Sådan designer du URL'er, der tåler at lække

    Gå ud fra, at hver URL, du opretter, før eller siden dukker op et sted, den ikke skulle, og design, så det ikke betyder noget:

    • Engangsbrug. Slet hemmeligheden efter første vellykkede visning, så en lækket URL er død, når den dukker op i nogens historik.
    • Kort udløb. Begræns det tidsrum, hvor en lækage kan skade. En URL, der virkede i fem minutter, er langt mindre værd end en, der virkede i en uge.
    • Adgangssætning via en anden kanal. Kræv en hemmelighed, der aldrig har været i URL'en. Så er URL'en alene, som er det eneste, logs har, ikke nok.
    • Adskil hentning fra visning. Lever metadata ved GET, og udlever først indholdet ved en udtrykkelig POST, så forhåndsvisningsbots og scannere ikke kan opbruge hemmeligheden.
    • Ingen ressourcer fra tredjeparter på følsomme sider, og desuden Referrer-Policy: no-referrer og <meta name="robots" content="noindex">.
    • Skjul hemmelige ruter i dine egne logs. I nginx mapper du anmodningens URI, før den logges (se referencen til ngx_http_log_module for log_format):
    map $request_uri $loggable_uri {
        ~^/s/   "/s/[redacted]";
        default $request_uri;
    }
    log_format redacted '$remote_addr - $remote_user [$time_local] '
                        '"$request_method $loggable_uri" $status';
    access_log /var/log/nginx/access.log redacted;
    

    Du styrer kun dine egne logs. Kopierne i CDN'et, proxyen og browseren er der stadig, og netop derfor bærer de tre første punkter på listen det meste af vægten.

    Den trusselsmodel er grunden til, at LinkPilots hemmelige links virker, som de gør: URL'en behandles, som om den uundgåeligt lækker, så URL'en alene er aldrig nok. En GET returnerer kun metadata, og indholdet kræver en udtrykkelig visning via POST, eventuelt beskyttet af en adgangssætning, der hashes med SHA-256 i klienten. Hemmeligheder, der er slettet, udløbet eller tilbagekaldt, returnerer HTTP 410, og indholdet er overskrevet, så det ikke kan gendannes. Svar ved visning har Cache-Control: no-store, og visninger logger en hashet IP-adresse med et salt, der skiftes dagligt, i stedet for den rå adresse. Og én ærlig begrænsning, som står på siden om sikkerhedsarkitekturen: dekrypteringsnøglen ligger i den del af linket, der står efter #, så hele linket skal behandles som hemmeligheden. Det er præcis den fare, denne artikel handler om. Kort udløb, sletning efter læsning og en adgangssætning via en anden kanal er det, der begrænser skaden, når et link lækker.

    Opdatering den 29. september 2026: dette afsnit sagde oprindeligt, at LinkPilot ikke tilbød end-to-end-kryptering. Nu krypteres tekst i browseren, vedhæftede filer inklusive.

    Prøv det gratis, uden tilmelding

    Selvdestruerende besked

    Send en note, der forsvinder efter én læsning.

    Åbn værktøjet

    Begrænsninger

    Design af URL'er kan ikke løse alt. Det styrer ikke, hvad modtageren gør efter en legitim visning, det kan ikke fjerne kopier, som tredjeparter allerede har, og det redder ikke en URL, der viser personoplysninger helt åbent. Står en brugers e-mailadresse i query-strengen, kan intet udløb forhindre, at den bliver logget. Den holdbare regel: læg aldrig oplysninger i en URL, som du senere får brug for at slette, for det er i praksis umuligt at slette en URL alle de steder, den er blevet kopieret til. Design i stedet URL'er, der er værdiløse, når de lækker.

    Kilder

    Værktøjer til denne artikel

    Ofte stillede spørgsmål

    LinkPilot sender et hemmeligt link, der er væk, når det er åbnet.

    Krypteres i din browser, vises én gang og destrueres derefter. Kræver ingen konto.

    Opret et hemmeligt link

    Læs videre