TLS
handskakningen som krypterar en anslutning
Vad det är
TLS, utskrivet Transport Layer Security, är det nätverksprotokoll som en klient och en server kör innan de utbyter några applikationsdata, så att det som följer är privat, inte kan ändras obemärkt och når den part som klienten avsåg. Produktmenyer och certifikatbutiker kallar det fortfarande SSL, efter Secure Sockets Layer, protokollet som TLS ersatte. RFC 7568 förklarade den sista SSL-versionen föråldrad i juni 2015, så allt som heter SSL i dag är TLS under ytan, eller borde vara det.
TLS ligger mellan ett applikationsprotokoll och transportlagret under det. HTTPS är HTTP som färdas inuti en TLS-anslutning, och samma lager skyddar inlämning av e-post, IMAP, databasanslutningar och protokollet Gemini. HTTP/3 går längre: det körs över QUIC, som bygger in handskakningen från TLS 1.3 i själva transporten i stället för att lägga den ovanpå TCP, så som RFC 9001 beskriver.
Den aktuella versionen är TLS 1.3, definierad i RFC 8446 från augusti 2018, som ersatte specifikationen för TLS 1.2. En anslutning börjar med en handskakning. Klienten skickar ett ClientHello med de versioner, chiffersviter och nyckelandelar den stöder, tillsammans med Server Name Indication (SNI), det värdnamn den vill nå, så att en adress kan betjäna många webbplatser. Servern väljer, svarar med sin egen nyckelandel, och från den stunden är allt krypterat, även certifikatet den visar upp. Certifikatkedjan knyter serverns nyckel till en certifikatutfärdare (CA) som klienten redan litar på. Klienten kontrollerar kedjan, namnet och datumen, och servern bevisar att den har den matchande privata nyckeln genom att signera handskakningen.
Tre saker skiljer 1.3 från 1.2. En fullständig handskakning tar en enda tur och retur över nätet (en round trip) i stället för två. Varje nyckelutbyte är efemärt, så en inspelning av dagens trafik förblir förseglad även om serverns privata nyckel läcker nästa år; den egenskapen kallas framåtsekretess (forward secrecy). Och en klient som återvänder får skicka ”tidiga data” redan i sitt första meddelande, så kallad 0-RTT, till ett pris som RFC:n skriver ut: tidiga data har varken framåtsekretess eller skydd mot att spelas upp igen på en annan anslutning.
Varför det spelar roll
Att använda TLS är redan avgjort. Kvar finns två beslut: vilka versioner du godtar och var den krypterade anslutningen tar slut.
Först versionerna. RFC 8996, publicerad i mars 2021, säger att TLS 1.0 och 1.1 inte får användas. RFC 9325, den gällande bästa praxisen (BCP 195), kräver stöd för 1.2, rekommenderar 1.3 och säger att 1.3 ska föredras när båda sidor har det. Den säger också att 1.2, konfigurerad på det sätt den beskriver, är lika säker som 1.3: ECDHE som nyckelutbyte för framåtsekretess, AES-GCM och inga av sviterna i CBC-läge. Det verkliga valet står alltså mellan ”1.2 och 1.3” och ”bara 1.3”. En tjänst med bara 1.3 har en mindre attackyta och en kortare konfiguration, och den stänger ute varje klient som högst talar 1.2: en äldre telefon, en kortterminal, en partners integration på en gammal Java-körmiljö. Den avvägningen är billig att avgöra med belägg. Logga den förhandlade versionen i några veckor och bestäm sedan utifrån siffrorna, inte utifrån vad som låter modernt.
Sedan termineringen. Där TLS slutar finns den privata nyckeln, och där blir trafiken klartext igen. Det finns tre vanliga platser för det:
- Ett CDN eller en lastbalanserare i molnet. Leverantören har nyckeln, eller ett certifikat den själv har utfärdat, tar handskakningslasten och ser varje förfrågan i klartext. Steget därifrån till ursprungsservern behöver ett eget TLS, annars går det okrypterat över nätet.
- En omvänd proxy på värddatorn, t.ex. nginx, Apache, HAProxy eller Caddy. En enda process har nycklarna för alla webbplatser på maskinen och skickar okrypterade förfrågningar vidare till applikationerna bakom, över loopback eller en lokal socket.
- Applikationen själv. Varje tjänst har sin egen nyckel. Det passar trafik mellan tjänster och ömsesidig TLS (mutual TLS), där också klienten visar upp ett certifikat, och det mångdubblar de ställen där ett certifikat måste förnyas.
De flesta miljöer blandar alla tre. Det som räknas är att någon för varje steg kan säga var klartexten finns och vem som skulle kunna läsa den.
Så ser det ut i praktiken
Företagets egen produktionsvärd visar hur lite TLS-terminering kräver. Värden är en molninstans med en kärna, 10 GB disk och 512 MB minne, och där terminerar webbservern TLS för sju domäner på samma maskin som git-forgen, onion-tjänsten för Tor, servrarna för Gemini och Gopher, de krypterade säkerhetskopiorna och spärren mot intrångsförsök. Det är terminering på värden i sin enklaste form: en enda webbserver svarar för alla sju webbplatserna, och krypteringen för dem kostar varken en extra maskin eller en extra tjänst. Designen behandlade minnet som den bindande begränsningen, och allt på den listan, termineringen inräknad, får plats i det användbara minnet på ungefär 464 MB.
Regeln som företaget arbetar efter står på sidan om hur vi arbetar säkert: kryptering under överföring överallt, med certifikat som utfärdas och förnyas automatiskt och en förnyelse som övervakas. Skälet som anges där är att TLS oftast fallerar genom ett certifikat som ingen höll ett öga på. Felen nedan är de som återstår när förnyelsen sköter sig själv.
Var det går fel
Vissa klienter faller bort med ett handskakningsfel medan webbläsare ansluter som vanligt. De två sidorna delar ingen version eller chiffersvit. Någon har smalnat av servern till bara 1.3, eller till en kort lista sviter, och en äldre klient erbjuder inget som finns på den. Eller så möter en server som fortfarande bara erbjuder CBC-sviter en klient som har slutat med dem. Felmeddelandet säger ”handshake failure” eller ”protocol version” och inte mycket mer. Testa varje version utifrån:
openssl s_client -connect example.com:443 \
-servername example.com -tls1_2 </dev/null
Logga den förhandlade versionen och sviten innan du smalnar av något, och behåll 1.2 med ECDHE och AES-GCM bredvid 1.3 tills loggarna visar att ingen använder den.
Webbläsare litar på certifikatet, medan skript, curl och mobilappar avvisar det. Servern skickar
sitt eget certifikat utan det mellanliggande certifikat som länkar det till roten. Webbläsare fyller
ofta luckan med mellanliggande certifikat som de har sett förut, eller hämtar det som saknas själva.
De flesta TLS-bibliotek gör inget av det och rapporterar en okänd utfärdare. Konfigurera hela
kedjefilen, serverns certifikat först och sedan de mellanliggande, och testa med en klient som inte
sparar något i cache: raden med openssl s_client ovan skriver ut den kedja som servern faktiskt
skickade.
Certifikatkontrollen stängs av ”tills vidare”, och inställningen följer med ut i produktion. En
testserver med ett självsignerat certifikat, eller en företagsproxy som signerar om trafiken, och
någon lägger till verify=False, curl -k, InsecureSkipVerify eller
NODE_TLS_REJECT_UNAUTHORIZED=0. Anslutningen förblir krypterad, men till den som svarar: vem som
helst däremellan kan visa upp ett eget certifikat och läsa allt. Lägg rätt CA-certifikat i
klientens förtroendelager, eller peka klienten uttryckligen mot det, och låt CI stoppa bygget när de
flaggorna dyker upp.
Vissa besökare får ett certifikat för en annan webbplats. Servern visar sitt standardcertifikat när ett ClientHello nämner ett värdnamn som den saknar konfiguration för, eller inget namn alls. Det händer när en ny domän pekas mot adressen innan dess serverblock finns, och när en övervakningssond eller en gammal klient skickar sin förfrågan utan SNI. Webbläsaren visar att namnet inte stämmer, och på en delad värd avslöjar den dessutom för besökaren vilka andra webbplatser som bor där. Ge varje publikt namn ett eget block och ett certifikat som täcker det, och låt standardblocket vägra handskakningen i stället för att visa upp en främlings certifikat.
En betalning, eller vilken annan förfrågan som helst, utförs två gånger. Termineringspunkten godtar tidiga data via 0-RTT, en POST kommer in bland dem, och en angripare eller ett omförsök i nätet skickar samma byte igen på en ny anslutning. RFC 8446 låter en server ta emot tidiga data och lämnar skyddet mot uppspelning mellan anslutningar åt applikationen. Godta tidiga data bara för förfrågningar som tål att upprepas, eller låt termineringspunkten vägra dem för allt annat. RFC 8470 definierar statusen 425 Too Early för just den överlämningen.
Läs mer
- RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3 — handskakningen, postlagret (record layer) och bilagan om varför data i 0-RTT kan spelas upp igen.
- RFC 9325: Recommendations for Secure Use of TLS and DTLS — BCP 195: vilka versioner som ska tillåtas, vilka sviter i 1.2 som ska behållas och reglerna för SNI.
- RFC 8996: Deprecating TLS 1.0 and TLS 1.1 — det formella slutet för de två äldre versionerna och skälen bakom det.
- RFC 8470: Using Early Data in HTTP — hur en termineringspunkt och en server kommer överens om vilka förfrågningar som får skickas i 0-RTT, och statusen 425.