Tietoturva

    Näin kertakäyttöiset salaiset linkit toimivat

    Kertakäyttölinkki näyttää sisältönsä kerran. Selain salaa sen, palvelin tallentaa vain salatekstin ja ensimmäinen avaus tuhoaa tallennetun kopion.

    W. Miller · Päivitetty · Tietoa LinkPilotista

    Kertakäyttöinen salainen linkki on URL-osoite, joka näyttää sisältönsä täsmälleen kerran ja lakkaa sen jälkeen pysyvästi toimimasta. Lähettäjän selain salaa salaisuuden AES-GCM-256-salauksella, palvelin tallentaa vain salatekstin ja avain kulkee linkin #-merkin jälkeisessä osassa (#k=), jota selaimet eivät koskaan lähetä. Kun vastaanottaja avaa salaisuuden ensimmäisen kerran, sama toiminto purkaa salauksen ja tuhoaa tallennetun kopion.

    Sellaisen voi tehdä ilman tiliä ilmaisella salaisten linkkien luontityökalulla.

    Mekanismi on yksinkertainen, mutta kiinnostavaksi sen tekevät erikoistapaukset. Juuri niissä huolimattomat toteutukset vuotavat huomaamatta.

    Perusvaiheet

    1. Lähettäjä liittää salaisuuden. Selain luo satunnaisen avaimen, salaa sisällön AES-GCM-256-salauksella Web Crypto API:n avulla ja lähettää vain salatekstin. Palvelin tallentaa sen satunnaisen, vaikeasti arvattavan polkutunnuksen alle ja palauttaa URL-osoitteen. Selain lisää avaimen osoitteen loppuun #-merkin jälkeiseen osaan muodossa #k=. Tämä osa ei koskaan poistu lähettäjän laitteelta.
    2. Lähettäjä jakaa URL-osoitteen millä tahansa kanavalla: sähköpostilla, pikaviestimellä tai tekstiviestillä.
    3. Vastaanottaja avaa URL-osoitteen. Pelkkä GET-pyyntö palauttaa vain tilan. Kun vastaanottaja napsauttaa näyttämispainiketta, palvelin merkitsee salaisuuden käytetyksi ja palauttaa salatekstin samassa toiminnossa, jota ei voi jakaa osiin. Vastaanottajan selain purkaa salauksen #-merkin jälkeisessä osassa olevalla avaimella.
    4. Jokainen myöhempi käynti saa sisällön sijaan tilasivun, jonka mukaan salaisuus on tuhoutunut.

    Ratkaiseva on vaihe 3. Jos lukeminen ja tilan päivitys tehdään kahtena erillisenä kyselynä (ensin SELECT tarkistaa, sitten UPDATE merkitsee), kaksi samanaikaista katsojaa voi kumpikin läpäistä tarkistuksen, ennen kuin kumpikaan kirjoittaa. Molemmat saavat sisällön. Tämä on klassinen TOCTOU-virhe (time-of-check to time-of-use), ja se muuttaa lupauksen ”täsmälleen kerran” muotoon ”yleensä kerran”.

    Miksi lukeminen ja tuhoaminen on tehtävä yhtenä vaiheena?

    Muuten kaksi samanaikaista katsojaa voi kumpikin läpäistä tarkistuksen, ennen kuin kumpikaan merkitsee salaisuuden käytetyksi. Korjaus on yhdistää tarkistus, merkintä ja lukeminen yhdeksi tietokantatoiminnoksi. Postgresissa se näyttää tältä, kun käytetään lausetta UPDATE ... RETURNING:

    UPDATE secrets
    SET burned_at = now()
    WHERE slug = $1
      AND burned_at IS NULL
      AND expires_at > now()
    RETURNING payload;
    

    UPDATE-lauseen ottama rivitason lukitus pakottaa samanaikaiset kutsujat jonoon: ensimmäinen täyttää WHERE-ehdon, asettaa sarakkeen burned_at ja saa sisällön takaisin RETURNING-osan kautta. Jokainen myöhempi kutsuja huomaa, että burned_at on jo asetettu, ei osu yhteenkään riviin ja saa tuhoutuneen tilan. Tarkistuksen ja käyttämisen välissä ei ole aukkoa, koska ne ovat sama lause.

    LinkPilot kirjaa avaukset juuri tästä syystä tietokantafunktiolla, joka lukee ja merkitsee samalla hetkellä: samanaikaiset näyttämisyritykset eivät voi vuotaa salaisuutta kahdesti. Jos arvioit työkalua, tätä on aivan aiheellista kysyä suoraan toimittajalta: tapahtuvatko lukeminen ja tuhoaminen yhtenä vaiheena, jota ei voi jakaa osiin?

    410 Gone kertoo, että resurssi on ollut olemassa ja on pysyvästi poissa, ja juuri sitä tuhoutunut salaisuus on. Käytetyn linkin pitää epäonnistua selvästi ja pysyvästi. LinkPilot tekee tuhoutumisen yhteydessä kaksi asiaa:

    • Tallennettu sisältö korvataan merkkijonolla [REDACTED] samassa kirjoituksessa, joka vaihtaa tilan. Siksi edes myöhempi tietokantamurto ei palauta käytettyä salaisuutta.
    • Myöhemmät näyttämisyritykset palauttavat vastauksen HTTP 410 Gone ja selkeän sivun, jonka mukaan sisältö on jo avattu ja tuhottu.

    410 on oikea tilakoodi: se tarkoittaa, että resurssi on ollut olemassa ja on tarkoituksella ja pysyvästi poissa. 404 taas sanoo, ettei resurssista ole koskaan kuultukaan. Ero on tärkeä myös ihmisille. Vastaanottaja, joka näkee ilmoituksen ”tämä salaisuus on jo avattu”, tietää kertoa asiasta lähettäjälle. Lähettäjä voi tarkistaa tarkastuslokin ja vaihtaa tunnukset, jos avaaja ei ollut vastaanottaja.

    Vaikeasti arvattavat polkutunnukset ja miksi ne eivät riitä

    Polkutunnus on ainoa asia julkisen internetin ja vielä avaamattoman salatekstin välissä (avain on #-merkin jälkeisessä osassa, ei palvelimella), joten siinä on oltava todellista entropiaa. Esimerkiksi 22 merkin base62-polkutunnus, joka on poimittu kryptografisesti turvallisesta satunnaislähteestä, sisältää noin 128 bittiä. Läpikäynti ei ole realistinen hyökkäys millään pyyntötahdilla, jonka palvelin kestäisi.

    Polkutunnuksen entropia suojaa kuitenkin vain arvaamiselta. Se ei auta mitään, jos URL-osoite nähdään: selainhistoria, välityspalvelinten lokit, edelleenlähetetyt sähköpostit, näytönjaot ja leikepöydän hallintaohjelmat. Siksi vakavasti otettavat toteutukset lisäävät kerroksia:

    • Voimassaoloaika, jotta nähty URL-osoite lakkaa toimimasta aikataulun mukaan.
    • Salalause, jotta pelkkä nähty URL-osoite ei riitä.
    • Tuhoutuminen lukemisen jälkeen, jotta nähty URL-osoite on arvoton oikean lukemisen jälkeen.

    Pikaviestinsovellukset (Slack, Teams, iMessage) ja sähköpostin tietoturvaskannerit avaavat URL-osoitteista esikatselun hakemalla ne GET-pyynnöllä heti, kun viesti toimitetaan. Jos näyttämisen päätepiste tuhoaa salaisuuden GET-pyynnöstä, esikatselutoiminto tuhoaa sen ennen kuin ihminen ehtii nähdä sen. Tämä on yksinkertaisten ”tuhoutuu lukemisen jälkeen” -työkalujen yleisin todellinen vika.

    Suojaukset, sellaisina kuin LinkPilot ne toteuttaa:

    • Metatiedot ja näyttäminen ovat erillisiä toimintoja. Näyttämisen päätepisteeseen tehty GET palauttaa vain tilan ja tiedon siitä, tarvitaanko salalausetta. Avaus kirjataan vain erillisestä POST-pyynnöstä, jonka ihminen tekee napsauttaessaan näyttämispainiketta.
    • Salalausesuojaus (Pro). Kun salalause on asetettu, sisältöä ei palauteta kenellekään, botille tai ihmiselle, ilman oikeaa tiivistettä.
    • Cache-Control: no-store jokaisessa näyttämisvastauksessa, jotta välityspalvelimet eivät koskaan tallenna salaisuuden sisältöä välimuistiin.

    LinkPilotin tietoturva-arkkitehtuurisivu kuvaa tämän käsittelyn alusta loppuun.

    Elinkaari tila tilalta

    TilaLaukaisijaMitä kävijä näkeeVoiko sisällön palauttaa?
    AktiivinenLuontiNäyttämissivu (salalausekysely, jos asetettu)Kyllä: yksi avaus jäljellä
    TuhoutunutAvauskertojen raja täyttyy”Jo avattu ja tuhottu”, HTTP 410Ei: sisältö korvattu
    VanhentunutVoimassaoloaika päättyyVanhentuneen linkin tilasivuEi: sisältö korvataan seuraavalla käyttökerralla
    MitätöityLähettäjä mitätöi linkin hallintapaneelistaSisältöä ei näytetä, HTTP 410Ei: välittömästi ja pysyvästi

    Jokainen tilasiirtymä kirjautuu tarkastuslokiin (loki linkin tapahtumista), joka on LinkPilotissa Pro-ominaisuus. Tapahtumatyypit ovat created, viewed, failed_passphrase, burned, expired ja revoked, ja jokaisessa on aikaleima ja tiivistetty IP-osoite (SHA-256 päivittäin vaihtuvalla suolalla; raakaa IP-osoitetta ei koskaan tallenneta). Tämän lokin ansiosta ”luulen, että hän sai sen” muuttuu muotoon ”avattu klo 10:05 odotetusta maasta, yksi avaus, sitten tuhoutui”.

    Yleiset laajennukset

    • Salalausesuojaus. Ennen näyttämistä vaaditaan toista kanavaa pitkin lähetetty salalause, joten vuotanut URL-osoite ei yksin tarkoita vuotanutta salaisuutta. LinkPilotissa tämä on Pro-ominaisuus (29 $/kk) samoin kuin mukautettu voimassaoloaika ja tarkastusloki; ilman tiliä toimiva työkalu ei voi asettaa salalausetta. Rajoita yrityksiä: LinkPilot sallii 5 yritystä IP-osoitetta kohden minuutissa salaisuutta kohden ja kirjaa jokaisen epäonnistumisen.
    • Aikaan perustuva voimassaoloaika. Salaisuus tuhoutuu asetetun ajan jälkeen, vaikka sitä ei olisi luettu. LinkPilotin lomake kirjautuneille tarjoaa vaihtoehdot 1 tunti, 24 tuntia tai 7 päivää kaikissa paketeissa, ja Pro-paketissa voi valita oman päivän ja kellonajan. Ilman tiliä toimiva työkalu asettaa oletuksena 7 päivää. Tämä kattaa tapauksen, jossa linkki unohtuu saapuneet-kansioon, mitä tuhoutuminen lukemisen jälkeen ei kata.
    • Manuaalinen mitätöinti. Lähettäjä voi mitätöidä lukemattoman salaisuuden hallintapaneelista heti, kun jokin tuntuu olevan vialla. Halpa vakuutus tilanteeseen, jossa linkki lähti väärälle Alexille.

    Erikoistapaukset, jotka erottavat hyvät toteutukset

    Väärä henkilö avaa linkin ensin

    Tuhoutuminen lukemisen jälkeen ei estä väärää katsojaa, mutta se tekee virheellisen toimituksen näkyväksi. Oikea vastaanottaja päätyy tuhoutuneen linkin sivulle, tarkastusloki näyttää yhden odottamattoman avauksen ja vaihdat tunnukset. Ikävää mutta rajattua: täsmälleen yksi altistus, joka huomataan nopeasti. Pikaviestiin liitetyn salaisuuden kohdalla et saisi sitä koskaan tietää.

    Kuvakaappausongelma

    Kertakäyttöinen tarkoittaa yhtä näyttämistä, ei yhtä kopiota. Vastaanottaja voi ottaa salaisuudesta kuvakaappauksen, kopioida sen tai kirjoittaa sen uudelleen, eikä linkki estä tätä mitenkään. Toimittajat, jotka antavat ymmärtää muuta, myyvät satua. Rehellinen tapa sanoa asia: tuhoutuminen lukemisen jälkeen hallitsee toimituskanavaa, ei vastaanottajaa. Luottamus vastaanottajaan on lähtöoletus, ei lopputulos.

    Selaimen esilataus ja ennakoiva lataaminen

    Jotkin selaimet ja sovellukset hakevat etukäteen URL-osoitteita, joita todennäköisesti napsautetaan. Koska hyvin tehty työkalu tuhoaa salaisuuden vain erillisestä POST-pyynnöstä, esilataus toimii täsmälleen kuten esikatselutoiminto: se voi hakea sivun rungon, mutta ei koskaan sisältöä.

    • Arvoa tarvitaan uudelleen. Palautettavuus on salasanojen hallintaohjelman koko suunnittelutavoite ja kertakäyttölinkin vastakohta. Käytä holvin kohdetta.
    • Useat vastaanottajat tarvitsevat sitä. Yksi linkki, yksi lukeminen. Jos vastaanottajia on monta, joko luot jokaiselle oman linkin (toimii, ja jäljitettävyys säilyy) tai myönnät, että tarvitset sen sijaan jaetun käyttöoikeuksien hallinnan.
    • Käyttäjä on kone. Palveluiden ja CI-järjestelmien pitää lukea salaisuudet salaisuuksien hallintapalvelusta, ei napsauttaa linkkejä.

    Jos haluat nähdä mekanismin toiminnassa, luo linkki ilmaisella salaisten linkkien luontityökalulla. Tiliä ei tarvita, sisältö salataan selaimessasi ja se katoaa ensimmäisen avauksen jälkeen.

    Lähteet

    Työkalut tähän artikkeliin

    Usein kysytyt kysymykset

    LinkPilot lähettää salaisen linkin, joka katoaa, kun se on avattu.

    Salataan selaimessasi, näytetään kerran ja tuhotaan sitten. Tiliä ei tarvita.

    Luo salainen linkki

    Lue seuraavaksi