# TLS

## Hva det er

TLS, kort for Transport Layer Security, er protokollen en klient og en server kjører før de
utveksler noen applikasjonsdata. Etterpå er det som sendes, privat, det lar seg ikke endre uten at
det merkes, og det når fram til den parten klienten faktisk ville nå. Produktmenyer og
sertifikatbutikker kaller det fortsatt SSL, etter Secure Sockets Layer, protokollen TLS avløste. Den
siste SSL-versjonen ble erklært foreldet i RFC 7568 i juni 2015, så alt som heter SSL i dag, er TLS
under panseret, eller burde være det.

TLS ligger mellom en applikasjonsprotokoll og transportlaget under den. HTTPS er HTTP fraktet inne i
en TLS-forbindelse, og det samme laget beskytter innsending av e-post, IMAP, databaseforbindelser og
Gemini-protokollen. HTTP/3 går et steg lenger: det kjører over QUIC, som bygger håndtrykket fra TLS
1.3 inn i selve transporten i stedet for å legge det oppå TCP, slik RFC 9001 beskriver.

Gjeldende versjon er TLS 1.3, definert i RFC 8446 fra august 2018, som erstattet spesifikasjonen for
TLS 1.2. En forbindelse åpner med et håndtrykk. Klienten sender en ClientHello med versjonene,
chifferpakkene (_cipher suites_) og nøkkelandelene den støtter, sammen med Server Name Indication
(SNI), vertsnavnet den vil nå, slik at én adresse kan betjene mange nettsteder. Serveren velger,
svarer med sin egen nøkkelandel, og fra det øyeblikket er alt kryptert, også sertifikatet den legger
fram. Sertifikatkjeden knytter serverens nøkkel til en sertifiseringsinstans klienten allerede
stoler på. Klienten sjekker kjeden, navnet og datoene, og serveren beviser at den har den tilhørende
private nøkkelen ved å signere håndtrykket.

Tre ting skiller 1.3 fra 1.2. Et fullt håndtrykk tar én rundtur i stedet for to. Hver
nøkkelutveksling er flyktig, så et opptak av dagens trafikk forblir forseglet selv om serverens
private nøkkel lekker neste år; den egenskapen kalles _forward secrecy_. Og en klient som kommer
tilbake, kan sende «early data» allerede i sin aller første melding, kjent som 0-RTT, til en pris
RFC-en gjør rede for: tidlige data har verken forward secrecy eller vern mot å bli spilt av på nytt
over en annen forbindelse.

## Hvorfor det er viktig

At TLS skal brukes, er avgjort for lengst. Det som gjenstår, er hvilke versjoner du godtar, og hvor
den krypterte forbindelsen slutter.

Først versjonene. RFC 8996, publisert i mars 2021, sier at TLS 1.0 og 1.1 ikke skal brukes. RFC
9325, gjeldende beste praksis (BCP 195), krever støtte for 1.2, anbefaler 1.3 og sier at 1.3 skal
foretrekkes når begge ender har den. Den sier også at 1.2, satt opp slik den beskriver, er like
trygg som 1.3: ECDHE-nøkkelutveksling for forward secrecy, AES-GCM og ingen av chifferpakkene i
CBC-modus. Det reelle valget står derfor mellom «1.2 og 1.3» og «bare 1.3». En tjeneste med bare 1.3
har mindre angrepsflate og kortere konfigurasjon, og den stenger ute alle klienter som høyst snakker
1.2: en eldre telefon, en kortterminal, en partners integrasjon på en gammel Java-runtime. Den
avveiningen er billig å avgjøre med data. Logg den forhandlede versjonen i noen uker, og bestem deg
ut fra tallene heller enn ut fra hva som høres moderne ut.

Deretter termineringen. Der TLS slutter, ligger den private nøkkelen, og trafikken blir klartekst
igjen. Tre steder er vanlige:

- **Et CDN eller en lastbalanserer i skyen.** Leverandøren har nøkkelen, eller et sertifikat den har
  utstedt selv, tar belastningen fra håndtrykkene og ser hver forespørsel i klartekst. Strekningen
  derfra til opprinnelsesserveren trenger sin egen TLS, ellers går den ukryptert over nettet.
- **En omvendt proxy på verten,** f.eks. nginx, Apache, HAProxy eller Caddy. Én prosess har nøklene
  for alle nettstedene på maskinen og sender forespørslene videre i klartekst til applikasjonene
  bak, over loopback eller en lokal socket.
- **Selve applikasjonen.** Hver tjeneste har sin egen nøkkel. Det passer for trafikk mellom
  tjenester og for gjensidig TLS (_mutual TLS_), der også klienten legger fram et sertifikat, og det
  mangedobler antallet steder der et sertifikat må fornyes.

De fleste driftsmiljøer blander alle tre. Det som teller, er at noen for hvert ledd kan si hvor
klarteksten finnes, og hvem som kan lese den.

## Slik ser det ut i praksis

Selskapets egen produksjonsvert viser hvor lite TLS-terminering krever. Instansen i skyen har én
kjerne, 10 GB disk og 512 MB minne, der rundt 464 MB kan brukes. På den
[terminerer webserveren TLS for sju domener](/nb/portfolio/ran-the-whole-company-on-one-512mb-host-109/)
og deler maskinen med git-forgen, onion-tjenesten for Tor, serverne for Gemini og Gopher, de
krypterte sikkerhetskopiene og utestengingen av inntrengere. Det er terminering på verten i sin
enkleste form: én webserver svarer for alle sju nettstedene, og krypteringen deres koster verken en
ekstra maskin eller en ekstra tjeneste. Designet behandlet minnet som den bindende begrensningen, og
alt på den listen, terminering inkludert, kjører innenfor de 464 MB.

Regelen selskapet arbeider etter, står på [sikkerhetssiden](/nb/security/): kryptering under
overføring overalt, med sertifikater som utstedes og fornyes automatisk, og en fornyelse som
overvåkes. Begrunnelsen der er at TLS oftest svikter på et sertifikat ingen fulgte med på. Feilene
nedenfor er de som er igjen når fornyelsen går av seg selv.

## Hvor det går galt

**Noen klienter faller av med et mislykket håndtrykk, mens nettleserne kobler til uten problemer.**
Endene har ingen felles versjon eller chifferpakke. Noen har snevret serveren inn til bare 1.3,
eller til en kort liste med chifferpakker, og en eldre klient tilbyr bare det serveren har strøket.
Eller en server som fortsatt bare tilbyr CBC-pakker, møter en klient som har sluttet å støtte dem.
Varselet sier «handshake failure» eller «protocol version» og lite mer. Test hver versjon utenfra:

```sh
openssl s_client -connect example.com:443 \
    -servername example.com -tls1_2 </dev/null
```

Logg den forhandlede versjonen og chifferpakken før du snevrer inn noe, og behold 1.2 med ECDHE og
AES-GCM ved siden av 1.3 til loggene viser at ingen bruker den.

**Nettleseren stoler på sertifikatet, mens skript, curl og mobilapper avviser det.** Serveren sender
sitt eget sertifikat uten mellomsertifikatet som knytter det til roten. Nettlesere fyller ofte
hullet med mellomsertifikater de har møtt før, eller henter det manglende selv. De fleste
TLS-biblioteker gjør ingen av delene og melder om en ukjent utsteder. Sett opp hele kjedefilen,
serverens sertifikat først og deretter mellomsertifikatene, og test med en klient som ikke har noen
cache: linjen med `openssl s_client` ovenfor skriver ut kjeden serveren faktisk sendte.

**Sertifikatsjekken slås av «inntil videre», og innstillingen havner i produksjon.** Det begynner
med en testserver med et selvsignert sertifikat, eller en bedriftsproxy som signerer trafikken på
nytt, og så legger noen til `verify=False`, `curl -k`, `InsecureSkipVerify` eller
`NODE_TLS_REJECT_UNAUTHORIZED=0`. Forbindelsen er fortsatt kryptert, men til den som svarer: hvem
som helst i mellom kan legge fram sitt eget sertifikat og lese alt. Legg det riktige CA-sertifikatet
i klientens tillitslager, eller pek klienten eksplisitt på det, og la CI feile på disse flaggene.

**Noen besøkende får et sertifikat for et annet nettsted.** Serveren legger fram
standardsertifikatet sitt når en ClientHello navngir en vert den mangler konfigurasjon for, eller
når den ikke navngir noen vert i det hele tatt. Det skjer når et nytt domene pekes mot adressen før
serverblokken finnes, og når en overvåkingsprobe eller en gammel klient sender uten SNI. Nettleseren
melder at navnet avviker, og på en delt vert avslører feilen også hvilke andre nettsteder som bor
der. Gi hvert offentlige navn sin egen blokk og et sertifikat som dekker det, og la standardblokken
avvise håndtrykket i stedet for å vise fram en fremmeds sertifikat.

**En betaling, eller en hvilken som helst annen forespørsel, blir utført to ganger.**
Termineringspunktet godtar tidlige data over 0-RTT, en POST kommer inne i dem, og en angriper eller
et nytt forsøk i nettverket sender de samme bytene igjen over en ny forbindelse. RFC 8446 lar en
server godta tidlige data og overlater gjentakelse mellom forbindelser til applikasjonen. Godta
tidlige data bare for forespørsler som tåler å gjentas, eller la termineringspunktet avvise dem for
alt annet; RFC 8470 definerer statuskoden 425 Too Early nettopp for den overleveringen.

## Les mer

- [RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3](https://www.rfc-editor.org/rfc/rfc8446)
  — håndtrykket, postlaget og vedlegget om hvorfor data sendt med 0-RTT kan spilles av på nytt.
- [RFC 9325: Recommendations for Secure Use of TLS and DTLS](https://www.rfc-editor.org/rfc/rfc9325)
  — BCP 195: hvilke versjoner som bør tillates, hvilke chifferpakker for 1.2 som bør beholdes, og
  reglene for SNI.
- [RFC 8996: Deprecating TLS 1.0 and TLS 1.1](https://www.rfc-editor.org/rfc/rfc8996) — den formelle
  slutten for de to eldre versjonene og begrunnelsen for den.
- [RFC 8470: Using Early Data in HTTP](https://www.rfc-editor.org/rfc/rfc8470) — hvordan
  termineringspunkt og server blir enige om hvilke forespørsler som kan reise med 0-RTT, og
  statuskoden 425.

<https://engineer.company/nb/glossary/tls/>
