Spring til indhold

TLS

håndtrykket der krypterer en forbindelse

Hvad det er

TLS, Transport Layer Security, er den protokol, en klient og en server kører, før de udveksler data, så det, der følger, er privat, ikke kan ændres ubemærket og når frem til den part, klienten ville have fat i. I produktmenuer og hos certifikatforhandlere hedder det stadig ofte SSL efter Secure Sockets Layer, den protokol, TLS afløste. RFC 7568 erklærede den sidste SSL-version for forældet i juni 2015, så alt, der i dag kaldes SSL, er TLS nedenunder, eller burde være det.

TLS ligger mellem en applikationsprotokol og transporten under den. HTTPS er HTTP inde i en TLS-forbindelse, og samme lag beskytter afsendelse af mail, IMAP, databaseforbindelser og Gemini-protokollen. HTTP/3 går et skridt videre og kører over QUIC, der bygger håndtrykket fra TLS 1.3 direkte ind i transporten i stedet for at lægge det oven på TCP, som RFC 9001 beskriver.

Den gældende version er TLS 1.3 fra RFC 8446, udgivet i august 2018, som afløste specifikationen for TLS 1.2. En forbindelse begynder med et håndtryk. Klienten sender en ClientHello med de versioner, cipher suites og nøgleandele, den understøtter, og med Server Name Indication (SNI), det værtsnavn, den vil have fat i, så én adresse kan betjene mange sites. Serveren vælger, svarer med sin egen nøgleandel, og fra det øjeblik er alt krypteret, også certifikatet, serveren viser frem. Certifikatkæden binder serverens nøgle til en certifikatudsteder, klienten allerede stoler på. Klienten kontrollerer kæden, navnet og datoerne, og serveren beviser, at den har den private nøgle, ved at signere håndtrykket.

Tre ting adskiller 1.3 fra 1.2. Et fuldt håndtryk kræver én tur frem og tilbage i stedet for to. Hver nøgleudveksling er flygtig, så en optagelse af dagens trafik forbliver lukket, selv hvis serverens private nøgle slipper ud næste år; den egenskab hedder forward secrecy. Og en klient, der vender tilbage, kan sende »early data« allerede i sin første besked, kendt som 0-RTT, til en pris, som RFC’en skriver ligeud: de data har hverken forward secrecy eller beskyttelse mod at blive afspillet igen på en anden forbindelse.

Hvorfor det betyder noget

At bruge TLS er afgjort for længst. Tilbage står to beslutninger: hvilke versioner man accepterer, og hvor den krypterede forbindelse ender.

Først versionerne. RFC 8996 fra marts 2021 siger, at TLS 1.0 og 1.1 ikke må bruges. RFC 9325, den gældende bedste praksis (BCP 195), kræver understøttelse af 1.2, anbefaler 1.3 og siger, at 1.3 skal foretrækkes, når begge ender kan tale det. Den siger også, at 1.2 sat op efter dens anvisninger er lige så sikkert som 1.3: ECDHE-nøgleudveksling for forward secrecy, AES-GCM og ingen af CBC-suiterne. Det reelle valg står derfor mellem »1.2 og 1.3« og »kun 1.3«. En server med kun 1.3 har en mindre angrebsflade og en kortere konfiguration, og den lukker alle klienter ude, der højst taler 1.2: en ældre telefon, en betalingsterminal, en samarbejdspartners integration på en gammel Java-runtime. Det valg er billigt at træffe på et oplyst grundlag. Log den forhandlede version i et par uger, og beslut ud fra tallene frem for ud fra, hvad der lyder moderne.

Dernæst termineringen. Der, hvor TLS ender, ligger den private nøgle, og der bliver trafikken til klartekst igen. Der er tre almindelige steder:

  • Et CDN eller en load balancer i skyen. Udbyderen har nøglen eller et certifikat, den selv har udstedt, tager belastningen fra håndtrykkene og ser hver forespørgsel i klartekst. Strækningen derfra til origin-serveren skal have sin egen TLS, ellers krydser den netværket ukrypteret.
  • En reverse proxy på værten, for eksempel Nginx, Apache, HAProxy eller Caddy. Én proces har nøglerne til alle sites på maskinen og sender forespørgslerne ukrypteret videre til programmerne bag sig over loopback eller en lokal socket.
  • Selve applikationen. Hver tjeneste har sin egen nøgle. Det egner sig til trafik mellem tjenester og til mutual TLS, hvor klienten også viser et certifikat, og det mangedobler antallet af steder, hvor et certifikat skal fornys.

De fleste miljøer blander alle tre. Det afgørende er, at nogen for hver strækning kan sige, hvor klarteksten findes, og hvem der kan læse den.

Sådan ser det ud i praksis

Virksomhedens egen produktionsvært viser, hvor lidt TLS-terminering kræver. Det er en cloudinstans med én kerne, 512 MB hukommelse, hvoraf omkring 464 MB kan bruges, og 10 GB disk. På den terminerer webserveren TLS for syv domæner side om side med git-forgen, en Tor onion-tjeneste, en Gemini-server, en Gopher-server, krypterede backups og blokering af indtrængere. Det er terminering på værten i sin enkleste form: én webserver svarer for alle syv sites, og krypteringen af dem koster hverken en ekstra maskine eller en ekstra tjeneste. Designet behandlede hukommelsen som den bindende begrænsning, og alt på listen, termineringen medregnet, kører inden for de 464 MB.

Reglen, virksomheden arbejder efter, står på dens sikkerhedsside: kryptering under overførsel overalt, med certifikater, der udstedes og fornys automatisk, og en fornyelse, der overvåges. Begrundelsen er, at TLS oftest svigter på grund af et certifikat, som ingen overvågede. Fejlene nedenfor er dem, der er tilbage, når fornyelsen kører af sig selv.

Hvor det går galt

Nogle klienter bliver afvist med en håndtryksfejl, mens browsere forbinder fint. De to ender har ingen version eller cipher suite til fælles. Nogen har strammet serveren til kun 1.3 eller til en kort liste af suiter, og en ældre klient har intet af det at byde på; eller en server, der stadig kun tilbyder CBC-suiter, møder en klient, der har droppet dem. Fejlbeskeden lyder »handshake failure« eller »protocol version« og siger ikke meget mere. Test hver version udefra:

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

Log den forhandlede version og suite, før noget strammes, og behold 1.2 med ECDHE og AES-GCM ved siden af 1.3, indtil loggene viser, at ingen bruger den.

Browsere stoler på certifikatet, mens scripts, curl og mobilapps afviser det. Serveren sender sit eget certifikat uden det mellemcertifikat, der forbinder det med roden. Browsere udfylder ofte hullet med mellemcertifikater, de har mødt før, eller henter selv det manglende; de fleste TLS-biblioteker gør ingen af delene og melder en ukendt udsteder. Konfigurér hele kædefilen, serverens eget certifikat først og derefter mellemcertifikaterne, og test med en klient uden cache: openssl s_client-linjen ovenfor viser den kæde, serveren faktisk sendte.

Certifikatkontrollen slås fra »indtil videre«, og indstillingen ender i produktion. En testserver med et selvsigneret certifikat eller en virksomhedsproxy, der gensignerer trafikken, og nogen tilføjer verify=False, curl -k, InsecureSkipVerify eller NODE_TLS_REJECT_UNAUTHORIZED=0. Forbindelsen er stadig krypteret, bare til hvem der end svarer: enhver undervejs kan vise sit eget certifikat og læse det hele. Læg det rigtige CA-certifikat i klientens tillidslager, eller peg klienten direkte på det, og lad CI fejle på de flag.

Nogle besøgende får et certifikat til et helt andet site. Serveren viser sit standardcertifikat, når en ClientHello nævner en vært, som den mangler konfiguration til, eller slet ikke nævner en vært. Det sker, når et nyt domæne peges på adressen, før dets serverblok findes, og når en overvågningsprobe eller en gammel klient udelader SNI. Browseren melder en navnefejl, og på en delt vært afslører den samtidig, hvilke andre sites der bor der. Giv hvert offentligt navn sin egen blok og et certifikat, der dækker det, og lad standardblokken afvise håndtrykket frem for at vise et fremmed certifikat.

En betaling eller en anden forespørgsel bliver udført to gange. Termineringen tager imod 0-RTT early data, en POST kommer med i dem, og en angriber eller et automatisk genforsøg sender de samme bytes igen på en ny forbindelse. RFC 8446 lader serveren tage imod early data og overlader beskyttelsen mod genafspilning mellem forbindelser til applikationen. Tag kun imod early data for forespørgsler, der tåler at blive gentaget, eller lad termineringen afvise dem for alt andet; RFC 8470 definerer statuskoden 425 Too Early til netop den overdragelse.

Læs mere

Ordliste