Et engangslink, der slettes ved et almindeligt GET, dør i det
øjeblik, Slack, Teams eller en e-mailgateway henter det for at vise en
forhåndsvisning. Løsningen er kun at returnere metadata på GET og
først slette hemmeligheden ved en bevidst visning via POST, med en
adgangssætning sendt ad en anden kanal som ekstra sikring. Indlægget
gennemgår, hvilke systemer der henter links uden at spørge, og
hvordan du designer, så de ikke gør skade.
LinkPilots generator til hemmelige engangslinks er bygget på den måde: en hentning til forhåndsvisning får kun selve siden uden indhold. Hemmeligheden hentes, og visningen tælles, først når en browser kører siden.
Den typiske fejl
De fleste chat- og e-mailprogrammer forsøger at vise en forhåndsvisning, når de ser en URL. Forløbet ser sådan ud:
- En bruger indsætter det hemmelige link i Slack.
- Slacks forhåndsvisningsbot henter URL'en (sender et
GET; Slack beskriver adfærden under link unfurling). - Din kode til visning behandler forespørgslen som en visning fra et menneske, sletter hemmeligheden og returnerer indholdet.
- Slack modtager det slettede indhold (eller en generisk side) og viser det.
- Mennesket klikker på linket, ser ”allerede vist” og beder afsenderen om et nyt.
Botten havde ingen ond hensigt. Din kode blandede ”nogen hentede URL'en” sammen med ”modtageren læste hemmeligheden”. Det er to forskellige hændelser, og hele designopgaven går ud på at holde dem adskilt.
Der gemmer sig en værre variant i trin 3: hvis bottens GET fik det
egentlige indhold, ligger hemmeligheden nu i en tredjeparts
infrastruktur til forhåndsvisninger. I bedste fald blev den kasseret,
efter at forhåndsvisningen var lavet, men det kan du ikke bekræfte, og
der er ingen hændelse i revisionsloggen, der fortæller dig, at det
skete.
Hvem henter et link, før modtageren åbner det?
Forhåndsvisningsbots i chatprogrammer, sikkerhedsgateways til e-mail, endpointbeskyttelse, proxyer i virksomheder og browserudvidelser med forhåndsvisning, og som regel mere end én af dem. ”Slack viser forhåndsvisninger” undervurderer problemet. En URL, der indsættes på en moderne arbejdsplads, bliver typisk hentet af flere systemer, før et menneske klikker på den:
| Hvem henter | Hvornår det sker | Kan den genkendes? |
|---|---|---|
| Forhåndsvisningsbots i chat (Slack, Teams, iMessage, WhatsApp, LinkedIn) | I det øjeblik beskeden sendes | Som regel: tydelige user agents som Slackbot-LinkExpanding |
| Sikkerhedsgateways til e-mail (Mimecast, Proofpoint, Microsoft Defender) | Ved levering og ofte igen, når der klikkes | Ofte ikke: mange bruger user agents fra rigtige browsere |
| Endpointbeskyttelse og antivirus | Når URL'en når modtagerens computer | Sjældent |
| Webproxyer i virksomheder | Når der klikkes, før brugerens forespørgsel sendes videre | Sjældent |
| Browserudvidelser med forhåndsvisning af links | Når musen holdes over linket, eller siden indlæses | Nej: de bruger brugerens egen browsersession |
Leverandørernes adfærd i tabellen ændrer sig hele tiden. Læs konkrete
påstande om gateways som ”som offentliggjort i juli 2026, tjek mod den
aktuelle dokumentation”. Fællesnævneren ændrer sig dog ikke: alle
systemerne sender et almindeligt GET, fordi det er den eneste
sikre og universelle måde at se på en URL, man ikke selv styrer.
Hvordan forhindrer du, at en forhåndsvisning sletter et engangslink?
Send metadata på GET, og slet kun ved et bevidst POST.
HTTP-semantikken findes allerede:
RFC 9110, afsnit 9.2.1
definerer GET som sikker og idempotent, dvs. en forespørgsel, som
alle frit må sende, fordi den ikke skal ændre noget. POST er
handlingsverbet. Gør derfor visningen til en POST-handling bag en
synlig knap:
GET /s/abc123 → HTML page: "Click to reveal this secret"
POST /s/abc123 → burns the secret, returns the payload
Nu returnerer Slacks GET en neutral side med metadata.
Hemmeligheden slettes først, når mennesket klikker på knappen. En
scanner, der respekterer HTTP-semantikken, rører aldrig indholdet.
Det gælder næsten dem alle, for sendte de POST-forespørgsler med
sideeffekter mod vilkårlige URL'er, ville halvdelen af nettet holde op
med at virke.
Et gennemgået eksempel
Følg ét link hele vejen. Du opretter en hemmelighed med Slet efter læsning og en adgangssætning og indsætter URL'en i en direkte besked i Slack og i en e-mail.
- Slacks forhåndsvisningsbot sender
GET /s/abc123. Svar: en lille side med metadata, status aktiv, adgangssætning påkrævet. Ingen visning registreret. Hemmeligheden lever. - Modtagerens e-mailgateway omskriver URL'en i e-mailen og henter
den ved levering for at tjekke dens omdømme. Samme
GET, samme metadata. Hemmeligheden lever stadig. - Modtageren klikker på linket i e-mailen. Gatewayens scanner
henter det én gang til (
GET) og sender derefter browseren videre. - Browseren indlæser siden til visning, endnu et
GET. Siden viser en knap til visning og et felt til adgangssætningen. Stadig ingen visning registreret. - Modtageren indtaster adgangssætningen og klikker på knappen.
Browseren sender
POST /s/abc123. Visningen registreres, indholdet returneres, og hemmeligheden slettes. - Alle, der henter URL'en bagefter, får et klart svar om, at indholdet ”allerede er vist og destrueret”, i stedet for indholdet.
Fem hentninger, én visning. Det forhold er normalt i en virksomhed. Et design, der ikke kan tåle det, fejler første dag, og så indsætter afsenderen bare adgangskoden direkte i chatten.
Forsvar i flere lag
Opdelingen mellem GET og POST
Klarer alle forhåndsvisningsbots og scannere, der opfører sig ordentligt, og det er langt størstedelen af den automatiske trafik. Det er fundamentet. Alt nedenfor er ekstra lag.
Adgangssætning som spærring
Dækker det, opdelingen ikke kan: sandboxe, der kører JavaScript og interagerer med siden, samt klik ved et uheld og videresendte e-mails. En sandbox til detonation kan klikke på en knap, men den kan ikke levere en adgangssætning, der er sendt ad en anden kanal. Send linket via e-mail og adgangssætningen i en direkte besked i Slack eller via sms.
Filtrering af bots efter user agent
Afvis kendte forhåndsvisningsbots (Slackbot, LinkedInBot,
Twitterbot), før de når koden til visning. Det er værd at gøre som
livrem og seler, men det er aldrig nok alene: sikkerhedsscannere
bruger rutinemæssigt user agents fra rigtige browsere, netop for at
ondsindede sider ikke kan skjule sig for analysen.
Kort udløb
Begræns det tidsrum, hvor der kan ske skade. Et link, der levede i femten minutter, efterlader scannere, logfiler og chathistorik med en URL, der ikke længere fører til noget.
Cache-Control: no-store
Sæt headeren på hvert svar fra visningen, så ingen mellemled (virksomhedens proxy, CDN eller browserens cache) gemmer en kopi af indholdet efter den ene legitime læsning.
Sikkerhedsgateways til e-mail
Gateways i virksomheder fortjener deres eget afsnit, fordi de henter to gange. Produkter i den kategori (Microsoft Defender Safe Links er det dokumenterede eksempel) omskriver hver URL i indgående e-mails, så den går via deres eget scanningsdomæne. URL'en hentes typisk én gang ved levering for at tjekke omdømmet og igen, når der klikkes, før mennesket sendes videre til den rigtige destination.
Hvis en af hentningerne slettede hemmeligheden, ville modtageren
altid se et dødt link. For brugerne ser fejlen tilfældig ud, men den
er helt forudsigelig. Opdelingen mellem GET og POST klarer begge
hentninger uden ekstra arbejde, fordi begge er almindelige GET.
Omdirigeringen ved klikket fører derefter mennesket til siden til
visning, hvor POST sker.
Særtilfælde, der stadig giver problemer
- Sandboxe, der kører JavaScript. Nogle miljøer til detonation
gengiver siden og interagerer med den. Et
POSTbag en knap uden adgangssætning kan i princippet blive klikket af en aggressiv sandbox. Adgangssætningen er den ekstra sikring. - Link og adgangssætning i samme kanal. Sendes begge i én e-mail, falder alle forsvarene ovenfor sammen til ”håb på, at ingen læser den e-mail”. Brug altid to kanaler.
- Videresendelse. Hver gang linket sendes videre til et nyt chat- eller e-mailsystem, udløses en ny runde forhåndsvisninger. Med opdelingen er det ufarligt, men hvert led er endnu et sæt logfiler, der rummer URL'en, og det taler for kort udløb.
- Samtidige visninger. Klikker to personer på knappen samtidig, skal læsning og sletning ske i ét trin, der ikke kan deles op: præcis én forespørgsel vinder, og den anden får ”allerede vist”. En implementering, hvor de to ting sker hver for sig, kan levere indholdet to gange.
Test dit eget værktøj
Før du betror rigtige loginoplysninger til en tjeneste til deling af hemmeligheder, så lav dette tjek, som tager to minutter:
- Opret en hemmelighed, du kan smide væk, med Slet efter læsning slået til.
- Hent den fra en terminal. Det er præcis, hvad en forhåndsvisningsbot gør:
curl -s -o /dev/null -w "%{http_code}" "<url>" - Åbn linket i en browser. Ser du ”allerede vist”, sletter værktøjet
ved
GET, og det er ikke sikkert at indsætte linket i en chat eller en e-mail. - Overlevede hemmeligheden, så vis den på normal vis i browseren og
kør
curligen. Nu bør du få et klart svar om, at den er væk eller slettet, ikke indholdet.
Sådan gør LinkPilot
LinkPilots hemmelige links bruger netop dette design: et GET mod
endpointet til visning returnerer kun metadata (status, og om der
kræves en adgangssætning). En visning registreres kun ved et bevidst
POST. Adgangssætninger hashes med SHA-256 i browseren og begrænses
til fem forsøg pr. IP-adresse pr. minut pr. hemmelighed. Hvert svar
fra visningen har Cache-Control: no-store, slettede eller udløbne
hemmeligheder returnerer HTTP 410, og det gemte indhold overskrives.
Revisionsloggen registrerer hver hændelse med en hashet IP-adresse
under et salt, der skiftes dagligt, og den rå IP-adresse gemmes
aldrig. Alle detaljer står på siden om
sikkerhedsarkitekturen.
Prøv det gratis, uden tilmelding
Selvdestruerende besked
Send en note, der forsvinder efter én læsning.
Designets begrænsninger
De ærlige grænser: intet af ovenstående beskytter en hemmelighed efter en legitim visning. Modtageren kan kopiere indholdet, tage et skærmbillede af det eller sende det videre. Det hjælper heller ikke, hvis adgangssætningen sendes sammen med linket. Og det kan ikke forhindre en person, der ved en fejl har fået linket, i at åbne det, før den rigtige modtager gør. Det er derfor, der er en revisionslog: du ser den uventede visning og skifter loginoplysningerne.
Relateret læsning
- Sådan virker hemmelige engangslinks
- Derfor lækker URL'er følsomme oplysninger
- LinkPilots sikkerhedsarkitektur
Kilder
- IETF, RFC 9110: HTTP Semantics, section 9.2.1 Safe Methods.
- Slack API, Unfurling links in messages.
- Microsoft Learn, Safe Links in Microsoft Defender for Office 365.
